Add DataMap on Node

This commit is contained in:
Clément Fournier
2020-01-19 10:07:41 +01:00
parent 27d7a6c02c
commit 84b59c3350
3 changed files with 118 additions and 3 deletions
pmd-core/src/main/java/net/sourceforge/pmd

@ -26,6 +26,9 @@ import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator;
import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator;
import net.sourceforge.pmd.lang.dfa.DataFlowNode;
import net.sourceforge.pmd.util.DataMap;
import net.sourceforge.pmd.util.DataMap.DataKey;
import net.sourceforge.pmd.util.DataMap.SimpleDataKey;
/**
@ -42,6 +45,10 @@ public abstract class AbstractNode implements Node {
private static final Logger LOG = Logger.getLogger(AbstractNode.class.getName());
private static final SimpleDataKey<Object> LEGACY_USER_DATA = DataMap.simpleDataKey("legacy user data");
private final DataMap<DataKey<?, ?>> userData = DataMap.newDataMap();
/**
* @deprecated Use {@link #getParent()}
*/
@ -73,7 +80,6 @@ public abstract class AbstractNode implements Node {
@Deprecated
protected GenericToken lastToken;
private DataFlowNode dataFlowNode;
private Object userData;
// @Deprecated?
private String image;
@ -522,12 +528,17 @@ public abstract class AbstractNode implements Node {
@Override
public Object getUserData() {
return userData;
return userData.get(LEGACY_USER_DATA);
}
@Override
public void setUserData(final Object userData) {
this.userData = userData;
this.userData.set(LEGACY_USER_DATA, userData);
}
@Override
public DataMap<DataKey<?, ?>> getUserMap() {
return userData;
}
/**

@ -14,6 +14,8 @@ import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
import net.sourceforge.pmd.lang.dfa.DataFlowNode;
import net.sourceforge.pmd.util.DataMap;
import net.sourceforge.pmd.util.DataMap.DataKey;
/**
* Root interface for all AST nodes. This interface provides only the API
@ -413,6 +415,14 @@ public interface Node {
void removeChildAtIndex(int childIndex);
/**
* Returns a data map used to store additional information on this node.
* This replaces the legacy {@link #getUserData()}/{@link #setUserData(Object)}.
*
* @return The user data map of this node
*/
DataMap<DataKey<?, ?>> getUserMap();
/**
* Returns the parent of this node, or null if this is the {@linkplain RootNode root}
* of the tree.

@ -0,0 +1,94 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util;
import java.util.IdentityHashMap;
import java.util.Map;
/**
* An opaque, strongly typed heterogeneous data container.
*
* @param <K> Type of keys in this map
*/
public class DataMap<K> {
private final Map<DataKey<? extends K, ?>, Object> map = new IdentityHashMap<>();
private DataMap() {
}
/**
* Set the mapping to the given data.
*
* @param key Key
* @param data Data mapped to the key
* @param <T> Type of the data
*
* @return Previous value associated with the key (nullable)
*/
@SuppressWarnings("unchecked")
public <T> T set(DataKey<? extends K, ? super T> key, T data) {
return (T) map.put(key, data);
}
/**
* Retrieves the data currently mapped to the key.
*
* @param key Key
* @param <T> Type of the data
*
* @return Value associated with the key (nullable)
*/
@SuppressWarnings("unchecked")
public <T> T get(DataKey<? extends K, ? super T> key) {
return (T) map.get(key);
}
/**
* Returns true if the given key has a non-null value in the map.
*
* @param key Key
*
* @return True if some value is set
*/
public boolean isSet(DataKey<? extends K, ?> key) {
return map.containsKey(key);
}
public static <K> DataMap<K> newDataMap() {
return new DataMap<>();
}
public static <T> SimpleDataKey<T> simpleDataKey(final String name) {
return new SimpleDataKey<>(name);
}
/**
* A key for type-safe access into a {@link DataMap}. Data keys use
* reference identity and are only compared by reference within
* {@link DataMap}.
*
* @param <K> Type of the family of keys this is a part of
* @param <T> Type of the addressed data
*/
public interface DataKey<K extends DataKey<K, T>, T> {
}
public static class SimpleDataKey<T> implements DataKey<SimpleDataKey<T>, T> {
private final String name;
SimpleDataKey(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
}