getDeclaredAnnotations() {
- return this.findChildrenOfType(ASTAnnotation.class);
- }
-
-
- /**
- * Returns the annotation with the given qualified name if it is present,
- * otherwise returns null. The argument should be a qualified name, though
- * this method will find also usages of an annotation that use the simple
- * name if it is in scope.
- *
- * E.g. {@code getAnnotation("java.lang.Override")} will find both
- * {@code @java.lang.Override} and {@code @Override}.
- */
- @Nullable
- default ASTAnnotation getAnnotation(String annotQualifiedName) {
- // TODO use node streams
- List annotations = getDeclaredAnnotations();
- for (ASTAnnotation annotation : annotations) {
- if (TypeHelper.isA(annotation, annotQualifiedName)) {
- return annotation;
- }
- }
- return null;
- }
-
-
- /**
- * Returns true if any annotation in the given collection is present,
- * using {@link #isAnnotationPresent(String)}, otherwise false.
- */
- default boolean isAnyAnnotationPresent(Collection annotQualifiedNames) {
- // TODO use node streams
- for (String annotQualifiedName : annotQualifiedNames) {
- if (isAnnotationPresent(annotQualifiedName)) {
- return true;
- }
- }
- return false;
+ default NodeStream getDeclaredAnnotations() {
+ return children(ASTAnnotation.class);
}
/**
* Returns true if an annotation with the given qualified name is
- * applied to this node. In this case, {@link #getAnnotation(String)}
- * will not return null.
+ * applied to this node.
*/
default boolean isAnnotationPresent(String annotQualifiedName) {
- return getAnnotation(annotQualifiedName) != null;
+ return getDeclaredAnnotations().any(t -> TypeHelper.isA(t, annotQualifiedName));
+ }
+
+
+ /**
+ * Returns true if an annotation with the given type is
+ * applied to this node.
+ */
+ default boolean isAnnotationPresent(Class> type) {
+ return getDeclaredAnnotations().any((Predicate) t -> TypeHelper.subclasses(t, type));
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalApiBridge.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalApiBridge.java
index 4676b62bbd..00463da788 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalApiBridge.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/InternalApiBridge.java
@@ -7,6 +7,12 @@ package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.java.qname.JavaOperationQualifiedName;
import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
import net.sourceforge.pmd.lang.symboltable.Scope;
@@ -28,6 +34,20 @@ public final class InternalApiBridge {
}
+ public static void setSymbol(SymbolDeclaratorNode node, JElementSymbol symbol) {
+ if (node instanceof ASTMethodDeclaration) {
+ ((ASTMethodDeclaration) node).setSymbol((JMethodSymbol) symbol);
+ } else if (node instanceof ASTConstructorDeclaration) {
+ ((ASTConstructorDeclaration) node).setSymbol((JConstructorSymbol) symbol);
+ } else if (node instanceof ASTAnyTypeDeclaration) {
+ ((AbstractAnyTypeDeclaration) node).setSymbol((JClassSymbol) symbol);
+ } else if (node instanceof ASTVariableDeclaratorId) {
+ ((ASTVariableDeclaratorId) node).setSymbol((JVariableSymbol) symbol);
+ } else if (node instanceof ASTTypeParameter) {
+ ((ASTTypeParameter) node).setSymbol((JTypeParameterSymbol) symbol);
+ }
+ }
+
public static void setSymbolTable(JavaNode node, JSymbolTable table) {
((AbstractJavaNode) node).setSymbolTable(table);
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JModifier.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JModifier.java
index d6c5a8036e..649a96810e 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JModifier.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JModifier.java
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.ast;
import java.lang.reflect.Modifier;
+import java.util.Collection;
import java.util.Locale;
/**
@@ -65,4 +66,14 @@ public enum JModifier {
public String toString() {
return getToken();
}
+
+
+ public static int toReflect(Collection mods) {
+ int res = 0;
+ for (JModifier mod : mods) {
+ res |= mod.getReflectMod();
+ }
+ return res;
+ }
+
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java
index cb4096cfb0..1168530699 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java
@@ -129,8 +129,7 @@ public interface JavaNode extends ScopedNode, TextAvailableNode {
/**
* Returns the symbol table for the program point represented by
* this node.
- *
- * TODO
*/
+ @NonNull
JSymbolTable getSymbolTable();
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java
index 8744e1a6c7..41d2f5ca9e 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java
@@ -25,24 +25,6 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
public class JavaParserVisitorAdapter implements JavaParserVisitor {
- public Object visit(ASTAnnotation node, Object data) {
- return visit((JavaNode) node, data);
- }
-
- @Override
- public Object visit(ASTMarkerAnnotation node, Object data) {
- return visit((ASTAnnotation) node, data);
- }
-
- @Override
- public Object visit(ASTSingleMemberAnnotation node, Object data) {
- return visit((ASTAnnotation) node, data);
- }
-
- @Override
- public Object visit(ASTNormalAnnotation node, Object data) {
- return visit((ASTAnnotation) node, data);
- }
public Object visit(ASTType node, Object data) {
return visit((JavaNode) node, data);
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java
index 6af146c604..2b4970e7c9 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SideEffectingVisitorAdapter.java
@@ -15,28 +15,22 @@ package net.sourceforge.pmd.lang.java.ast;
public class SideEffectingVisitorAdapter implements SideEffectingVisitor {
- public void visit(ASTAnnotation node, T data) {
+ public void visit(ASTMethodOrConstructorDeclaration node, T data) {
visit((JavaNode) node, data);
}
-
+
@Override
- public void visit(ASTSingleMemberAnnotation node, T data) {
- visit((ASTAnnotation) node, data);
+ public void visit(ASTMethodDeclaration node, T data) {
+ visit((ASTMethodOrConstructorDeclaration) node, data);
}
-
+
@Override
- public void visit(ASTNormalAnnotation node, T data) {
- visit((ASTAnnotation) node, data);
- }
-
- @Override
- public void visit(ASTMarkerAnnotation node, T data) {
- visit((ASTAnnotation) node, data);
+ public void visit(ASTConstructorDeclaration node, T data) {
+ visit((ASTMethodOrConstructorDeclaration) node, data);
}
// TODO delegation
-
public void visit(ASTAnyTypeDeclaration node, T data) {
visit((JavaNode) node, data);
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SymbolDeclaratorNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SymbolDeclaratorNode.java
new file mode 100644
index 0000000000..eb9bd01e7e
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/SymbolDeclaratorNode.java
@@ -0,0 +1,17 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.ast;
+
+import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+public interface SymbolDeclaratorNode extends JavaNode {
+
+ /** Returns the symbol this node declares. */
+ JElementSymbol getSymbol();
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeParamOwnerNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeParamOwnerNode.java
index c4c7f86db5..d2e2ade35e 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeParamOwnerNode.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeParamOwnerNode.java
@@ -6,10 +6,15 @@ package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.Nullable;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
+
/**
* @author Clément Fournier
*/
-public interface TypeParamOwnerNode extends JavaNode {
+public interface TypeParamOwnerNode extends SymbolDeclaratorNode {
+
+ @Override
+ JTypeParameterOwnerSymbol getSymbol();
/**
* Returns the type parameter declaration of this node, or null if
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaProcessingStage.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaProcessingStage.java
index d26082bb69..980cd1a89a 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaProcessingStage.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaProcessingStage.java
@@ -23,17 +23,16 @@ import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.ast.JavaParser;
import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker;
-import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade;
import net.sourceforge.pmd.lang.java.multifile.MultifileVisitorFacade;
import net.sourceforge.pmd.lang.java.qname.QualifiedNameResolver;
import net.sourceforge.pmd.lang.java.symbols.SymbolResolver;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.ast.AstSymFactory;
import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ClasspathSymbolResolver;
import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectionSymFactory;
import net.sourceforge.pmd.lang.java.symbols.table.internal.SemanticChecksLogger;
import net.sourceforge.pmd.lang.java.symbols.table.internal.SymbolTableResolver;
import net.sourceforge.pmd.lang.java.symboltable.SymbolFacade;
import net.sourceforge.pmd.lang.java.typeresolution.PMDASMClassLoader;
-import net.sourceforge.pmd.lang.java.typeresolution.TypeResolutionFacade;
/**
@@ -55,7 +54,7 @@ public enum JavaProcessingStage implements AstProcessingStage new QualifiedNameResolver().initializeWith(classLoader, acu));
+ () -> new QualifiedNameResolver(astSymFactory, configuration.getTypeResolutionClassLoader()).traverse(acu));
SymbolResolver symResolver = new ClasspathSymbolResolver(classLoader, new ReflectionSymFactory());
@@ -93,6 +93,7 @@ public enum JavaProcessingStage implements AstProcessingStageIn fact, populates symbols on declaration nodes.
+ * TODO in the near future we'll get rid of qualified names, and can
+ * reuse this class just to build symbols (moving it to symbols.impl.ast).
+ *
* @author Clément Fournier
* @since 6.1.0
* @deprecated Is internal API
@@ -65,6 +77,9 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
private final Stack innermostEnclosingTypeName = new Stack<>();
+ private final Deque enclosingSymbols = new ArrayDeque<>();
+ private final AstSymFactory symFactory;
+
/**
* Package list of the current file.
* The qualified names of classes and methods declared
@@ -102,16 +117,16 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
*/
private ClassLoader classLoader;
+ public QualifiedNameResolver(AstSymFactory symFactory, ClassLoader classLoader) {
+ this.symFactory = symFactory;
+ this.classLoader = classLoader;
+ }
+
/**
- * Initialises the visitor and starts it.
- *
- * @param classLoader The classloader that will be used by type qualified names
- * to load their type.
- * @param rootNode The root hierarchy
+ * Traverse the compilation unit.
*/
- public void initializeWith(ClassLoader classLoader, ASTCompilationUnit rootNode) {
- this.classLoader = PMDASMClassLoader.getInstance(classLoader);
- rootNode.jjtAccept(this, null);
+ public void traverse(ASTCompilationUnit root) {
+ root.jjtAccept(this, null);
}
@@ -193,6 +208,23 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
return getLongestPackagePrefix(acc.substring(0, acc.lastIndexOf('.')), i - 1);
}
+ @Override
+ public Object visit(ASTVariableDeclaratorId node, Object data) {
+
+ if (isTrueLocalVar(node)) {
+ symFactory.setLocalVarSymbol(node);
+ } else {
+ // in the other cases, building the method/ctor/class symbols already set the symbols
+ assert node.getSymbol() != null : "Symbol was null for " + node;
+ }
+
+ return super.visit(node, data);
+ }
+
+ private boolean isTrueLocalVar(ASTVariableDeclaratorId node) {
+ return !(node.isField() || node.isEnumConstant() || node.getParent() instanceof ASTFormalParameter);
+ }
+
@Override
public Object visit(ASTAnyTypeDeclaration node, Object data) {
@@ -203,26 +235,13 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
updateClassContext(node.getSimpleName(), localIndex);
- InternalApiBridge.setQname(node, contextClassQName());
-
- super.visit(node, data);
-
- // go back to previous context
- rollbackClassContext();
-
- return data;
+ return recurseOnClass(node);
}
-
@Override
public Object visit(ASTAnonymousClassDeclaration node, Object data) {
-
updateContextForAnonymousClass();
- InternalApiBridge.setQname(node, contextClassQName());
- super.visit(node, data);
- rollbackClassContext();
-
- return data;
+ return recurseOnClass(node);
}
@@ -230,7 +249,7 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
public Object visit(ASTMethodDeclaration node, Object data) {
String opname = getOperationName(node.getName(), node.getFirstDescendantOfType(ASTFormalParameters.class));
InternalApiBridge.setQname(node, contextOperationQName(opname, false));
- return super.visit(node, data);
+ return recurseOnExecutable(node);
}
@@ -238,7 +257,31 @@ public class QualifiedNameResolver extends JavaParserVisitorAdapter {
public Object visit(ASTConstructorDeclaration node, Object data) {
String opname = getOperationName(classNames.head(), node.getFirstDescendantOfType(ASTFormalParameters.class));
InternalApiBridge.setQname(node, contextOperationQName(opname, false));
- return super.visit(node, data);
+ return recurseOnExecutable(node);
+ }
+
+
+ public Object recurseOnExecutable(ASTMethodOrConstructorDeclaration node) {
+ JExecutableSymbol sym = node.getSymbol();
+ enclosingSymbols.addLast(sym);
+
+ super.visit(node, null);
+
+ enclosingSymbols.removeLast();
+ return null;
+ }
+
+ public Object recurseOnClass(ASTAnyTypeDeclaration node) {
+ InternalApiBridge.setQname(node, contextClassQName());
+
+ JClassSymbol sym = symFactory.setClassSymbol(enclosingSymbols.peekLast(), node);
+ enclosingSymbols.addLast(sym);
+
+ super.visit(node, null);
+
+ rollbackClassContext();
+ enclosingSymbols.removeLast();
+ return null;
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java
index a6df69870f..81d3335341 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractIgnoredAnnotationRule.java
@@ -38,6 +38,6 @@ public abstract class AbstractIgnoredAnnotationRule extends AbstractJavaRule {
* @return true
if the annotation has been found, otherwise false
*/
protected boolean hasIgnoredAnnotation(Annotatable node) {
- return node.isAnyAnnotationPresent(getProperty(ignoredAnnotationsDescriptor));
+ return getProperty(ignoredAnnotationsDescriptor).stream().anyMatch(node::isAnnotationPresent);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java
index a62b725ef9..63ff42aaaf 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java
@@ -16,7 +16,6 @@ import net.sourceforge.pmd.lang.java.JavaLanguageModule;
import net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTAndExpression;
-import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
@@ -107,9 +106,6 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse
// FIXME those are not in sync with JavaParserVisitorAdapter
// See #1786
- public Object visit(ASTAnnotation node, Object data) {
- return JavaParserVisitor.super.visit(node, data);
- }
public Object visit(ASTExpression node, Object data) {
return JavaParserVisitor.super.visit(node, data);
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java
index f6883b3196..2ba13ebc45 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractLombokAwareRule.java
@@ -136,6 +136,6 @@ public class AbstractLombokAwareRule extends AbstractIgnoredAnnotationRule {
* @return true
if a lombok annotation has been found
*/
protected boolean hasLombokAnnotation(Annotatable node) {
- return node.isAnyAnnotationPresent(LOMBOK_ANNOTATIONS);
+ return LOMBOK_ANNOTATIONS.stream().anyMatch(node::isAnnotationPresent);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java
index 2952d14069..b0a92688a6 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java
@@ -9,13 +9,11 @@ import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
-import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
-import net.sourceforge.pmd.lang.java.ast.ASTNormalAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
@@ -41,7 +39,7 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
@Override
public Object visit(ASTMethodDeclaration method, Object data) {
if (isJUnitMethod(method, data)) {
- if (!isExpectAnnotated(method.getParent())) {
+ if (!isExpectAnnotated(method)) {
Map variables = getVariables(method);
Scope classScope = method.getScope().getParent();
@@ -98,10 +96,9 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
for (Map.Entry> entry : decls.entrySet()) {
Node parent = entry.getKey().getNode().getParent().getParent().getParent();
- if (parent.hasDescendantOfType(ASTMarkerAnnotation.class)
- && parent.getFirstChildOfType(ASTFieldDeclaration.class) != null) {
- String annot = parent.getFirstDescendantOfType(ASTMarkerAnnotation.class).getChild(0).getImage();
- if (!"Rule".equals(annot) && !"org.junit.Rule".equals(annot)) {
+ if (parent.getFirstChildOfType(ASTFieldDeclaration.class) != null) {
+ ASTAnnotation annot = parent.getFirstDescendantOfType(ASTAnnotation.class);
+ if (annot == null || !TypeHelper.isA(annot, "org.junit.Rule")) {
continue;
}
@@ -118,20 +115,12 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
/**
* Tells if the node contains a Test annotation with an expected exception.
*/
- private boolean isExpectAnnotated(Node methodParent) {
- List annotations = methodParent.findDescendantsOfType(ASTNormalAnnotation.class);
- for (ASTNormalAnnotation annotation : annotations) {
- ASTName name = annotation.getFirstChildOfType(ASTName.class);
- if (name != null && TypeHelper.isA(name, JUNIT4_CLASS_NAME)) {
- List memberValues = annotation.findDescendantsOfType(ASTMemberValuePair.class);
- for (ASTMemberValuePair pair : memberValues) {
- if ("expected".equals(pair.getImage())) {
- return true;
- }
- }
- }
- }
- return false;
+ private boolean isExpectAnnotated(ASTMethodDeclaration method) {
+ return method.getDeclaredAnnotations()
+ .filter(it -> TypeHelper.isA(it, JUNIT4_CLASS_NAME))
+ .flatMap(ASTAnnotation::getMembers)
+ .any(it -> "expected".equals(it.getName()));
+
}
/**
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
index 38eb211aa9..f85eecc207 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java
@@ -5,14 +5,12 @@
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import net.sourceforge.pmd.lang.ast.Node;
-import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
-import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
-import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
-import net.sourceforge.pmd.lang.java.ast.ASTName;
+import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTResultType;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.util.CollectionUtil;
@@ -44,17 +42,8 @@ public class LooseCouplingRule extends AbstractJavaRule {
return data;
}
- private boolean methodHasOverride(Node node) {
- ASTClassOrInterfaceBodyDeclaration method = node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
- if (method != null && method.getNumChildren() > 0 && method.getChild(0) instanceof ASTAnnotation) {
- ASTMarkerAnnotation marker = method.getFirstDescendantOfType(ASTMarkerAnnotation.class);
- if (marker != null && marker.getFirstChildOfType(ASTName.class) != null) {
- ASTName name = marker.getFirstChildOfType(ASTName.class);
- if (name.getType() == Override.class) {
- return true;
- }
- }
- }
- return false;
+ private boolean methodHasOverride(JavaNode node) {
+ ASTMethodDeclaration method = node.ancestors(ASTMethodDeclaration.class).first();
+ return method != null && method.isAnnotationPresent(Override.class);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java
index 9076e635de..1b00d0f84d 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java
@@ -18,7 +18,6 @@ import java.util.Stack;
import java.util.logging.Logger;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
-import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
@@ -213,11 +212,9 @@ public class MissingOverrideRule extends AbstractJavaRule {
return super.visit(node, data);
}
- for (ASTAnnotation annot : node.getDeclaredAnnotations()) {
- if (Override.class.equals(annot.getType())) {
- // we assume the compiler has already checked it, so it's correct
- return super.visit(node, data);
- }
+ if (node.isAnnotationPresent(Override.class)) {
+ // we assume the compiler has already checked it, so it's correct
+ return super.visit(node, data);
}
try {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java
index 0111277c61..a04cfbfbf9 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedFormalParameterRule.java
@@ -18,10 +18,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
-import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
-import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTThrowsList;
import net.sourceforge.pmd.lang.java.ast.ASTType;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
@@ -125,17 +123,6 @@ public class UnusedFormalParameterRule extends AbstractJavaRule {
}
private boolean hasOverrideAnnotation(ASTMethodDeclaration node) {
- int childIndex = node.getIndexInParent();
- for (int i = 0; i < childIndex; i++) {
- Node previousSibling = node.getParent().getChild(i);
- List annotations = previousSibling.findDescendantsOfType(ASTMarkerAnnotation.class);
- for (ASTMarkerAnnotation annotation : annotations) {
- ASTName name = annotation.getFirstChildOfType(ASTName.class);
- if (name != null && (name.hasImageEqualTo("Override") || name.hasImageEqualTo("java.lang.Override"))) {
- return true;
- }
- }
- }
- return false;
+ return node.isAnnotationPresent(Override.class);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
index b805a0cabc..0fab28c792 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
@@ -73,7 +73,7 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule memberValuePairs = annotation.findDescendantsOfType(ASTMemberValuePair.class);
-
- for (ASTMemberValuePair memberValuePair : memberValuePairs) {
- // to set the access level of a constructor in lombok, you set the access property on the annotation
- if ("access".equals(memberValuePair.getImage())) {
- List names = memberValuePair.findDescendantsOfType(ASTName.class);
-
- for (ASTName name : names) {
- // check to see if the value of the member value pair ends PRIVATE. This is from the AccessLevel enum in Lombok
- if (name.getImage().endsWith("PRIVATE")) {
- // if the constructor is found and the accesslevel is private no need to check anything else
- return true;
- }
- }
- }
- }
- }
-
- return false;
+ return parent.getDeclaredAnnotations()
+ .filter(t -> TypeHelper.isA(t, "lombok.NoArgsConstructor"))
+ .flatMap(ASTAnnotation::getMembers)
+ // to set the access level of a constructor in lombok, you set the access property on the annotation
+ .filterMatching(ASTMemberValuePair::getName, "access")
+ .map(ASTMemberValuePair::getValue)
+ // This is from the AccessLevel enum in Lombok
+ // if the constructor is found and the accesslevel is private no need to check anything else
+ .any(it -> it.getImage().equals("PRIVATE"));
}
private Node skipAnnotations(Node p) {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
index fd5b262987..fab4558260 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
@@ -10,7 +10,6 @@ import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
-import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
@@ -19,7 +18,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
-import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTName;
@@ -31,6 +29,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTResultType;
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
+import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
import net.sourceforge.pmd.properties.PropertyDescriptor;
@@ -175,20 +174,8 @@ public class UselessOverridingMethodRule extends AbstractJavaRule {
return super.visit(node, data);
}
- if (!ignoreAnnotations) {
- ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.getParent();
- for (int i = 0; i < parent.getNumChildren(); i++) {
- Node n = parent.getChild(i);
- if (n instanceof ASTAnnotation) {
- if (n.getChild(0) instanceof ASTMarkerAnnotation) {
- // @Override is ignored
- if ("Override".equals(((ASTName) n.getChild(0).getChild(0)).getImage())) {
- continue;
- }
- }
- return super.visit(node, data);
- }
- }
+ if (!ignoreAnnotations && node.getDeclaredAnnotations().any(it -> !TypeHelper.isExactlyA(it, Override.class.getName()))) {
+ return super.visit(node, data);
}
if (arguments.getNumChildren() == 0) {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java
index 60dcafd286..f9af7da0ef 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java
@@ -19,9 +19,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.AccessNode;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.multifile.signature.JavaOperationSignature;
@@ -178,13 +176,7 @@ public class CommentRequiredRule extends AbstractCommentRule {
private boolean isAnnotatedOverride(ASTMethodDeclaration decl) {
- List annotations = decl.getParent().findDescendantsOfType(ASTMarkerAnnotation.class);
- for (ASTMarkerAnnotation ann : annotations) { // TODO consider making a method to get the annotations of a method
- if (ann.getFirstChildOfType(ASTName.class).getImage().equals("Override")) {
- return true;
- }
- }
- return false;
+ return decl.isAnnotationPresent(Override.class);
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java
index eb210b9f8b..30ebdd4b95 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AnnotationSuppressionUtil.java
@@ -100,12 +100,7 @@ final class AnnotationSuppressionUtil {
}
private static boolean hasSuppressWarningsAnnotationFor(final Annotatable node, Rule rule) {
- for (ASTAnnotation a : node.getDeclaredAnnotations()) {
- if (annotationSuppresses(a, rule)) {
- return true;
- }
- }
- return false;
+ return node.getDeclaredAnnotations().any(it -> annotationSuppresses(it, rule));
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
index f49b1767b7..7b408cc08d 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
@@ -218,4 +218,9 @@ public interface JClassSymbol extends JTypeDeclSymbol,
return !isInterface() && !isArray() && !isPrimitive();
}
+
+ @Override
+ default R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitClass(this, param);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JConstructorSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JConstructorSymbol.java
index 60fc77dc6b..7f8037e582 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JConstructorSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JConstructorSymbol.java
@@ -24,4 +24,11 @@ public interface JConstructorSymbol extends JExecutableSymbol, BoundToNode R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitCtor(this, param);
+ }
+
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JElementSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JElementSymbol.java
index 53745b7c08..1465417183 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JElementSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JElementSymbol.java
@@ -67,7 +67,7 @@ public interface JElementSymbol {
*
* @param o Comparand
*
- * @return True if the other is a symbol of the same type and
+ * @return True if the other is a symbol for the same program element
*/
@Override
boolean equals(Object o);
@@ -80,4 +80,11 @@ public interface JElementSymbol {
// We should be able to create a type definition from a java.lang.reflect.Type,
// paying attention to type variables of enclosing methods and types.
// We should also be able to do so from an ASTType, with support from a JSymbolTable.
+
+
+ /**
+ * Dispatch to the appropriate visit method of the visitor and returns its result.
+ */
+ R acceptVisitor(SymbolVisitor visitor, P param);
+
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFieldSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFieldSymbol.java
index 7b1955a0d7..40aa12b0c3 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFieldSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFieldSymbol.java
@@ -37,4 +37,9 @@ public interface JFieldSymbol extends JAccessibleElementSymbol, JVariableSymbol
return getEnclosingClass().getPackageName();
}
+
+ @Override
+ default R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitField(this, param);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFormalParamSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFormalParamSymbol.java
index 8db15905fe..93bddc3661 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFormalParamSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JFormalParamSymbol.java
@@ -15,4 +15,9 @@ public interface JFormalParamSymbol extends JLocalVariableSymbol {
/** Returns the symbol declaring this parameter. */
JExecutableSymbol getDeclaringSymbol();
+
+ @Override
+ default R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitFormal(this, param);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JLocalVariableSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JLocalVariableSymbol.java
index 3d4f1d9992..c6de6d327b 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JLocalVariableSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JLocalVariableSymbol.java
@@ -18,4 +18,10 @@ public interface JLocalVariableSymbol extends JVariableSymbol {
// todo maybe add isParameter, isLocalVariable, isCatchParameter, etc.
+
+
+ @Override
+ default R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitLocal(this, param);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JMethodSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JMethodSymbol.java
index 1be7deca03..598f20bcb3 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JMethodSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JMethodSymbol.java
@@ -25,4 +25,10 @@ public interface JMethodSymbol extends JExecutableSymbol, BoundToNode R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitMethod(this, param);
+ }
+
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JTypeParameterSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JTypeParameterSymbol.java
index 55d0df12ed..8ff630bc28 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JTypeParameterSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JTypeParameterSymbol.java
@@ -8,7 +8,6 @@ package net.sourceforge.pmd.lang.java.symbols;
import java.lang.reflect.Modifier;
import org.checkerframework.checker.nullness.qual.NonNull;
-import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter;
@@ -42,11 +41,16 @@ public interface JTypeParameterSymbol extends JTypeDeclSymbol, BoundToNode R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitTypeParam(this, param);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/SymbolVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/SymbolVisitor.java
new file mode 100644
index 0000000000..5922392d4a
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/SymbolVisitor.java
@@ -0,0 +1,69 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols;
+
+/**
+ * Visitor over symbols.
+ */
+public interface SymbolVisitor {
+
+
+ R visitSymbol(JElementSymbol sym, P p);
+
+ default R visitTypeDecl(JTypeDeclSymbol sym, P param) {
+ return visitSymbol(sym, param);
+ }
+
+ /** Delegates to {@link #visitTypeDecl(JTypeDeclSymbol, Object) visitTypeDecl}. */
+ default R visitClass(JClassSymbol sym, P param) {
+ return visitTypeDecl(sym, param);
+ }
+
+ /** Delegates to {@link #visitClass(JClassSymbol, Object) visitClass}. */
+ default R visitArray(JClassSymbol sym, JTypeDeclSymbol component, P param) {
+ return visitClass(sym, param);
+ }
+
+ /** Delegates to {@link #visitTypeDecl(JTypeDeclSymbol, Object) visitTypeDecl}. */
+ default R visitTypeParam(JTypeParameterSymbol sym, P param) {
+ return visitTypeDecl(sym, param);
+ }
+
+
+ default R visitExecutable(JExecutableSymbol sym, P param) {
+ return visitSymbol(sym, param);
+ }
+
+ /** Delegates to {@link #visitExecutable(JExecutableSymbol, Object) visitExecutable}. */
+ default R visitCtor(JConstructorSymbol sym, P param) {
+ return visitExecutable(sym, param);
+ }
+
+ /** Delegates to {@link #visitExecutable(JExecutableSymbol, Object) visitExecutable}. */
+ default R visitMethod(JMethodSymbol sym, P param) {
+ return visitExecutable(sym, param);
+ }
+
+
+ default R visitVariable(JVariableSymbol sym, P param) {
+ return visitSymbol(sym, param);
+ }
+
+ /** Delegates to {@link #visitVariable(JVariableSymbol, Object) visitVariable}. */
+ default R visitField(JFieldSymbol sym, P param) {
+ return visitVariable(sym, param);
+ }
+
+ /** Delegates to {@link #visitVariable(JVariableSymbol, Object) visitVariable}. */
+ default R visitLocal(JLocalVariableSymbol sym, P param) {
+ return visitVariable(sym, param);
+ }
+
+ /** Delegates to {@link #visitLocal(JLocalVariableSymbol, Object) visitLocal}. */
+ default R visitFormal(JFormalParamSymbol sym, P param) {
+ return visitLocal(sym, param);
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ArraySymbolImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ArraySymbolImpl.java
index aa1fe51d1e..e39f8b9553 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ArraySymbolImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ArraySymbolImpl.java
@@ -17,10 +17,11 @@ import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
-import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.lang.java.symbols.SymbolVisitor;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals;
/**
* Generic implementation for array symbols, which does not rely on
@@ -83,22 +84,22 @@ class ArraySymbolImpl implements JClassSymbol {
@Override
public List getDeclaredMethods() {
- return Collections.singletonList(new ArrayCloneMethod(this));
+ return Collections.singletonList(ImplicitMemberSymbols.arrayClone(this));
}
@Override
public List getDeclaredFields() {
- return Collections.singletonList(new ArrayLengthField(this));
+ return Collections.singletonList(ImplicitMemberSymbols.arrayLengthField(this));
}
@Override
public @Nullable JClassSymbol getSuperclass() {
- return SymbolFactory.OBJECT_SYM;
+ return ReflectSymInternals.OBJECT_SYM;
}
@Override
public List getSuperInterfaces() {
- return SymbolFactory.ARRAY_SUPER_INTERFACES;
+ return ReflectSymInternals.ARRAY_SUPER_INTERFACES;
}
@Override
@@ -106,22 +107,19 @@ class ArraySymbolImpl implements JClassSymbol {
return component;
}
+ @Override
+ public R acceptVisitor(SymbolVisitor visitor, P param) {
+ return visitor.visitArray(this, component, param);
+ }
@Override
public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ArraySymbolImpl that = (ArraySymbolImpl) o;
- return Objects.equals(component, that.component);
+ return SymbolEquality.equals(this, o);
}
@Override
public int hashCode() {
- return Objects.hash(component);
+ return SymbolEquality.hash(this);
}
@Override
@@ -131,7 +129,7 @@ class ArraySymbolImpl implements JClassSymbol {
@Override
public List getConstructors() {
- return Collections.singletonList(new ArrayConstructor(this));
+ return Collections.singletonList(ImplicitMemberSymbols.arrayConstructor(this));
}
@Override
@@ -200,187 +198,7 @@ class ArraySymbolImpl implements JClassSymbol {
@Override
public String toString() {
- return "array(" + component.toString() + ")";
+ return SymbolToStrings.SHARED.toString(this);
}
- private static class ArrayLengthField implements JFieldSymbol {
-
- private final JClassSymbol arraySymbol;
-
- ArrayLengthField(JClassSymbol arraySymbol) {
- this.arraySymbol = arraySymbol;
- }
-
- @Override
- public String getSimpleName() {
- return "length";
- }
-
- @Override
- public int getModifiers() {
- return Modifier.PUBLIC | Modifier.FINAL;
- }
-
- @Override
- public boolean isEnumConstant() {
- return false;
- }
-
- @Override
- public @NonNull JClassSymbol getEnclosingClass() {
- return arraySymbol;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ArrayLengthField that = (ArrayLengthField) o;
- return arraySymbol.equals(that.arraySymbol);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(arraySymbol);
- }
- }
-
- private static class ArrayCloneMethod implements JMethodSymbol {
-
- private final ArraySymbolImpl arraySymbol;
-
- ArrayCloneMethod(ArraySymbolImpl arraySymbol) {
- this.arraySymbol = arraySymbol;
- }
-
- @Override
- public String getSimpleName() {
- return "clone";
- }
-
- @Override
- public List getFormalParameters() {
- return Collections.emptyList();
- }
-
- @Override
- public boolean isVarargs() {
- return false;
- }
-
- @Override
- public int getArity() {
- return 0;
- }
-
- @Override
- public int getModifiers() {
- return Modifier.PUBLIC;
- }
-
- @Override
- public @NonNull JClassSymbol getEnclosingClass() {
- return arraySymbol;
- }
-
- @Override
- public List getTypeParameters() {
- return Collections.emptyList();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ArrayCloneMethod that = (ArrayCloneMethod) o;
- return Objects.equals(arraySymbol, that.arraySymbol);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(arraySymbol);
- }
- }
-
- private static class ArrayConstructor implements JConstructorSymbol {
-
- private final ArraySymbolImpl arraySymbol;
-
- ArrayConstructor(ArraySymbolImpl arraySymbol) {
- this.arraySymbol = arraySymbol;
- }
-
- @Override
- public List getFormalParameters() {
- return Collections.singletonList(new JFormalParamSymbol() {
-
- @Override
- public JExecutableSymbol getDeclaringSymbol() {
- return ArrayConstructor.this;
- }
-
- @Override
- public String getSimpleName() {
- return "arg0";
- }
-
- @Override
- public boolean isFinal() {
- return false;
- }
-
- // TODO equals/hashcode?
- });
- }
-
- @Override
- public boolean isVarargs() {
- return false;
- }
-
- @Override
- public int getArity() {
- return 1;
- }
-
- @Override
- public int getModifiers() {
- return Modifier.PUBLIC | Modifier.FINAL;
- }
-
- @Override
- public @NonNull JClassSymbol getEnclosingClass() {
- return arraySymbol;
- }
-
- @Override
- public List getTypeParameters() {
- return Collections.emptyList();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ArrayConstructor that = (ArrayConstructor) o;
- return Objects.equals(arraySymbol, that.arraySymbol);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(arraySymbol);
- }
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ImplicitMemberSymbols.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ImplicitMemberSymbols.java
new file mode 100644
index 0000000000..62c606ee86
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ImplicitMemberSymbols.java
@@ -0,0 +1,268 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.function.Function;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.util.CollectionUtil;
+
+/**
+ * Members inserted by the compiler, eg default constructor, etc. They
+ * would be absent from the source, but are reflected by the {@link Class}.
+ */
+public final class ImplicitMemberSymbols {
+
+ private static final int VISIBILITY_MASK = Modifier.PRIVATE | Modifier.PUBLIC | Modifier.PROTECTED;
+
+ private ImplicitMemberSymbols() {
+
+ }
+
+ public static JMethodSymbol enumValueOf(JClassSymbol enumSym) {
+ assert enumSym.isEnum() : "Not an enum symbol " + enumSym;
+
+ return new FakeMethodSym(
+ enumSym,
+ "valueOf",
+ Modifier.PUBLIC | Modifier.STATIC,
+ singletonList(t -> new FakeFormalParamSym(t, "name"))
+ );
+ }
+
+ public static JMethodSymbol enumValues(JClassSymbol enumSym) {
+ assert enumSym.isEnum() : "Not an enum symbol " + enumSym;
+
+ return new FakeMethodSym(
+ enumSym,
+ "values",
+ Modifier.PUBLIC | Modifier.STATIC,
+ emptyList()
+ );
+ }
+
+
+ public static JConstructorSymbol defaultCtor(JClassSymbol sym) {
+ assert sym != null;
+
+ // Enum constructors have 2 additional implicit parameters, for the name and ordinal
+ // Inner classes have 1 additional implicit param, for the outer instance
+ // They are not reflected by the symbol
+
+ int modifiers = sym.isEnum() ? Modifier.PRIVATE
+ : sym.getModifiers() & VISIBILITY_MASK;
+
+ return new FakeCtorSym(sym, modifiers, emptyList());
+ }
+
+
+ public static JMethodSymbol arrayClone(JClassSymbol arraySym) {
+ assert arraySym.isArray() : "Not an array symbol " + arraySym;
+
+ return new FakeMethodSym(
+ arraySym,
+ "clone",
+ Modifier.PUBLIC | Modifier.FINAL,
+ emptyList()
+ );
+ }
+
+ public static JConstructorSymbol arrayConstructor(JClassSymbol arraySym) {
+ assert arraySym.isArray() : "Not an array symbol " + arraySym;
+
+ return new FakeCtorSym(
+ arraySym,
+ Modifier.PUBLIC | Modifier.FINAL,
+ singletonList(c -> new FakeFormalParamSym(c, "arg0"))
+ );
+ }
+
+ public static JFieldSymbol arrayLengthField(JClassSymbol arraySym) {
+ assert arraySym.isArray() : "Not an array symbol " + arraySym;
+
+ return new FakeFieldSym(
+ arraySym,
+ "length",
+ Modifier.PUBLIC | Modifier.FINAL
+ );
+ }
+
+ private abstract static class FakeExecutableSymBase implements JExecutableSymbol {
+
+ private final JClassSymbol owner;
+ private final String name;
+ private final int modifiers;
+ private final List formals;
+
+ FakeExecutableSymBase(JClassSymbol owner,
+ String name,
+ int modifiers,
+ List> formals) {
+ this.owner = owner;
+ this.name = name;
+ this.modifiers = modifiers;
+ this.formals = CollectionUtil.map(formals, f -> f.apply((T) this));
+ }
+
+ @Override
+ public String getSimpleName() {
+ return name;
+ }
+
+ @Override
+ public List getFormalParameters() {
+ return formals;
+ }
+
+ @Override
+ public boolean isVarargs() {
+ return false;
+ }
+
+ @Override
+ public int getArity() {
+ return formals.size();
+ }
+
+ @Override
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ @Override
+ public @NonNull JClassSymbol getEnclosingClass() {
+ return owner;
+ }
+
+ @Override
+ public List getTypeParameters() {
+ return emptyList();
+ }
+
+ }
+
+ private static final class FakeMethodSym extends FakeExecutableSymBase implements JMethodSymbol {
+
+ FakeMethodSym(JClassSymbol owner,
+ String name,
+ int modifiers,
+ List> formals) {
+ super(owner, name, modifiers, formals);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return SymbolEquality.METHOD.equals(this, o);
+ }
+
+ @Override
+ public int hashCode() {
+ return SymbolEquality.METHOD.hash(this);
+ }
+ }
+
+ private static final class FakeCtorSym extends FakeExecutableSymBase implements JConstructorSymbol {
+
+ FakeCtorSym(JClassSymbol owner,
+ int modifiers,
+ List> formals) {
+ super(owner, JConstructorSymbol.CTOR_NAME, modifiers, formals);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return SymbolEquality.CONSTRUCTOR.equals(this, o);
+ }
+
+ @Override
+ public int hashCode() {
+ return SymbolEquality.CONSTRUCTOR.hash(this);
+ }
+ }
+
+ private static final class FakeFormalParamSym implements JFormalParamSymbol {
+
+ private final JExecutableSymbol owner;
+ private final String name;
+
+ private FakeFormalParamSym(JExecutableSymbol owner, String name) {
+ this.owner = owner;
+ this.name = name;
+ }
+
+ @Override
+ public JExecutableSymbol getDeclaringSymbol() {
+ return owner;
+ }
+
+ @Override
+ public boolean isFinal() {
+ return false;
+ }
+
+ @Override
+ public String getSimpleName() {
+ return name;
+ }
+ }
+
+
+ private static final class FakeFieldSym implements JFieldSymbol {
+
+ private final JClassSymbol owner;
+ private final String name;
+ private final int modifiers;
+
+ FakeFieldSym(JClassSymbol owner, String name, int modifiers) {
+ this.owner = owner;
+ this.name = name;
+ this.modifiers = modifiers;
+ }
+
+ @Override
+ public String getSimpleName() {
+ return name;
+ }
+
+ @Override
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ @Override
+ public boolean isEnumConstant() {
+ return false;
+ }
+
+ @Override
+ public @NonNull JClassSymbol getEnclosingClass() {
+ return owner;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return SymbolEquality.FIELD.equals(this, o);
+ }
+
+ @Override
+ public int hashCode() {
+ return SymbolEquality.FIELD.hash(this);
+ }
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolEquality.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolEquality.java
index 5def8a0679..8c929e5c93 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolEquality.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolEquality.java
@@ -11,8 +11,10 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.lang.java.symbols.SymbolVisitor;
/**
* Routines to share logic for equality, respecting the contract of
@@ -157,6 +159,18 @@ public final class SymbolEquality {
}
};
+ private static final EqAndHash IDENTITY = new EqAndHash() {
+ @Override
+ public int hash(Object t1) {
+ return System.identityHashCode(t1);
+ }
+
+ @Override
+ public boolean equals(Object t1, Object t2) {
+ return t1 == t2;
+ }
+ };
+
/**
* Strategy to perform equals/hashcode for a type T. There are libraries
* for that, whatever.
@@ -168,7 +182,64 @@ public final class SymbolEquality {
public abstract boolean equals(T t1, Object t2);
+ }
+ public static boolean equals(T e1, Object e2) {
+ @SuppressWarnings("unchecked")
+ EqAndHash eqAndHash = (EqAndHash) e1.acceptVisitor(EqAndHashVisitor.INSTANCE, null);
+ return eqAndHash.equals(e1, e2);
+ }
+
+ public static int hash(T e1) {
+ @SuppressWarnings("unchecked")
+ EqAndHash eqAndHash = (EqAndHash) e1.acceptVisitor(EqAndHashVisitor.INSTANCE, null);
+ return eqAndHash.hash(e1);
+ }
+
+
+ private static final class EqAndHashVisitor implements SymbolVisitor, Void> {
+
+ static final EqAndHashVisitor INSTANCE = new EqAndHashVisitor();
+
+ @Override
+ public EqAndHash> visitSymbol(JElementSymbol sym, Void aVoid) {
+ throw new IllegalStateException("Unknown symbol " + sym.getClass());
+ }
+
+ @Override
+ public EqAndHash> visitClass(JClassSymbol sym, Void param) {
+ return CLASS;
+ }
+
+ @Override
+ public EqAndHash> visitTypeParam(JTypeParameterSymbol sym, Void param) {
+ return TYPE_PARAM;
+ }
+
+ @Override
+ public EqAndHash> visitCtor(JConstructorSymbol sym, Void param) {
+ return CONSTRUCTOR;
+ }
+
+ @Override
+ public EqAndHash> visitMethod(JMethodSymbol sym, Void param) {
+ return METHOD;
+ }
+
+ @Override
+ public EqAndHash> visitField(JFieldSymbol sym, Void param) {
+ return FIELD;
+ }
+
+ @Override
+ public EqAndHash> visitLocal(JLocalVariableSymbol sym, Void param) {
+ return IDENTITY;
+ }
+
+ @Override
+ public EqAndHash> visitFormal(JFormalParamSymbol sym, Void param) {
+ return FORMAL_PARAM;
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolFactory.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolFactory.java
index d7d4bec210..ef3a2a2c4b 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolFactory.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolFactory.java
@@ -5,18 +5,12 @@
package net.sourceforge.pmd.lang.java.symbols.internal.impl;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals;
/**
* Builds symbols.
@@ -29,46 +23,9 @@ import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInt
*/
public interface SymbolFactory {
-
- // object
- JClassSymbol OBJECT_SYM = ReflectSymInternals.createSharedSym(Object.class);
// unresolved symbol
JClassSymbol UNRESOLVED_CLASS_SYM = new UnresolvedClassImpl("/*unresolved*/");
- // primitives
- JClassSymbol BOOLEAN_SYM = ReflectSymInternals.createSharedSym(boolean.class);
- JClassSymbol BYTE_SYM = ReflectSymInternals.createSharedSym(byte.class);
- JClassSymbol CHAR_SYM = ReflectSymInternals.createSharedSym(char.class);
- JClassSymbol DOUBLE_SYM = ReflectSymInternals.createSharedSym(double.class);
- JClassSymbol FLOAT_SYM = ReflectSymInternals.createSharedSym(float.class);
- JClassSymbol INT_SYM = ReflectSymInternals.createSharedSym(int.class);
- JClassSymbol LONG_SYM = ReflectSymInternals.createSharedSym(long.class);
- JClassSymbol SHORT_SYM = ReflectSymInternals.createSharedSym(short.class);
- JClassSymbol VOID_SYM = ReflectSymInternals.createSharedSym(void.class);
-
- // primitive wrappers
- JClassSymbol BOXED_BOOLEAN_SYM = ReflectSymInternals.createSharedSym(Boolean.class);
- JClassSymbol BOXED_BYTE_SYM = ReflectSymInternals.createSharedSym(Byte.class);
- JClassSymbol BOXED_CHAR_SYM = ReflectSymInternals.createSharedSym(Character.class);
- JClassSymbol BOXED_DOUBLE_SYM = ReflectSymInternals.createSharedSym(Double.class);
- JClassSymbol BOXED_FLOAT_SYM = ReflectSymInternals.createSharedSym(Float.class);
- JClassSymbol BOXED_INT_SYM = ReflectSymInternals.createSharedSym(Integer.class);
- JClassSymbol BOXED_LONG_SYM = ReflectSymInternals.createSharedSym(Long.class);
- JClassSymbol BOXED_SHORT_SYM = ReflectSymInternals.createSharedSym(Short.class);
- JClassSymbol BOXED_VOID_SYM = ReflectSymInternals.createSharedSym(Void.class);
-
- // array supertypes
- JClassSymbol CLONEABLE_SYM = ReflectSymInternals.createSharedSym(Cloneable.class);
- JClassSymbol SERIALIZABLE_SYM = ReflectSymInternals.createSharedSym(Serializable.class);
- List ARRAY_SUPER_INTERFACES = Collections.unmodifiableList(Arrays.asList(CLONEABLE_SYM, SERIALIZABLE_SYM));
-
- // other important/common types
- JClassSymbol CLASS_SYM = ReflectSymInternals.createSharedSym(Class.class);
- JClassSymbol ITERABLE_SYM = ReflectSymInternals.createSharedSym(Iterable.class);
- JClassSymbol ENUM_SYM = ReflectSymInternals.createSharedSym(Enum.class);
- JClassSymbol STRING_SYM = ReflectSymInternals.createSharedSym(String.class);
-
-
/**
* Produces an unresolved class symbol from the given canonical name.
*
@@ -83,6 +40,7 @@ public interface SymbolFactory {
}
+
/**
* Produces an array symbol from the given component symbol (one dimension).
* The component can naturally be another array symbol, but cannot be an
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolToStrings.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolToStrings.java
new file mode 100644
index 0000000000..0d455e3a1d
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/SymbolToStrings.java
@@ -0,0 +1,121 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl;
+
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.lang.java.symbols.SymbolVisitor;
+
+public class SymbolToStrings {
+
+ public static final SymbolToStrings SHARED = new SymbolToStrings("");
+ public static final SymbolToStrings REFLECT = new SymbolToStrings("reflect");
+ public static final SymbolToStrings AST = new SymbolToStrings("ast");
+
+ private final ToStringVisitor visitor;
+
+ public SymbolToStrings(String impl) {
+ this.visitor = new ToStringVisitor(impl);
+ }
+
+ public String toString(JElementSymbol symbol) {
+ return symbol.acceptVisitor(visitor, new StringBuilder()).toString();
+ }
+
+ private static class ToStringVisitor implements SymbolVisitor {
+
+ private final String impl;
+
+ private ToStringVisitor(String impl) {
+ this.impl = impl;
+ }
+
+ private StringBuilder withImpl(StringBuilder builder, String kind, Object first, Object... rest) {
+ if (!impl.isEmpty()) {
+ builder.append(impl).append(':');
+ }
+ builder.append(kind).append('(');
+ appendArg(builder, first);
+ for (Object s : rest) {
+ builder.append(", ");
+ appendArg(builder, s);
+ }
+ return builder.append(')');
+ }
+
+ private void appendArg(StringBuilder builder, Object s) {
+ if (s instanceof JElementSymbol) {
+ ((JElementSymbol) s).acceptVisitor(this, builder);
+ } else {
+ builder.append(s);
+ }
+ }
+
+ @Override
+ public StringBuilder visitSymbol(JElementSymbol sym, StringBuilder builder) {
+ throw new IllegalStateException("Unknown symbol " + sym.getClass());
+ }
+
+ @Override
+ public StringBuilder visitClass(JClassSymbol sym, StringBuilder param) {
+ String kind;
+ if (sym.isUnresolved()) {
+ kind = "unresolved";
+ } else if (sym.isEnum()) {
+ kind = "enum";
+ } else if (sym.isAnnotation()) {
+ kind = "annot";
+ } else {
+ kind = "class";
+ }
+
+ return withImpl(param, kind, sym.getBinaryName());
+ }
+
+ @Override
+ public StringBuilder visitArray(JClassSymbol sym, JTypeDeclSymbol component, StringBuilder param) {
+ param.append("array(");
+ return component.acceptVisitor(this, param).append(")");
+ }
+
+ @Override
+ public StringBuilder visitTypeParam(JTypeParameterSymbol sym, StringBuilder param) {
+ return withImpl(param, "tparam", sym.getSimpleName(), sym.getDeclaringSymbol());
+ }
+
+ @Override
+ public StringBuilder visitCtor(JConstructorSymbol sym, StringBuilder param) {
+ return withImpl(param, "ctor", sym.getEnclosingClass());
+ }
+
+ @Override
+ public StringBuilder visitMethod(JMethodSymbol sym, StringBuilder param) {
+ return withImpl(param, "method", sym.getSimpleName(), sym.getEnclosingClass());
+ }
+
+ @Override
+ public StringBuilder visitField(JFieldSymbol sym, StringBuilder param) {
+ return withImpl(param, "field", sym.getSimpleName(), sym.getEnclosingClass());
+ }
+
+ @Override
+ public StringBuilder visitLocal(JLocalVariableSymbol sym, StringBuilder param) {
+ return withImpl(param, "local", sym.getSimpleName());
+ }
+
+ @Override
+ public StringBuilder visitFormal(JFormalParamSymbol sym, StringBuilder param) {
+ return withImpl(param, "formal", sym.getSimpleName());
+ }
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/UnresolvedClassImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/UnresolvedClassImpl.java
index 3d30d78996..0e454ffaa8 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/UnresolvedClassImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/UnresolvedClassImpl.java
@@ -7,7 +7,6 @@ package net.sourceforge.pmd.lang.java.symbols.internal.impl;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -19,6 +18,7 @@ import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals;
/**
* Unresolved external reference to a class.
@@ -95,7 +95,7 @@ class UnresolvedClassImpl implements JClassSymbol {
@Nullable
@Override
public JClassSymbol getSuperclass() {
- return SymbolFactory.OBJECT_SYM;
+ return ReflectSymInternals.OBJECT_SYM;
}
@@ -171,32 +171,25 @@ class UnresolvedClassImpl implements JClassSymbol {
return Collections.emptyList();
}
- @Override
- public String toString() {
- return "unresolved(" + canonicalName + ")";
- }
-
@Override
public List getTypeParameters() {
return Collections.emptyList();
}
+ @Override
+ public String toString() {
+ return SymbolToStrings.SHARED.toString(this);
+ }
+
@Override
public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof JClassSymbol)) {
- return false;
- }
- JClassSymbol that = (JClassSymbol) o;
- return Objects.equals(getBinaryName(), that.getBinaryName());
+ return SymbolEquality.equals(this, o);
}
@Override
public int hashCode() {
- return Objects.hash(this.getSimpleName());
+ return SymbolEquality.hash(this);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstBackedSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstBackedSymbol.java
new file mode 100644
index 0000000000..e2211cfa35
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstBackedSymbol.java
@@ -0,0 +1,41 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
+import net.sourceforge.pmd.lang.java.ast.SymbolDeclaratorNode;
+import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolToStrings;
+
+/**
+ * @author Clément Fournier
+ */
+abstract class AbstractAstBackedSymbol implements JElementSymbol {
+
+ protected final T node;
+ protected final AstSymFactory factory;
+
+ protected AbstractAstBackedSymbol(T node, AstSymFactory factory) {
+ this.node = node;
+ this.factory = factory;
+ InternalApiBridge.setSymbol(node, this);
+ }
+
+ @Override
+ public String toString() {
+ return SymbolToStrings.AST.toString(this);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return SymbolEquality.equals(this, o);
+ }
+
+ @Override
+ public int hashCode() {
+ return SymbolEquality.hash(this);
+ }
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstExecSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstExecSymbol.java
new file mode 100644
index 0000000000..cff5957e3d
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstExecSymbol.java
@@ -0,0 +1,58 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import java.util.List;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
+import net.sourceforge.pmd.util.CollectionUtil;
+
+/**
+ * @author Clément Fournier
+ */
+abstract class AbstractAstExecSymbol
+ extends AbstractAstTParamOwner
+ implements JExecutableSymbol {
+
+ private final JClassSymbol owner;
+ private List formals;
+
+ protected AbstractAstExecSymbol(T node, AstSymFactory factory, JClassSymbol owner) {
+ super(node, factory);
+ this.owner = owner;
+ formals = CollectionUtil.map(
+ node.getFormalParameters(),
+ p -> new AstFormalParamSym(p.getVarId(), factory, this)
+ );
+ }
+
+ @Override
+ public List getFormalParameters() {
+ return formals;
+ }
+
+ @Override
+ public @NonNull JClassSymbol getEnclosingClass() {
+ return owner;
+ }
+
+
+ @Override
+ public boolean isVarargs() {
+ return node.isVarargs();
+ }
+
+ @Override
+ public int getArity() {
+ return formals.size();
+ }
+
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstTParamOwner.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstTParamOwner.java
new file mode 100644
index 0000000000..120aad1551
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstTParamOwner.java
@@ -0,0 +1,70 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import static net.sourceforge.pmd.util.CollectionUtil.map;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import net.sourceforge.pmd.lang.java.ast.ASTList;
+import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
+import net.sourceforge.pmd.lang.java.ast.AccessNode;
+import net.sourceforge.pmd.lang.java.ast.JModifier;
+import net.sourceforge.pmd.lang.java.ast.TypeParamOwnerNode;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+abstract class AbstractAstTParamOwner
+ extends AbstractAstBackedSymbol implements JTypeParameterOwnerSymbol {
+
+ private final List tparams;
+ private final int modifiers;
+
+
+ AbstractAstTParamOwner(T node, AstSymFactory factory) {
+ super(node, factory);
+ this.modifiers = JModifier.toReflect(node.getModifiers().getEffectiveModifiers());
+
+ List result = map(
+ ASTList.orEmpty(node.getTypeParameters()),
+ it -> new AstTypeParamSym(it, factory, this)
+ );
+
+ // this needs to be set before calling computeBounds
+ this.tparams = Collections.unmodifiableList(result);
+
+ }
+
+ @Override
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ @Override
+ public List getTypeParameters() {
+ return tparams;
+ }
+
+
+ @Override
+ public @NonNull String getPackageName() {
+ return node.getRoot().getPackageName();
+ }
+
+ @Override
+ public int getTypeParameterCount() {
+ if (tparams != null) {
+ return tparams.size();
+ }
+ ASTTypeParameters ps = node.getTypeParameters();
+ return ps == null ? 0 : ps.jjtGetNumChildren();
+ }
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstVariableSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstVariableSym.java
new file mode 100644
index 0000000000..3dce2dce80
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AbstractAstVariableSym.java
@@ -0,0 +1,31 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+abstract class AbstractAstVariableSym
+ extends AbstractAstBackedSymbol
+ implements JVariableSymbol {
+
+ AbstractAstVariableSym(ASTVariableDeclaratorId node, AstSymFactory factory) {
+ super(node, factory);
+ }
+
+ @Override
+ public boolean isFinal() {
+ return node.isFinal();
+ }
+
+ @Override
+ public String getSimpleName() {
+ return node.getVariableName();
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstClassSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstClassSym.java
new file mode 100644
index 0000000000..11d737c977
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstClassSym.java
@@ -0,0 +1,217 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.ImplicitMemberSymbols;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals;
+
+
+final class AstClassSym
+ extends AbstractAstTParamOwner
+ implements JClassSymbol {
+
+ private final @Nullable JTypeParameterOwnerSymbol enclosing;
+ private final List declaredClasses;
+ private final List declaredMethods;
+ private final List declaredCtors;
+ private final List declaredFields;
+
+ AstClassSym(ASTAnyTypeDeclaration node,
+ AstSymFactory factory,
+ @Nullable JTypeParameterOwnerSymbol enclosing) {
+ super(node, factory);
+ this.enclosing = enclosing;
+
+ // evaluate everything strictly
+ // this populates symbols on the relevant AST nodes
+
+ List myClasses = new ArrayList<>();
+ List myMethods = new ArrayList<>();
+ List myCtors = new ArrayList<>();
+ List myFields = new ArrayList<>();
+
+ if (node instanceof ASTEnumDeclaration) {
+ node.getEnumConstants().forEach(constant -> myFields.add(new AstFieldSym(constant.getVarId(), factory, this)));
+ }
+
+ for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) {
+
+ JavaNode dnode = decl.getDeclarationNode();
+
+ if (dnode instanceof ASTAnyTypeDeclaration) {
+ myClasses.add(new AstClassSym((ASTAnyTypeDeclaration) dnode, factory, this));
+ } else if (dnode instanceof ASTMethodDeclaration) {
+ myMethods.add(new AstMethodSym((ASTMethodDeclaration) dnode, factory, this));
+ } else if (dnode instanceof ASTConstructorDeclaration) {
+ myCtors.add(new AstCtorSym((ASTConstructorDeclaration) dnode, factory, this));
+ } else if (dnode instanceof ASTFieldDeclaration) {
+ for (ASTVariableDeclaratorId varId : ((ASTFieldDeclaration) dnode).getVarIds()) {
+ myFields.add(new AstFieldSym(varId, factory, this));
+ }
+ }
+ }
+
+ if (myCtors.isEmpty() && isClass()) {
+ myCtors.add(ImplicitMemberSymbols.defaultCtor(this));
+ }
+
+ if (this.isEnum()) {
+ myMethods.add(ImplicitMemberSymbols.enumValues(this));
+ myMethods.add(ImplicitMemberSymbols.enumValueOf(this));
+ }
+
+ this.declaredClasses = Collections.unmodifiableList(myClasses);
+ this.declaredMethods = Collections.unmodifiableList(myMethods);
+ this.declaredCtors = Collections.unmodifiableList(myCtors);
+ this.declaredFields = Collections.unmodifiableList(myFields);
+ }
+
+ @Override
+ public @NonNull String getSimpleName() {
+ return node.getSimpleName();
+ }
+
+
+ @Override
+ public @NonNull String getBinaryName() {
+ return node.getBinaryName();
+ }
+
+ @Override
+ public @Nullable String getCanonicalName() {
+ return node.getCanonicalName();
+ }
+
+ @Override
+ public boolean isUnresolved() {
+ return false;
+ }
+
+ @Override
+ public @Nullable JClassSymbol getEnclosingClass() {
+ if (enclosing instanceof JClassSymbol) {
+ return (JClassSymbol) enclosing;
+ } else if (enclosing instanceof JExecutableSymbol) {
+ return enclosing.getEnclosingClass();
+ }
+ assert enclosing == null;
+ return null;
+ }
+
+ @Override
+ public @Nullable JExecutableSymbol getEnclosingMethod() {
+ return enclosing instanceof JExecutableSymbol ? (JExecutableSymbol) enclosing : null;
+ }
+
+ @Override
+ public List getDeclaredClasses() {
+ return declaredClasses;
+ }
+
+ @Override
+ public List getDeclaredMethods() {
+ return declaredMethods;
+ }
+
+ @Override
+ public List getConstructors() {
+ return declaredCtors;
+ }
+
+ @Override
+ public List getDeclaredFields() {
+ return declaredFields;
+ }
+
+
+ @Override
+ public @Nullable JClassSymbol getSuperclass() {
+ if (isEnum()) {
+ return ReflectSymInternals.ENUM_SYM;
+ } else if (node instanceof ASTClassOrInterfaceDeclaration) {
+ // This is TODO, needs symbol table
+ }
+ return null;
+ }
+
+ // those casts only succeed if the program compiles, it relies on
+ // the fact that only classes can be super interfaces, ie not String[]
+ // or some type var
+
+ @Override
+ public List getSuperInterfaces() {
+ // TODO needs symbol table
+ return Collections.emptyList();
+ }
+
+ @Override
+ public @Nullable JTypeDeclSymbol getArrayComponent() {
+ return null;
+ }
+
+ @Override
+ public boolean isArray() {
+ return false;
+ }
+
+ @Override
+ public boolean isPrimitive() {
+ return false;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return node.isInterface();
+ }
+
+ @Override
+ public boolean isEnum() {
+ return node.isEnum();
+ }
+
+ @Override
+ public boolean isAnnotation() {
+ return node.isAnnotation();
+ }
+
+ @Override
+ public boolean isLocalClass() {
+ return node.isLocal();
+ }
+
+ @Override
+ public boolean isAnonymousClass() {
+ return node.isAnonymous();
+ }
+
+ @Override
+ public @Nullable Class> getJvmRepr() {
+ return null;
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstCtorSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstCtorSym.java
new file mode 100644
index 0000000000..07eb879f26
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstCtorSym.java
@@ -0,0 +1,20 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+final class AstCtorSym extends AbstractAstExecSymbol implements JConstructorSymbol {
+
+ AstCtorSym(ASTConstructorDeclaration node, AstSymFactory factory, JClassSymbol owner) {
+ super(node, factory, owner);
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFieldSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFieldSym.java
new file mode 100644
index 0000000000..2cbc025351
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFieldSym.java
@@ -0,0 +1,41 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.ast.JModifier;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
+
+final class AstFieldSym extends AbstractAstVariableSym implements JFieldSymbol {
+
+
+ private final JClassSymbol owner;
+
+ AstFieldSym(ASTVariableDeclaratorId node,
+ AstSymFactory factory,
+ JClassSymbol owner) {
+ super(node, factory);
+ this.owner = owner;
+ }
+
+ @Override
+ public int getModifiers() {
+ return JModifier.toReflect(node.getModifiers().getEffectiveModifiers());
+ }
+
+ @Override
+ public boolean isEnumConstant() {
+ return node.isEnumConstant();
+ }
+
+ @Override
+ public @NonNull JClassSymbol getEnclosingClass() {
+ return owner;
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFormalParamSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFormalParamSym.java
new file mode 100644
index 0000000000..cb32bb0c44
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstFormalParamSym.java
@@ -0,0 +1,28 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+final class AstFormalParamSym extends AbstractAstVariableSym implements JFormalParamSymbol {
+
+ private final AbstractAstExecSymbol> owner;
+
+ AstFormalParamSym(ASTVariableDeclaratorId node, AstSymFactory factory, AbstractAstExecSymbol> owner) {
+ super(node, factory);
+ this.owner = owner;
+ }
+
+ @Override
+ public JExecutableSymbol getDeclaringSymbol() {
+ return owner;
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstLocalVarSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstLocalVarSym.java
new file mode 100644
index 0000000000..768bc96a68
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstLocalVarSym.java
@@ -0,0 +1,28 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+final class AstLocalVarSym extends AbstractAstVariableSym implements JLocalVariableSymbol {
+
+ AstLocalVarSym(ASTVariableDeclaratorId node, AstSymFactory factory) {
+ super(node, factory);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return node.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return node.hashCode();
+ }
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstMethodSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstMethodSym.java
new file mode 100644
index 0000000000..733f9da9d2
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstMethodSym.java
@@ -0,0 +1,28 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
+
+/**
+ * @author Clément Fournier
+ */
+final class AstMethodSym
+ extends AbstractAstExecSymbol
+ implements JMethodSymbol {
+
+
+ AstMethodSym(ASTMethodDeclaration node, AstSymFactory factory, JClassSymbol owner) {
+ super(node, factory, owner);
+ }
+
+ @Override
+ public String getSimpleName() {
+ return node.getName();
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstSymFactory.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstSymFactory.java
new file mode 100644
index 0000000000..35ddd7977b
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstSymFactory.java
@@ -0,0 +1,39 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
+import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
+
+
+public final class AstSymFactory {
+
+ // keep in mind, creating a symbol sets it on the node (see constructor of AbstractAstBackedSymbol)
+
+ /**
+ * Builds, sets and returns the symbol for the given local variable.
+ */
+ public JLocalVariableSymbol setLocalVarSymbol(ASTVariableDeclaratorId id) {
+ assert !id.isField() && !id.isEnumConstant() : "Local var symbol is not appropriate for fields";
+ assert !id.isFormalParameter()
+ || id.isLambdaParameter()
+ || id.isExceptionBlockParameter() : "Local var symbol is not appropriate for method parameters";
+
+ return new AstLocalVarSym(id, this);
+ }
+
+ /**
+ * Builds, sets and returns the symbol for the given class.
+ */
+ public JClassSymbol setClassSymbol(@Nullable JTypeParameterOwnerSymbol enclosing, ASTAnyTypeDeclaration klass) {
+ return new AstClassSym(klass, this, enclosing);
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstTypeParamSym.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstTypeParamSym.java
new file mode 100644
index 0000000000..a17909242b
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/ast/AstTypeParamSym.java
@@ -0,0 +1,43 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.symbols.internal.impl.ast;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
+import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
+
+final class AstTypeParamSym
+ extends AbstractAstBackedSymbol
+ implements JTypeParameterSymbol {
+
+ private final AbstractAstTParamOwner> owner;
+ // private final FreshTypeVar typeVar;
+
+ AstTypeParamSym(ASTTypeParameter node, AstSymFactory factory, AbstractAstTParamOwner> owner) {
+ super(node, factory);
+ this.owner = owner;
+ // this.typeVar = factory.types().newTypeVar(this);
+ }
+
+ @Override
+ public JTypeParameterOwnerSymbol getDeclaringSymbol() {
+ return owner;
+ }
+
+ @Override
+ public @Nullable Class> getJvmRepr() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public String getSimpleName() {
+ return node.getParameterName();
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedExecutableSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedExecutableSymbol.java
index e52fb10483..cab98372b2 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedExecutableSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedExecutableSymbol.java
@@ -52,6 +52,9 @@ abstract class AbstractReflectedExecutableSymbol extends A
public final List getFormalParameters() {
if (params == null) {
this.params = Arrays.stream(reflected.getParameters())
+ // implicit parameters are filtered out
+ // this affects eg params of enum constructors
+ .filter(it -> !it.isImplicit())
.map(p -> new ReflectedMethodParamImpl(this, p))
.collect(Collectors.toList());
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedSymbol.java
index 2176bd6fbc..5f00cc1664 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/AbstractReflectedSymbol.java
@@ -5,6 +5,8 @@
package net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect;
import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolToStrings;
/**
*
@@ -17,4 +19,18 @@ abstract class AbstractReflectedSymbol implements JElementSymbol {
this.symFactory = symFactory;
}
+ @Override
+ public String toString() {
+ return SymbolToStrings.REFLECT.toString(this);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return SymbolEquality.equals(this, o);
+ }
+
+ @Override
+ public int hashCode() {
+ return SymbolEquality.hash(this);
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectSymInternals.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectSymInternals.java
index d619f62619..d745593da3 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectSymInternals.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectSymInternals.java
@@ -4,6 +4,11 @@
package net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolFactory;
@@ -12,7 +17,38 @@ import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolFactory;
*/
public final class ReflectSymInternals {
- private static final ReflectionSymFactory STATIC_FACTORY = new ReflectionSymFactory();
+ public static final ReflectionSymFactory STATIC_FACTORY = new ReflectionSymFactory();
+ // object
+ public static final JClassSymbol OBJECT_SYM = createSharedSym(Object.class);
+ // primitives
+ public static final JClassSymbol BOOLEAN_SYM = createSharedSym(boolean.class);
+ public static final JClassSymbol BYTE_SYM = createSharedSym(byte.class);
+ public static final JClassSymbol CHAR_SYM = createSharedSym(char.class);
+ public static final JClassSymbol DOUBLE_SYM = createSharedSym(double.class);
+ public static final JClassSymbol FLOAT_SYM = createSharedSym(float.class);
+ public static final JClassSymbol INT_SYM = createSharedSym(int.class);
+ public static final JClassSymbol LONG_SYM = createSharedSym(long.class);
+ public static final JClassSymbol SHORT_SYM = createSharedSym(short.class);
+ public static final JClassSymbol VOID_SYM = createSharedSym(void.class);
+ // primitive wrappers
+ public static final JClassSymbol BOXED_BOOLEAN_SYM = createSharedSym(Boolean.class);
+ public static final JClassSymbol BOXED_BYTE_SYM = createSharedSym(Byte.class);
+ public static final JClassSymbol BOXED_CHAR_SYM = createSharedSym(Character.class);
+ public static final JClassSymbol BOXED_DOUBLE_SYM = createSharedSym(Double.class);
+ public static final JClassSymbol BOXED_FLOAT_SYM = createSharedSym(Float.class);
+ public static final JClassSymbol BOXED_INT_SYM = createSharedSym(Integer.class);
+ public static final JClassSymbol BOXED_LONG_SYM = createSharedSym(Long.class);
+ public static final JClassSymbol BOXED_SHORT_SYM = createSharedSym(Short.class);
+ public static final JClassSymbol BOXED_VOID_SYM = createSharedSym(Void.class);
+ // array supertypes
+ public static final JClassSymbol CLONEABLE_SYM = createSharedSym(Cloneable.class);
+ public static final JClassSymbol SERIALIZABLE_SYM = createSharedSym(Serializable.class);
+ public static final List ARRAY_SUPER_INTERFACES = Collections.unmodifiableList(Arrays.asList(CLONEABLE_SYM, SERIALIZABLE_SYM));
+ // other important/common types
+ public static final JClassSymbol CLASS_SYM = createSharedSym(Class.class);
+ public static final JClassSymbol ITERABLE_SYM = createSharedSym(Iterable.class);
+ public static final JClassSymbol ENUM_SYM = createSharedSym(Enum.class);
+ public static final JClassSymbol STRING_SYM = createSharedSym(String.class);
private ReflectSymInternals() {
// util class
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedClassImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedClassImpl.java
index c7b1bd43ec..a0a4ec22d4 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedClassImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedClassImpl.java
@@ -18,8 +18,6 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolFactory;
final class ReflectedClassImpl extends AbstractTypeParamOwnerSymbol> implements JClassSymbol {
@@ -107,7 +105,7 @@ final class ReflectedClassImpl extends AbstractTypeParamOwnerSymbol> im
@Override
public List getSuperInterfaces() {
if (superInterfaces == null) {
- superInterfaces = myClass.isArray() ? SymbolFactory.ARRAY_SUPER_INTERFACES
+ superInterfaces = myClass.isArray() ? ReflectSymInternals.ARRAY_SUPER_INTERFACES
: Arrays.stream(myClass.getInterfaces()).map(symFactory::getClassSymbol).collect(toList());
}
return superInterfaces;
@@ -204,22 +202,6 @@ final class ReflectedClassImpl extends AbstractTypeParamOwnerSymbol> im
return declaredFields;
}
- @Override
- public String toString() {
- return getBinaryName();
- }
-
- @Override
- public boolean equals(Object o) {
- return SymbolEquality.CLASS.equals(this, o);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.CLASS.hash(this);
- }
-
-
static ReflectedClassImpl createWithEnclosing(ReflectionSymFactory symbolFactory,
@Nullable JClassSymbol enclosing,
Class> myClass) {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedCtorImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedCtorImpl.java
index a8f83252e9..02ea37e955 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedCtorImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedCtorImpl.java
@@ -9,7 +9,6 @@ import java.lang.reflect.Constructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
class ReflectedCtorImpl extends AbstractReflectedExecutableSymbol> implements JConstructorSymbol {
@@ -18,13 +17,4 @@ class ReflectedCtorImpl extends AbstractReflectedExecutableSymbol
super(owner, myConstructor);
}
- @Override
- public boolean equals(Object obj) {
- return SymbolEquality.CONSTRUCTOR.equals(this, obj);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.CONSTRUCTOR.hash(this);
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedFieldImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedFieldImpl.java
index 58df439d81..93ccab2168 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedFieldImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedFieldImpl.java
@@ -10,7 +10,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
class ReflectedFieldImpl extends AbstractReflectedSymbol implements JFieldSymbol {
@@ -44,14 +43,4 @@ class ReflectedFieldImpl extends AbstractReflectedSymbol implements JFieldSymbol
return myField.getModifiers();
}
-
- @Override
- public boolean equals(Object o) {
- return SymbolEquality.FIELD.equals(this, o);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.FIELD.hash(this);
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodImpl.java
index e415f9866a..10a0f7cbac 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodImpl.java
@@ -9,7 +9,6 @@ import java.lang.reflect.Method;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
class ReflectedMethodImpl extends AbstractReflectedExecutableSymbol implements JMethodSymbol {
@@ -24,14 +23,4 @@ class ReflectedMethodImpl extends AbstractReflectedExecutableSymbol impl
return reflected.getName();
}
-
- @Override
- public boolean equals(Object o) {
- return SymbolEquality.METHOD.equals(this, o);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.METHOD.hash(this);
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodParamImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodParamImpl.java
index 64c335d27f..2e6d120bd0 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodParamImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedMethodParamImpl.java
@@ -9,7 +9,6 @@ import java.lang.reflect.Parameter;
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
final class ReflectedMethodParamImpl extends AbstractReflectedSymbol implements JFormalParamSymbol {
@@ -38,13 +37,4 @@ final class ReflectedMethodParamImpl extends AbstractReflectedSymbol implements
return reflected.getName();
}
- @Override
- public boolean equals(Object o) {
- return SymbolEquality.FORMAL_PARAM.equals(this, o);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.FORMAL_PARAM.hash(this);
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedTypeParamImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedTypeParamImpl.java
index 1eae5f6789..375c21400d 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedTypeParamImpl.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectedTypeParamImpl.java
@@ -11,7 +11,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolEquality;
@SuppressWarnings("PMD")
// yeah this looks weird for now
@@ -47,13 +46,4 @@ class ReflectedTypeParamImpl implements JTypeParameterSymbol {
return name;
}
- @Override
- public boolean equals(Object o) {
- return SymbolEquality.TYPE_PARAM.equals(this, o);
- }
-
- @Override
- public int hashCode() {
- return SymbolEquality.TYPE_PARAM.hash(this);
- }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectionSymFactory.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectionSymFactory.java
index 7402fdd362..a92b339fe3 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectionSymFactory.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/impl/reflect/ReflectionSymFactory.java
@@ -5,6 +5,30 @@
package net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOOLEAN_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_BOOLEAN_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_BYTE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_CHAR_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_DOUBLE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_FLOAT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_INT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_LONG_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_SHORT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BOXED_VOID_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.BYTE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.CHAR_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.CLONEABLE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.DOUBLE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.ENUM_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.FLOAT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.INT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.ITERABLE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.LONG_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.OBJECT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.SERIALIZABLE_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.SHORT_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.STRING_SYM;
+import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.VOID_SYM;
import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectedClassImpl.createOuterClass;
import static net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectedClassImpl.createWithEnclosing;
@@ -31,7 +55,6 @@ public final class ReflectionSymFactory implements SymbolFactory> {
*/
private static Map, JClassSymbol> commonSymbols;
-
@Override
@Nullable
public JClassSymbol getClassSymbol(@Nullable Class> klass) {
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/EmptySymbolTable.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/EmptySymbolTable.java
index ddadc2a962..b1512fcf5f 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/EmptySymbolTable.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/EmptySymbolTable.java
@@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.java.symbols.table.internal;
import java.util.stream.Stream;
-import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
@@ -37,13 +37,13 @@ final class EmptySymbolTable implements JSymbolTable {
@Override
- public @NonNull ResolveResult resolveTypeName(String simpleName) {
+ public @Nullable ResolveResult resolveTypeName(String simpleName) {
return ResolveResultImpl.failed();
}
@Override
- public @NonNull ResolveResult resolveValueName(String simpleName) {
+ public @Nullable ResolveResult resolveValueName(String simpleName) {
return ResolveResultImpl.failed();
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SamePackageSymbolTable.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SamePackageSymbolTable.java
index d4ce8bf05c..d8b05474b6 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SamePackageSymbolTable.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SamePackageSymbolTable.java
@@ -4,9 +4,12 @@
package net.sourceforge.pmd.lang.java.symbols.table.internal;
+import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
+import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
@@ -22,11 +25,12 @@ import net.sourceforge.pmd.lang.java.symbols.table.internal.ResolveResultImpl.Cl
*/
final class SamePackageSymbolTable extends AbstractSymbolTable {
- private final @Nullable ASTPackageDeclaration packageDeclaration;
+ private final @NonNull JavaNode contributor;
- SamePackageSymbolTable(JSymbolTable parent, SymbolTableHelper helper, @Nullable ASTPackageDeclaration packageDeclaration) {
+ SamePackageSymbolTable(JSymbolTable parent, SymbolTableHelper helper, ASTCompilationUnit acu) {
super(parent, helper);
- this.packageDeclaration = packageDeclaration;
+ ASTPackageDeclaration pdecl = acu.getPackageDeclaration();
+ this.contributor = pdecl == null ? acu : pdecl;
}
@@ -38,6 +42,6 @@ final class SamePackageSymbolTable extends AbstractSymbolTable {
// or if the type was never in this package in the first place
JClassSymbol jClassSymbol = loadClassIgnoreFailure(helper.prependPackageName(simpleName));
return jClassSymbol == null ? null
- : new ClassResolveResult(jClassSymbol, this, packageDeclaration);
+ : new ClassResolveResult(jClassSymbol, this, contributor);
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java
index c648982f36..c571dae134 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java
@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTModifierList;
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.ast.SideEffectingVisitorAdapter;
@@ -61,6 +62,7 @@ public final class SymbolTableResolver {
: "Unbalanced stack push/pop! Top is " + myStackTop;
}
+
/**
* Create a new symbol table using {@link TableLinker#createAndLink(JSymbolTable, SymbolTableHelper, Object)},
* linking it to the top of the stack as its parent.
@@ -98,7 +100,6 @@ public final class SymbolTableResolver {
return this.myStackTop;
}
-
@FunctionalInterface
private interface TableLinker {
@@ -120,6 +121,10 @@ public final class SymbolTableResolver {
// The parameter on the visit methods is unnecessary
// TODO introduce another visitor with `void visit(Node);` signature
+ @Override
+ public void visit(ASTModifierList node, Void data) {
+ // do nothing
+ }
@Override
public void visit(ASTCompilationUnit node, Void data) {
@@ -129,7 +134,7 @@ public final class SymbolTableResolver {
int pushed = 0;
pushed += pushOnStack(ImportOnDemandSymbolTable::new, isImportOnDemand.get(true));
pushed += pushOnStack(JavaLangSymbolTable::new, node);
- pushed += pushOnStack(SamePackageSymbolTable::new, node.getPackageDeclaration());
+ pushed += pushOnStack(SamePackageSymbolTable::new, node);
pushed += pushOnStack(SingleImportSymbolTable::new, isImportOnDemand.get(false));
// types declared inside the compilation unit
// pushed += pushOnStack(MemberTypeSymTable::new, node);
@@ -140,8 +145,12 @@ public final class SymbolTableResolver {
}
- private void setTopSymbolTableAndRecurse(JavaNode node) {
+ private void setTopSymbolTable(JavaNode node) {
InternalApiBridge.setSymbolTable(node, peekStack());
+ }
+
+ private void setTopSymbolTableAndRecurse(JavaNode node) {
+ setTopSymbolTable(node);
for (JavaNode child : node.children()) {
child.jjtAccept(this, null);
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/package-info.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/package-info.java
index 18ea325008..799e501bce 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/package-info.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/package-info.java
@@ -21,7 +21,7 @@
* and static method or field names imported from a type by a static-import-on-demand;
* {@link net.sourceforge.pmd.lang.java.symbols.table.internal.JavaLangSymbolTable}: Top-level types implicitly imported from {@code java.lang};
* {@link net.sourceforge.pmd.lang.java.symbols.table.internal.SamePackageSymbolTable}: Top-level types from the same package, which are implicitly imported
- * {@link net.sourceforge.pmd.lang.java.symbols.table.internal.SingleImportSymbolTable}: types imported by single-type-imports, and static methods and
+ * {@link net.sourceforge.pmd.lang.java.symbols.table.internal.SingleImportSymbolTable}: Types imported by single-type-imports, and static methods and
* fields imported by a single-static-import.
*
* These dominate the whole compilation unit and thus are all linked to the {@link net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit}.
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java
index e9b67a934d..d72065a677 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java
@@ -7,6 +7,8 @@ package net.sourceforge.pmd.lang.java;
import java.util.ArrayList;
import java.util.List;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
@@ -23,6 +25,7 @@ public class JavaParsingHelper extends BaseParsingHelper {
+ child {
it::getAnnotationName shouldBe "F"
it::getSimpleName shouldBe "F"
+
+ it::getMemberList shouldBe null
}
}
"@java.lang.Override" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "java.lang.Override"
it::getSimpleName shouldBe "Override"
+
+ it::getMemberList shouldBe null
}
}
}
@@ -51,45 +55,63 @@ class ASTAnnotationTest : ParserTestSpec({
inContext(AnnotationParsingCtx) {
"@F(\"ohio\")" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "F"
it::getSimpleName shouldBe "F"
- it::getMemberValue shouldBe stringLit("\"ohio\"")
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ stringLit("\"ohio\"")
+ }
+ }
}
}
"@org.F({java.lang.Math.PI})" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "org.F"
it::getSimpleName shouldBe "F"
- it::getMemberValue shouldBe child {
- child {
- it::getFieldName shouldBe "PI"
- ambiguousName("java.lang.Math")
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ child {
+ child {
+ it::getFieldName shouldBe "PI"
+ ambiguousName("java.lang.Math")
+ }
+ }
}
}
}
}
"@org.F({@Aha, @Oh})" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "org.F"
it::getSimpleName shouldBe "F"
- it::getMemberValue shouldBe child {
- annotation("Aha")
- annotation("Oh")
+
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ child {
+ annotation("Aha")
+ annotation("Oh")
+ }
+ }
}
}
}
"@org.F(@Oh)" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "org.F"
it::getSimpleName shouldBe "F"
- it::getMemberValue shouldBe annotation("Oh")
+
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ annotation("Oh")
+ }
+ }
}
}
}
@@ -101,44 +123,37 @@ class ASTAnnotationTest : ParserTestSpec({
inContext(AnnotationParsingCtx) {
"@F(a=\"ohio\")" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "F"
it::getSimpleName shouldBe "F"
- memberValuePair("a") {
- stringLit("\"ohio\"")
+
+ it::getMemberList shouldBe child {
+ memberValuePair("a") {
+ stringLit("\"ohio\"")
+ }
}
}
}
"@org.F(a={java.lang.Math.PI}, b=2)" should parseAs {
- child {
+ child {
it::getAnnotationName shouldBe "org.F"
it::getSimpleName shouldBe "F"
- memberValuePair("a") {
- child {
- child {
- it::getFieldName shouldBe "PI"
- ambiguousName("java.lang.Math")
+
+ it::getMemberList shouldBe child {
+ memberValuePair("a") {
+ child {
+ fieldAccess("PI") {
+ ambiguousName("java.lang.Math")
+ }
}
}
- }
- memberValuePair("b") {
- number()
- }
- }
- }
-
- "@org.F({@Aha, @Oh})" should parseAs {
- child {
- it::getAnnotationName shouldBe "org.F"
- it::getSimpleName shouldBe "F"
-
- it::getMemberValue shouldBe child {
- annotation("Aha")
- annotation("Oh")
+ memberValuePair("b") {
+ number()
+ }
}
}
}
@@ -146,28 +161,45 @@ class ASTAnnotationTest : ParserTestSpec({
"""
@TestAnnotation({@SuppressWarnings({}),
- @SuppressWarnings({"Beware the ides of March.",}),
+ @SuppressWarnings(value = {"Beware the ides of March.",}),
@SuppressWarnings({"Look both ways", "Before Crossing",}), })
""" should parseAs {
- child {
+ child {
- it::getMemberValue shouldBe child {
- child {
+ it::getMemberList shouldBe child {
- it::getMemberValue shouldBe child {}
- }
- child {
+ shorthandMemberValue {
- it::getMemberValue shouldBe child {
- stringLit("\"Beware the ides of March.\"")
- }
- }
- child {
+ child {
+ annotation {
- it::getMemberValue shouldBe child {
- stringLit("\"Look both ways\"")
- stringLit("\"Before Crossing\"")
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ child {}
+ }
+ }
+ }
+ annotation {
+ it::getMemberList shouldBe child {
+ memberValuePair("value") {
+ it::isShorthand shouldBe false
+ child {
+ stringLit("\"Beware the ides of March.\"")
+ }
+ }
+ }
+ }
+ annotation {
+ it::getMemberList shouldBe child {
+ shorthandMemberValue {
+ child {
+ stringLit("\"Look both ways\"")
+ stringLit("\"Before Crossing\"")
+ }
+ }
+ }
+ }
}
}
}
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt
index f347079cc6..a67e981a01 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTArrayTypeTest.kt
@@ -36,7 +36,7 @@ class ASTArrayTypeTest : ParserTestSpec({
arrayType {
it::getElementType shouldBe classType("ArrayTypes")
- it::getDeclaredAnnotations shouldBe fromChild> {
+ it::declaredAnnotationsList shouldBe fromChild> {
arrayDim { }
arrayDim { }
@@ -44,7 +44,7 @@ class ASTArrayTypeTest : ParserTestSpec({
val lst = listOf(annotation("A"))
- it::getDeclaredAnnotations shouldBe lst
+ it::declaredAnnotationsList shouldBe lst
lst
}
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt
index d2f47d13d3..b6e12c936f 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTCastExpressionTest.kt
@@ -56,11 +56,11 @@ class ASTCastExpressionTest : ParserTestSpec({
castExpr {
it::getCastType shouldBe child {
- it::getDeclaredAnnotations shouldBe emptyList()
+ it::declaredAnnotationsList shouldBe emptyList()
classType("Foo") {
// annotations nest on the inner node
- it::getDeclaredAnnotations shouldBe listOf(annotation("F"))
+ it::declaredAnnotationsList shouldBe listOf(annotation("F"))
}
classType("Bar")
@@ -76,15 +76,15 @@ class ASTCastExpressionTest : ParserTestSpec({
castExpr {
it::getCastType shouldBe child {
- it::getDeclaredAnnotations shouldBe emptyList()
+ it::declaredAnnotationsList shouldBe emptyList()
classType("Foo") {
// annotations nest on the inner node
- it::getDeclaredAnnotations shouldBe listOf(annotation("F"))
+ it::declaredAnnotationsList shouldBe listOf(annotation("F"))
}
classType("Bar") {
- it::getDeclaredAnnotations shouldBe listOf(annotation("B"), annotation("C"))
+ it::declaredAnnotationsList shouldBe listOf(annotation("B"), annotation("C"))
}
}
@@ -140,3 +140,6 @@ class ASTCastExpressionTest : ParserTestSpec({
})
+
+val Annotatable.declaredAnnotationsList: List
+ get() = declaredAnnotations.toList()
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt
index 7d3f766039..018b289557 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclarationTest.kt
@@ -4,6 +4,7 @@
package net.sourceforge.pmd.lang.java.ast
+import io.kotlintest.shouldBe
import net.sourceforge.pmd.lang.ast.test.shouldBe
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType
@@ -52,7 +53,7 @@ class ASTConstructorDeclarationTest : ParserTestSpec({
}
}
- it::toList shouldBe listOf(
+ it.toList() shouldBe listOf(
child {
localVarModifiers { }
primitiveType(PrimitiveType.INT)
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
index 0f13861daf..2fbab99481 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTEnumConstantTest.kt
@@ -168,7 +168,7 @@ class ASTEnumConstantTest : ParserTestSpec({
val c = it
it::getModifiers shouldBe modifiers {
- c::getDeclaredAnnotations shouldBe listOf(annotation("C"))
+ c::declaredAnnotationsList shouldBe listOf(annotation("C"))
}
@@ -184,7 +184,7 @@ class ASTEnumConstantTest : ParserTestSpec({
val c = it
it::getModifiers shouldBe modifiers {
- c::getDeclaredAnnotations shouldBe listOf(annotation("A"), annotation("a"))
+ c::declaredAnnotationsList shouldBe listOf(annotation("A"), annotation("a"))
}
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt
index c2f6373742..6b6786b3d7 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarationTest.kt
@@ -1,6 +1,7 @@
package net.sourceforge.pmd.lang.java.ast
import io.kotlintest.should
+import io.kotlintest.shouldBe
import io.kotlintest.shouldNot
import net.sourceforge.pmd.lang.ast.test.shouldBe
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType.PrimitiveType
@@ -399,7 +400,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({
it::getResultType shouldBe voidResult()
it::getFormalParameters shouldBe formalsList(0) {
- it::toList shouldBe emptyList()
+ it.toList() shouldBe emptyList()
it::getReceiverParameter shouldBe child {
classType("Foo") {
@@ -434,7 +435,7 @@ class ASTMethodDeclarationTest : ParserTestSpec({
}
}
- it::toList shouldBe listOf(
+ it.toList() shouldBe listOf(
child {
localVarModifiers { }
primitiveType(PrimitiveType.INT)
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParserTestSpec.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParserTestSpec.kt
index d3b80fb0fb..e10e474da1 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParserTestSpec.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ParserTestSpec.kt
@@ -125,6 +125,13 @@ abstract class ParserTestSpec(body: ParserTestSpec.() -> Unit) : AbstractSpec(),
inner class VersionedTestCtx(private val context: TestContext, javaVersion: JavaVersion) : ParserTestCtx(javaVersion) {
+
+ fun doTest(name: String, assertions: VersionedTestCtx.() -> Unit) {
+ containedParserTestImpl(context, name, javaVersion = javaVersion) {
+ assertions()
+ }
+ }
+
infix fun String.should(matcher: Assertions) {
containedParserTestImpl(context, "'$this'", javaVersion = javaVersion) {
this@should kotlintestShould matcher
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
index 324448d9b5..016fbeecb9 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt
@@ -485,8 +485,14 @@ fun TreeNodeWrapper.ambiguousName(image: String, contents: NodeSpec.memberValuePair(name: String, contents: ValuedNodeSpec) =
child {
- it::getMemberName shouldBe name
- it::getMemberValue shouldBe contents()
+ it::getName shouldBe name
+ it::getValue shouldBe contents()
+ }
+
+fun TreeNodeWrapper.shorthandMemberValue(contents: ValuedNodeSpec) =
+ memberValuePair("value") {
+ it::isShorthand shouldBe true
+ contents()
}
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/ArraySymbolTests.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/ArraySymbolTests.kt
index 88b29c7d9d..3ca2ac404b 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/ArraySymbolTests.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/ArraySymbolTests.kt
@@ -8,8 +8,7 @@ import net.sourceforge.pmd.lang.java.ast.JavaNode
import net.sourceforge.pmd.lang.java.symbols.JAccessibleElementSymbol.PRIMITIVE_PACKAGE
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolFactory.INT_SYM
-import net.sourceforge.pmd.lang.java.symbols.internal.impl.SymbolFactory.STRING_SYM
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals.*
/**
* @author Clément Fournier
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/AstSymbolTests.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/AstSymbolTests.kt
new file mode 100644
index 0000000000..48ef837a64
--- /dev/null
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/AstSymbolTests.kt
@@ -0,0 +1,409 @@
+package net.sourceforge.pmd.lang.java.symbols.internal
+
+import io.kotlintest.matchers.collections.shouldBeEmpty
+import io.kotlintest.matchers.collections.shouldHaveSize
+import io.kotlintest.shouldBe
+import net.sourceforge.pmd.lang.ast.test.*
+import net.sourceforge.pmd.lang.ast.test.shouldBe
+import net.sourceforge.pmd.lang.java.ast.*
+import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol
+import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol
+import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol
+import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol
+import net.sourceforge.pmd.lang.java.symbols.internal.impl.reflect.ReflectSymInternals
+import java.lang.reflect.Modifier
+
+/**
+ * @author Clément Fournier
+ * @since 7.0.0
+ */
+class AstSymbolTests : ParserTestSpec({
+
+ parserTest("Parsed class symbols") {
+
+ val acu = parser.withProcessing().parse("""
+
+ package com.foo;
+
+ public final class Foo extends java.util.List {
+
+ void bar() {
+
+ }
+
+ private void ohio() {
+
+ }
+
+ private interface Inner {}
+
+
+ enum EE {
+ A,
+ B
+ }
+ }
+ """)
+
+ val (fooClass, innerItf, innerEnum) = acu.descendants(ASTAnyTypeDeclaration::class.java).toList { it.symbol }
+
+ val (barM, ohioM) = acu.descendants(ASTMethodDeclaration::class.java).toList { it.symbol }
+
+
+
+ doTest("should reflect their modifiers") {
+ fooClass::getModifiers shouldBe (Modifier.PUBLIC or Modifier.FINAL)
+ innerItf::getModifiers shouldBe (Modifier.PRIVATE or Modifier.ABSTRACT or Modifier.STATIC)
+ innerEnum::getModifiers shouldBe (Modifier.FINAL or Modifier.STATIC)
+ }
+
+ doTest("should reflect their simple names properly") {
+ fooClass::getSimpleName shouldBe "Foo"
+ innerItf::getSimpleName shouldBe "Inner"
+ innerEnum::getSimpleName shouldBe "EE"
+ }
+
+ doTest("should reflect their canonical names properly") {
+ fooClass::getCanonicalName shouldBe "com.foo.Foo"
+ innerItf::getCanonicalName shouldBe "com.foo.Foo.Inner"
+ innerEnum::getCanonicalName shouldBe "com.foo.Foo.EE"
+ }
+
+ doTest("should reflect their methods") {
+ fooClass.declaredMethods shouldBe listOf(barM, ohioM)
+ }
+
+ doTest("should fetch their methods properly") {
+ fooClass.getDeclaredMethods("ohio") shouldBe listOf(ohioM)
+ }
+
+ doTest("should reflect their super class") {
+ // Postponed
+ // fooClass::getSuperclass shouldBe testSymFactory.getClassSymbol(java.util.List::class.java)
+
+ innerEnum::getSuperclass shouldBe ReflectSymInternals.ENUM_SYM
+ }
+
+ doTest("should reflect their member types") {
+ fooClass.declaredClasses shouldBe listOf(innerItf, innerEnum)
+ innerEnum.declaredClasses shouldBe emptyList()
+ innerItf.declaredClasses shouldBe emptyList()
+ }
+
+ doTest("should reflect their declaring type") {
+ fooClass::getEnclosingClass shouldBe null
+ innerEnum::getEnclosingClass shouldBe fooClass
+ innerItf::getEnclosingClass shouldBe fooClass
+ }
+
+ doTest("(enums) should reflect enum constants as fields") {
+ val constants =
+ acu.descendants(ASTEnumDeclaration::class.java)
+ .take(1)
+ .flatMap { it.enumConstants }
+ .toList { it.varId.symbol as JFieldSymbol }
+
+ constants.shouldHaveSize(2)
+
+ innerEnum.declaredFields.shouldBe(constants)
+
+ constants.forEach {
+ it::isEnumConstant shouldBe true
+ it::getModifiers shouldBe (Modifier.PUBLIC or Modifier.STATIC or Modifier.FINAL)
+ }
+ }
+ }
+
+
+ parserTest("Default/implicit constructors") {
+
+ val acu = parser.withProcessing().parse("""
+
+ package com.foo;
+
+ public final class Foo extends java.util.List {
+
+ private interface Inner {}
+ private @interface Annot {}
+
+
+ enum EE { A, B }
+ enum E2 {
+ A, B;
+ E2(String s) {}
+ }
+
+ class BClass {
+ protected BClass() { }
+ }
+ class CClass {
+ // default, package private
+ }
+ }
+ """)
+
+ val (fooClass, innerItf, innerAnnot, e1, e2, bClass, cClass) =
+ acu.descendants(ASTAnyTypeDeclaration::class.java).toList { it.symbol }
+
+ doTest("Annotations/itfs should have no constructors") {
+ innerItf.constructors.shouldBeEmpty()
+ innerAnnot.constructors.shouldBeEmpty()
+ }
+
+ doTest("Classes should have a default constructor if there are none") {
+ fooClass.constructors[0].shouldBeA