Remove old symbol table
This commit is contained in:
50 files changed
+158
-5180
No files matched your search
@@ -9,13 +9,11 @@ import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.ast.AstInfo;
|
||||
import net.sourceforge.pmd.lang.ast.NodeStream;
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
|
||||
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeSystem;
|
||||
import net.sourceforge.pmd.lang.java.types.ast.LazyTypeResolver;
|
||||
|
||||
@@ -90,13 +88,6 @@ public final class ASTCompilationUnit extends AbstractJavaTypeNode implements Ja
|
||||
return children(ASTAnyTypeDeclaration.class);
|
||||
}
|
||||
|
||||
|
||||
@InternalApi
|
||||
@Deprecated
|
||||
public ClassTypeResolver getClassTypeResolver() {
|
||||
return new ClassTypeResolver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull JSymbolTable getSymbolTable() {
|
||||
assert symbolTable != null : "Symbol table wasn't set";
|
||||
|
||||
@@ -14,8 +14,8 @@ import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute;
|
||||
* Represents a field declaration in the body of a type declaration.
|
||||
*
|
||||
* <p>This declaration may define several variables, possibly of different
|
||||
* types (see {@link ASTVariableDeclaratorId#getType()}). The nodes
|
||||
* corresponding to the declared variables are accessible through {@link #iterator()}.
|
||||
* types. The nodes corresponding to the declared variables are accessible
|
||||
* through {@link #iterator()}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
|
||||
@@ -6,8 +6,6 @@ package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
|
||||
import net.sourceforge.pmd.lang.java.types.JPrimitiveType;
|
||||
import net.sourceforge.pmd.lang.java.types.JPrimitiveType.PrimitiveTypeKind;
|
||||
|
||||
@@ -25,17 +23,6 @@ public final class ASTPrimitiveType extends AbstractJavaTypeNode implements ASTT
|
||||
|
||||
private PrimitiveTypeKind kind;
|
||||
|
||||
/**
|
||||
* @deprecated Made public for one shady usage in {@link ClassScope}
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public ASTPrimitiveType(PrimitiveTypeKind type) {
|
||||
super(JavaParserImplTreeConstants.JJTPRIMITIVETYPE);
|
||||
setKind(type);
|
||||
}
|
||||
|
||||
|
||||
ASTPrimitiveType(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
+3
-34
@@ -11,13 +11,10 @@ import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
@@ -33,13 +30,9 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
* <li> Resource declarations occurring in try-with-resources statements.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Since this node conventionally represents the declared variable in PMD, our symbol table
|
||||
* populates it with a {@link VariableNameDeclaration}, and its usages can be accessed through
|
||||
* the method {@link #getUsages()}.
|
||||
*
|
||||
* <p>Type resolution assigns the type of the variable to this node. See {@link #getType()}'s
|
||||
* documentation for the contract of this method.
|
||||
*
|
||||
* <p>Since this node conventionally represents the declared variable in PMD,
|
||||
* it owns a {@link JVariableSymbol} and can provide access to
|
||||
* {@linkplain #getLocalUsages() variable usages}.
|
||||
*
|
||||
* <pre class="grammar">
|
||||
*
|
||||
@@ -51,8 +44,6 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
// @formatter:on
|
||||
public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator<JVariableSymbol> implements AccessNode, SymbolDeclaratorNode, FinalizableNode {
|
||||
|
||||
private VariableNameDeclaration nameDeclaration;
|
||||
|
||||
private List<ASTNamedReferenceExpr> usages = Collections.emptyList();
|
||||
|
||||
ASTVariableDeclaratorId(int id) {
|
||||
@@ -64,28 +55,6 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this might be <code>null</code> in certain cases.
|
||||
*/
|
||||
public VariableNameDeclaration getNameDeclaration() {
|
||||
return nameDeclaration;
|
||||
}
|
||||
|
||||
@InternalApi
|
||||
@Deprecated
|
||||
public void setNameDeclaration(VariableNameDeclaration decl) {
|
||||
nameDeclaration = decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated transitional, use {@link #getLocalUsages()}
|
||||
*/
|
||||
@Deprecated
|
||||
public List<NameOccurrence> getUsages() {
|
||||
return getScope().getDeclarations(VariableNameDeclaration.class)
|
||||
.getOrDefault(nameDeclaration, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of the usages of this variable that
|
||||
* are made in this file. Note that for a record component, this returns
|
||||
|
||||
@@ -12,11 +12,9 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.AbstractJjtreeNode;
|
||||
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
|
||||
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeSystem;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
abstract class AbstractJavaNode extends AbstractJjtreeNode<AbstractJavaNode, JavaNode> implements JavaNode {
|
||||
|
||||
private Scope scope;
|
||||
protected JSymbolTable symbolTable;
|
||||
private ASTCompilationUnit root;
|
||||
|
||||
@@ -97,8 +95,7 @@ abstract class AbstractJavaNode extends AbstractJjtreeNode<AbstractJavaNode, Jav
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public JSymbolTable getSymbolTable() {
|
||||
public @NonNull JSymbolTable getSymbolTable() {
|
||||
if (symbolTable == null) {
|
||||
return getParent().getSymbolTable();
|
||||
}
|
||||
@@ -110,22 +107,10 @@ abstract class AbstractJavaNode extends AbstractJjtreeNode<AbstractJavaNode, Jav
|
||||
return getRoot().getTypeSystem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope getScope() {
|
||||
if (scope == null && getParent() != null) {
|
||||
return getParent().getScope();
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
void setScope(Scope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ASTCompilationUnit getRoot() {
|
||||
public @NonNull ASTCompilationUnit getRoot() {
|
||||
// storing a reference on each node ensures that each path is roamed
|
||||
// at most once.
|
||||
if (root == null) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
|
||||
import net.sourceforge.pmd.lang.java.symbols.table.internal.ReferenceCtx;
|
||||
import net.sourceforge.pmd.lang.java.types.JMethodSig;
|
||||
import net.sourceforge.pmd.lang.java.types.JPrimitiveType.PrimitiveTypeKind;
|
||||
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
|
||||
import net.sourceforge.pmd.lang.java.types.JVariableSig;
|
||||
import net.sourceforge.pmd.lang.java.types.JVariableSig.FieldSig;
|
||||
@@ -34,7 +33,6 @@ import net.sourceforge.pmd.lang.java.types.ast.ExprContext;
|
||||
import net.sourceforge.pmd.lang.java.types.ast.LazyTypeResolver;
|
||||
import net.sourceforge.pmd.lang.java.types.internal.infer.Infer;
|
||||
import net.sourceforge.pmd.lang.java.types.internal.infer.TypeInferenceLogger;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
/**
|
||||
* Acts as a bridge between outer parts of PMD and the restricted access
|
||||
@@ -62,48 +60,6 @@ public final class InternalApiBridge {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a fake method name declaration for built-in methods from Java
|
||||
* like the Enum Method "valueOf".
|
||||
*
|
||||
* @param methodName the method name
|
||||
* @param parameterTypes the reference types of each parameter of the method
|
||||
*
|
||||
* @return a method name declaration
|
||||
*/
|
||||
public static ASTMethodDeclaration createBuiltInMethodDeclaration(final String methodName, final String... parameterTypes) {
|
||||
ASTMethodDeclaration methodDeclaration = new ASTMethodDeclaration(0);
|
||||
// InternalApiBridge.setModifier(methodDeclaration, JModifier.PUBLIC);
|
||||
|
||||
methodDeclaration.setImage(methodName);
|
||||
|
||||
ASTFormalParameters formalParameters = new ASTFormalParameters(0);
|
||||
methodDeclaration.addChild(formalParameters, 0);
|
||||
|
||||
/*
|
||||
* jjtAddChild resizes it's child node list according to known indexes.
|
||||
* Going backwards makes sure the first time it gets the right size avoiding copies.
|
||||
*/
|
||||
for (int i = parameterTypes.length - 1; i >= 0; i--) {
|
||||
ASTFormalParameter formalParameter = new ASTFormalParameter(0);
|
||||
formalParameters.addChild(formalParameter, i);
|
||||
|
||||
ASTVariableDeclaratorId variableDeclaratorId = new ASTVariableDeclaratorId(0);
|
||||
variableDeclaratorId.setImage("arg" + i);
|
||||
formalParameter.addChild(variableDeclaratorId, 1);
|
||||
|
||||
PrimitiveTypeKind primitive = PrimitiveTypeKind.fromName(parameterTypes[i]);
|
||||
// TODO : this could actually be a primitive array...
|
||||
AbstractJavaNode type = primitive != null
|
||||
? new ASTPrimitiveType(primitive)
|
||||
: new ASTClassOrInterfaceType(parameterTypes[i]);
|
||||
|
||||
formalParameter.addChild(type, 0);
|
||||
}
|
||||
|
||||
return methodDeclaration;
|
||||
}
|
||||
|
||||
public static JavaccTokenDocument javaTokenDoc(String fullText) {
|
||||
return new JavaTokenDocument(fullText);
|
||||
}
|
||||
@@ -216,10 +172,6 @@ public final class InternalApiBridge {
|
||||
((AbstractJavaNode) node).setSymbolTable(table);
|
||||
}
|
||||
|
||||
public static void setScope(JavaNode node, Scope scope) {
|
||||
((AbstractJavaNode) node).setScope(scope);
|
||||
}
|
||||
|
||||
public static void setQname(ASTAnyTypeDeclaration declaration, String binaryName, @Nullable String canon) {
|
||||
((AbstractAnyTypeDeclaration) declaration).setBinaryName(binaryName, canon);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,12 @@ import net.sourceforge.pmd.lang.ast.AstVisitor;
|
||||
import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeNode;
|
||||
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeSystem;
|
||||
import net.sourceforge.pmd.lang.symboltable.ScopedNode;
|
||||
|
||||
|
||||
/**
|
||||
* Root interface for all Nodes of the Java AST.
|
||||
*/
|
||||
public interface JavaNode extends JjtreeNode<JavaNode>, ScopedNode {
|
||||
public interface JavaNode extends JjtreeNode<JavaNode> {
|
||||
|
||||
/**
|
||||
* Calls back the visitor's visit method corresponding to the runtime type of this Node.
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast.internal;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
|
||||
|
||||
/**
|
||||
* Helper class to analyze {@link ASTImportDeclaration}s.
|
||||
*/
|
||||
public final class ImportWrapper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ImportWrapper.class);
|
||||
|
||||
private final ASTImportDeclaration node;
|
||||
private final String name;
|
||||
private final String fullname;
|
||||
private final Set<String> allStaticDemands;
|
||||
|
||||
public ImportWrapper(ASTImportDeclaration node) {
|
||||
this.node = node;
|
||||
this.fullname = node.getImportedName();
|
||||
this.name = node.getImportedSimpleName();
|
||||
this.allStaticDemands = collectStaticFieldsAndMethods(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
*/
|
||||
private Set<String> collectStaticFieldsAndMethods(ASTImportDeclaration node) {
|
||||
if (!isStaticOnDemand() || node == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// This was edited during the grammar updating process, because
|
||||
// ImportDeclaration is not a TypeNode anymore, and there is no Name anymore.
|
||||
// If tests are failing, refer to the history of this file to get the
|
||||
// previously working version.
|
||||
Class<?> type = null;
|
||||
if (node != null) {
|
||||
type = node.getRoot().getClassTypeResolver().loadClassOrNull(node.getImportedName());
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
try {
|
||||
Set<String> names = new HashSet<>();
|
||||
while (type != null) {
|
||||
// consider static fields, public and non-public
|
||||
for (Field f : type.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(f.getModifiers())) {
|
||||
names.add(f.getName());
|
||||
}
|
||||
}
|
||||
// and methods, too
|
||||
for (Method m : type.getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(m.getModifiers())) {
|
||||
names.add(m.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// consider statics of super classes as well
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
return names;
|
||||
} catch (LinkageError e) {
|
||||
// This is an incomplete classpath, report the missing class
|
||||
LOG.debug("Possible incomplete auxclasspath: Error while processing imports", e);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean matches(String fullName, String name) {
|
||||
if (isStaticOnDemand()) {
|
||||
if (allStaticDemands.contains(fullName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.name == null && name == null) {
|
||||
return fullName.equals(fullname);
|
||||
}
|
||||
return name.equals(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ImportWrapper that = (ImportWrapper) o;
|
||||
return Objects.equals(node.isStatic(), that.node.isStatic())
|
||||
&& Objects.equals(isOnDemand(), that.isOnDemand())
|
||||
&& Objects.equals(node.getImportedName(), that.node.getImportedName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(node.isStatic(), node.isImportOnDemand(), node.getImportedName());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return node.getPackageName();
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullname;
|
||||
}
|
||||
|
||||
public ASTImportDeclaration getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public boolean isStaticOnDemand() {
|
||||
return node.isStatic() && node.isImportOnDemand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Import[name=" + name + ",fullname=" + fullname + ",static*=" + isStaticOnDemand() + ']';
|
||||
}
|
||||
|
||||
public boolean isOnDemand() {
|
||||
return node.isImportOnDemand();
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.symboltable.AbstractScope;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
/**
|
||||
* Provides the basic java scope implementation.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3">JLS 6.3</a>
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public abstract class AbstractJavaScope extends AbstractScope {
|
||||
|
||||
@Override
|
||||
public void addDeclaration(NameDeclaration declaration) {
|
||||
checkForDuplicatedNameDeclaration(declaration);
|
||||
super.addDeclaration(declaration);
|
||||
}
|
||||
|
||||
protected void checkForDuplicatedNameDeclaration(NameDeclaration declaration) {
|
||||
if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) {
|
||||
// don't throw anymore
|
||||
// Scopes will be removed before 7.0, and this sometimes triggers for no reason
|
||||
// because Scopes were not ported to the newer grammar
|
||||
// throw new RuntimeException(declaration + " is already in the symbol table");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(NameOccurrence occurrence) {
|
||||
return !findVariableHere((JavaNameOccurrence) occurrence).isEmpty();
|
||||
}
|
||||
|
||||
protected abstract Set<NameDeclaration> findVariableHere(JavaNameOccurrence occurrence);
|
||||
|
||||
protected <T> String glomNames(Set<T> s) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (T t : s) {
|
||||
result.append(t.toString());
|
||||
result.append(',');
|
||||
}
|
||||
return result.length() == 0 ? "" : result.toString().substring(0, result.length() - 1);
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil;
|
||||
import net.sourceforge.pmd.lang.symboltable.AbstractNameDeclaration;
|
||||
|
||||
public class ClassNameDeclaration extends AbstractNameDeclaration implements TypedNameDeclaration {
|
||||
|
||||
public ClassNameDeclaration(JavaNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (node instanceof ASTAnyTypeDeclaration) {
|
||||
return PrettyPrintingUtil.getPrintableNodeKind((ASTAnyTypeDeclaration) node) + node.getImage();
|
||||
}
|
||||
return "anonymous";
|
||||
}
|
||||
|
||||
public Node getAccessNodeParent() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeImage() {
|
||||
return getTypeNode().getImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
if (node instanceof ASTAnyTypeDeclaration) {
|
||||
return ((ASTAnyTypeDeclaration) node).getType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null for anonymous classes.
|
||||
*/
|
||||
@Override
|
||||
public TypeNode getTypeNode() {
|
||||
return node instanceof TypeNode ? (TypeNode) node : null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
-51
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class DeclarationFinderFunction implements Predicate<NameDeclaration> {
|
||||
|
||||
private NameOccurrence occurrence;
|
||||
private NameDeclaration decl;
|
||||
|
||||
public DeclarationFinderFunction(NameOccurrence occurrence) {
|
||||
this.occurrence = occurrence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(NameDeclaration nameDeclaration) {
|
||||
// do not match method references
|
||||
if (occurrence.getLocation() instanceof ASTMethodReference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDeclaredBefore(nameDeclaration) && isSameName(nameDeclaration)) {
|
||||
decl = nameDeclaration;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isDeclaredBefore(NameDeclaration nameDeclaration) {
|
||||
return nameDeclaration.getNode() == null || occurrence.getLocation() == null
|
||||
|| nameDeclaration.getNode().getBeginLine() <= occurrence.getLocation().getBeginLine();
|
||||
}
|
||||
|
||||
private boolean isSameName(NameDeclaration nameDeclaration) {
|
||||
return occurrence.getImage().equals(nameDeclaration.getName());
|
||||
}
|
||||
|
||||
public NameDeclaration getDecl() {
|
||||
return this.decl;
|
||||
}
|
||||
}
|
||||
-232
@@ -1,232 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResource;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
public class JavaNameOccurrence implements NameOccurrence {
|
||||
|
||||
private JavaNode location;
|
||||
private String image;
|
||||
private NameOccurrence qualifiedName;
|
||||
|
||||
private boolean isMethodOrConstructorInvocation;
|
||||
private int argumentCount;
|
||||
|
||||
private static final String THIS = "this";
|
||||
private static final String SUPER = "super";
|
||||
|
||||
private static final String THIS_DOT = "this.";
|
||||
private static final String SUPER_DOT = "super.";
|
||||
|
||||
public JavaNameOccurrence(JavaNode location, String image) {
|
||||
this.location = location;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public void setIsMethodOrConstructorInvocation() {
|
||||
isMethodOrConstructorInvocation = true;
|
||||
}
|
||||
|
||||
public void setArgumentCount(int count) {
|
||||
argumentCount = count;
|
||||
}
|
||||
|
||||
public int getArgumentCount() {
|
||||
return argumentCount;
|
||||
}
|
||||
|
||||
public boolean isMethodOrConstructorInvocation() {
|
||||
return isMethodOrConstructorInvocation;
|
||||
}
|
||||
|
||||
public boolean isMethodReference() {
|
||||
return location instanceof ASTMethodReference;
|
||||
}
|
||||
|
||||
public void setNameWhichThisQualifies(NameOccurrence qualifiedName) {
|
||||
this.qualifiedName = qualifiedName;
|
||||
}
|
||||
|
||||
public NameOccurrence getNameForWhichThisIsAQualifier() {
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
public boolean isPartOfQualifiedName() {
|
||||
return qualifiedName != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaNode getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public boolean isOnRightHandSide() {
|
||||
Node node = location.getParent().getParent().getParent();
|
||||
return node instanceof ASTExpression && node.getNumChildren() == 3;
|
||||
}
|
||||
|
||||
public boolean isOnLeftHandSide() {
|
||||
// I detest this method with every atom of my being
|
||||
Node primaryExpression;
|
||||
if (location.getParent() instanceof ASTPrimaryExpression) {
|
||||
primaryExpression = location.getParent().getParent();
|
||||
} else if (location.getParent().getParent() instanceof ASTPrimaryExpression) {
|
||||
primaryExpression = location.getParent().getParent().getParent();
|
||||
} else if (location.getParent() instanceof ASTResource) {
|
||||
return false;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Found a NameOccurrence (" + location + ") that didn't have an ASTPrimary Expression"
|
||||
+ " as parent or grandparent nor is a concise resource. Parent = "
|
||||
+ location.getParent() + " and grandparent = " + location.getParent().getParent()
|
||||
+ " (location line " + location.getBeginLine() + " col " + location.getBeginColumn() + ")");
|
||||
}
|
||||
|
||||
return isStandAlonePostfix(primaryExpression)
|
||||
|| primaryExpression.getNumChildren() > 1
|
||||
&& primaryExpression.getChild(1) instanceof ASTAssignmentOperator
|
||||
&& !isPartOfQualifiedName() /* and is not an array type */
|
||||
&& !isCompoundAssignment(primaryExpression);
|
||||
}
|
||||
|
||||
private boolean isCompoundAssignment(Node primaryExpression) {
|
||||
return ((ASTAssignmentOperator) primaryExpression.getChild(1)).isCompound();
|
||||
}
|
||||
|
||||
private boolean isStandAlonePostfix(Node primaryExpression) {
|
||||
if (!(primaryExpression instanceof ASTUnaryExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTUnaryExpression unaryExpr = (ASTUnaryExpression) primaryExpression;
|
||||
|
||||
if (unaryExpr.getOperator().isPure()
|
||||
|| unaryExpr.getOperator().isPrefix()
|
||||
|| !(primaryExpression.getParent() instanceof ASTStatementExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTPrimaryPrefix pf = (ASTPrimaryPrefix) ((ASTPrimaryExpression) primaryExpression.getChild(0))
|
||||
.getChild(0);
|
||||
|
||||
return pf.usesThisModifier() || thirdChildHasDottedName(primaryExpression);
|
||||
}
|
||||
|
||||
private boolean thirdChildHasDottedName(Node primaryExpression) {
|
||||
Node thirdChild = primaryExpression.getChild(0).getChild(0).getChild(0);
|
||||
return thirdChild instanceof ASTName && ((ASTName) thirdChild).getImage().indexOf('.') == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert it the occurrence is a self assignment such as:
|
||||
* <code>i += 3;</code>
|
||||
*
|
||||
* @return true, if the occurrence is self-assignment, false, otherwise.
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidBranchingStatementAsLastInLoop")
|
||||
public boolean isSelfAssignment() {
|
||||
Node l = location;
|
||||
while (true) {
|
||||
Node p = l.getParent();
|
||||
Node gp = p.getParent();
|
||||
Node node = gp.getParent();
|
||||
if (node instanceof ASTUnaryExpression && !((ASTUnaryExpression) node).getOperator().isPure()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasAssignmentOperator(gp)) {
|
||||
return isCompoundAssignment(gp);
|
||||
}
|
||||
|
||||
if (hasAssignmentOperator(node)) {
|
||||
return isCompoundAssignment(node);
|
||||
}
|
||||
|
||||
// deal with extra parenthesis: "(i)++"
|
||||
if (p instanceof ASTPrimaryPrefix && p.getNumChildren() == 1 && gp instanceof ASTPrimaryExpression
|
||||
&& gp.getNumChildren() == 1 && node instanceof ASTExpression && node.getNumChildren() == 1
|
||||
&& node.getParent() instanceof ASTPrimaryPrefix
|
||||
&& node.getParent().getNumChildren() == 1) {
|
||||
l = node;
|
||||
continue;
|
||||
}
|
||||
|
||||
// catch this.i++ or ++this.i
|
||||
return node instanceof ASTUnaryExpression && !((ASTUnaryExpression) node).getOperator().isPure();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasAssignmentOperator(Node node) {
|
||||
if (node instanceof ASTStatementExpression || node instanceof ASTExpression) {
|
||||
if (node.getNumChildren() >= 2 && node.getChild(1) instanceof ASTAssignmentOperator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply return true is the image is equal to keyword 'this' or 'super'.
|
||||
*
|
||||
* @return return true if image equal to 'this' or 'super'.
|
||||
*/
|
||||
public boolean isThisOrSuper() {
|
||||
return THIS.equals(image) || SUPER.equals(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply return if the image start with keyword 'this' or 'super'.
|
||||
*
|
||||
* @return true, if keyword is used, false otherwise.
|
||||
*/
|
||||
public boolean useThisOrSuper() {
|
||||
Node node = location.getParent();
|
||||
if (node instanceof ASTPrimaryExpression) {
|
||||
ASTPrimaryExpression primaryExpression = (ASTPrimaryExpression) node;
|
||||
ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) primaryExpression.getChild(0);
|
||||
if (prefix != null) {
|
||||
return prefix.usesSuperModifier() || prefix.usesThisModifier();
|
||||
}
|
||||
}
|
||||
return image.startsWith(THIS_DOT) || image.startsWith(SUPER_DOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof JavaNameOccurrence) {
|
||||
JavaNameOccurrence n = (JavaNameOccurrence) o;
|
||||
return n.getImage().equals(getImage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getImage().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getImage() + ":" + location.getBeginLine() + ":" + location.getClass()
|
||||
+ (this.isMethodOrConstructorInvocation() ? "(method call)" : "");
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.symboltable.Applier;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
/**
|
||||
* A LocalScope can have variable declarations and class declarations within it.
|
||||
*/
|
||||
public class LocalScope extends AbstractJavaScope {
|
||||
|
||||
public Map<VariableNameDeclaration, List<NameOccurrence>> getVariableDeclarations() {
|
||||
return getDeclarations(VariableNameDeclaration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NameDeclaration> addNameOccurrence(NameOccurrence occurrence) {
|
||||
JavaNameOccurrence javaOccurrence = (JavaNameOccurrence) occurrence;
|
||||
Set<NameDeclaration> declarations = findVariableHere(javaOccurrence);
|
||||
if (!declarations.isEmpty() && !javaOccurrence.isThisOrSuper()) {
|
||||
for (NameDeclaration decl : declarations) {
|
||||
List<NameOccurrence> nameOccurrences = getVariableDeclarations().get(decl);
|
||||
nameOccurrences.add(javaOccurrence);
|
||||
Node n = javaOccurrence.getLocation();
|
||||
if (n instanceof ASTName) {
|
||||
((ASTName) n).setNameDeclaration(decl);
|
||||
} // TODO what to do with PrimarySuffix case?
|
||||
}
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeclaration(NameDeclaration nameDecl) {
|
||||
if (!(nameDecl instanceof VariableNameDeclaration || nameDecl instanceof ClassNameDeclaration)) {
|
||||
throw new IllegalArgumentException(
|
||||
"A LocalScope can contain only VariableNameDeclarations or ClassNameDeclarations. "
|
||||
+ "Tried to add " + nameDecl.getClass() + "(" + nameDecl + ")");
|
||||
}
|
||||
super.addDeclaration(nameDecl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NameDeclaration> findVariableHere(JavaNameOccurrence occurrence) {
|
||||
if (occurrence.isThisOrSuper() || occurrence.isMethodOrConstructorInvocation()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
DeclarationFinderFunction finder = new DeclarationFinderFunction(occurrence);
|
||||
Applier.apply(finder, getVariableDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocalScope:" + glomNames(getVariableDeclarations().keySet());
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.sourceforge.pmd.internal.util.IteratorUtil;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.symboltable.AbstractNameDeclaration;
|
||||
|
||||
public class MethodNameDeclaration extends AbstractNameDeclaration {
|
||||
|
||||
public MethodNameDeclaration(ASTMethodDeclaration node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public int getParameterCount() {
|
||||
return getDeclarator().getArity();
|
||||
}
|
||||
|
||||
public boolean isVarargs() {
|
||||
return getDeclarator().isVarargs();
|
||||
}
|
||||
|
||||
public String getParameterDisplaySignature() {
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
// TODO - this can be written with Streams and Collectors::joining
|
||||
for (ASTFormalParameter p : getDeclarator().getFormalParameters()) {
|
||||
sb.append(p.getTypeNode().getTypeImage());
|
||||
if (p.isVarargs()) {
|
||||
sb.append("...");
|
||||
}
|
||||
sb.append(',');
|
||||
}
|
||||
if (sb.charAt(sb.length() - 1) == ',') {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ASTMethodDeclaration getDeclarator() {
|
||||
return (ASTMethodDeclaration) node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof MethodNameDeclaration)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MethodNameDeclaration other = (MethodNameDeclaration) o;
|
||||
|
||||
// compare name
|
||||
if (!other.getName().equals(getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compare parameter count - this catches the case where there are no
|
||||
// params, too
|
||||
if (other.getParameterCount() != this.getParameterCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compare parameter types
|
||||
|
||||
List<ASTFormalParameter> myParams = IteratorUtil.toList(getDeclarator().getFormalParameters().iterator());
|
||||
List<ASTFormalParameter> otherParams = IteratorUtil.toList(other.getDeclarator().getFormalParameters().iterator());
|
||||
|
||||
for (int i = 0; i < myParams.size(); i++) {
|
||||
ASTFormalParameter myParam = myParams.get(i);
|
||||
ASTFormalParameter otherParam = otherParams.get(i);
|
||||
|
||||
// Compare vararg
|
||||
if (myParam.isVarargs() != otherParam.isVarargs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTType myTypeNode = myParam.getTypeNode();
|
||||
ASTType otherTypeNode = otherParam.getTypeNode();
|
||||
|
||||
// compare primitive vs reference type
|
||||
if (myTypeNode.getClass() != otherTypeNode.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// fallback on simple comparison of type images
|
||||
// this can be fooled by one method using "String"
|
||||
// and the other method using "java.lang.String"
|
||||
// once we get real types in here that should get fixed
|
||||
if (!Objects.equals(myTypeNode.getTypeImage(), otherTypeNode.getTypeImage())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
ASTMethodDeclaration declaration = getDeclarator();
|
||||
int hash = declaration.getName().hashCode() * 31 + declaration.getArity();
|
||||
|
||||
for (ASTFormalParameter myParam : declaration.getFormalParameters()) {
|
||||
String myTypeImg = myParam.getTypeNode().getTypeImage();
|
||||
hash = hash * 31 + myTypeImg.hashCode();
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Method " + node.getImage() + ", line " + node.getBeginLine() + ", params = "
|
||||
+ getDeclarator().getArity();
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.symboltable.Applier;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
/**
|
||||
* A Method Scope can have variable declarations and class declarations within
|
||||
* it.
|
||||
*/
|
||||
public class MethodScope extends AbstractJavaScope {
|
||||
|
||||
private Node node;
|
||||
|
||||
public MethodScope(Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public Map<VariableNameDeclaration, List<NameOccurrence>> getVariableDeclarations() {
|
||||
return getDeclarations(VariableNameDeclaration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NameDeclaration> addNameOccurrence(NameOccurrence occurrence) {
|
||||
JavaNameOccurrence javaOccurrence = (JavaNameOccurrence) occurrence;
|
||||
Set<NameDeclaration> declarations = findVariableHere(javaOccurrence);
|
||||
if (!declarations.isEmpty() && !javaOccurrence.isThisOrSuper()) {
|
||||
for (NameDeclaration decl : declarations) {
|
||||
getVariableDeclarations().get(decl).add(javaOccurrence);
|
||||
Node n = javaOccurrence.getLocation();
|
||||
if (n instanceof ASTName) {
|
||||
((ASTName) n).setNameDeclaration(decl);
|
||||
} // TODO what to do with PrimarySuffix case?
|
||||
}
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeclaration(NameDeclaration variableDecl) {
|
||||
if (!(variableDecl instanceof VariableNameDeclaration || variableDecl instanceof ClassNameDeclaration)) {
|
||||
throw new IllegalArgumentException(
|
||||
"A MethodScope can contain only VariableNameDeclarations or ClassNameDeclarations");
|
||||
}
|
||||
super.addDeclaration(variableDecl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NameDeclaration> findVariableHere(JavaNameOccurrence occurrence) {
|
||||
if (occurrence.isThisOrSuper() || occurrence.isMethodOrConstructorInvocation()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
DeclarationFinderFunction finder = new DeclarationFinderFunction(occurrence);
|
||||
Applier.apply(finder, getVariableDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (node instanceof ASTConstructorDeclaration) {
|
||||
return this.getEnclosingScope(ClassScope.class).getClassName();
|
||||
}
|
||||
return node.getChild(1).getImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodScope:" + glomNames(getVariableDeclarations().keySet());
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMemberSelector;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
@SuppressWarnings("PMD")
|
||||
public class NameFinder {
|
||||
|
||||
private List<JavaNameOccurrence> names = new ArrayList<>();
|
||||
|
||||
public NameFinder(ASTPrimaryExpression node) {
|
||||
|
||||
// ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) node.getChild(0);
|
||||
// if (prefix.usesSuperModifier()) {
|
||||
// add(new JavaNameOccurrence(prefix, "super"));
|
||||
// } else if (prefix.usesThisModifier()) {
|
||||
// add(new JavaNameOccurrence(prefix, "this"));
|
||||
// }
|
||||
// for (int i = 0; i < node.getNumChildren(); i++) {
|
||||
// checkForNameChild((JavaNode) node.getChild(i));
|
||||
// }
|
||||
}
|
||||
|
||||
public List<JavaNameOccurrence> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
private void checkForNameChild(JavaNode node) {
|
||||
if (node.getImage() != null) {
|
||||
add(new JavaNameOccurrence(node, node.getImage()));
|
||||
}
|
||||
if (node.getNumChildren() > 0 && node.getChild(0) instanceof ASTName) {
|
||||
ASTName grandchild = (ASTName) node.getChild(0);
|
||||
for (StringTokenizer st = new StringTokenizer(grandchild.getImage(), "."); st.hasMoreTokens();) {
|
||||
add(new JavaNameOccurrence(grandchild, st.nextToken()));
|
||||
}
|
||||
}
|
||||
if (node.getNumChildren() > 1 && node.getChild(1) instanceof ASTMethodReference) {
|
||||
ASTMethodReference methodRef = (ASTMethodReference) node.getChild(1);
|
||||
add(new JavaNameOccurrence(methodRef, methodRef.getImage()));
|
||||
}
|
||||
if (node instanceof ASTPrimarySuffix) {
|
||||
ASTPrimarySuffix suffix = (ASTPrimarySuffix) node;
|
||||
if (suffix.isArguments()) {
|
||||
if (!names.isEmpty()) {
|
||||
JavaNameOccurrence occurrence = names.get(names.size() - 1);
|
||||
occurrence.setIsMethodOrConstructorInvocation();
|
||||
ASTArguments args = (ASTArguments) ((ASTPrimarySuffix) node).getChild(0);
|
||||
occurrence.setArgumentCount(args.size());
|
||||
}
|
||||
} else if (suffix.getNumChildren() == 1 && suffix.getChild(0) instanceof ASTMemberSelector) {
|
||||
ASTMemberSelector member = (ASTMemberSelector) suffix.getChild(0);
|
||||
if (member.getNumChildren() == 1 && member.getChild(0) instanceof ASTMethodReference) {
|
||||
ASTMethodReference methodRef = (ASTMethodReference) member.getChild(0);
|
||||
add(new JavaNameOccurrence(methodRef, methodRef.getImage()));
|
||||
} else {
|
||||
add(new JavaNameOccurrence(member, member.getImage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(JavaNameOccurrence name) {
|
||||
names.add(name);
|
||||
if (names.size() > 1) {
|
||||
JavaNameOccurrence qualifiedName = names.get(names.size() - 2);
|
||||
qualifiedName.setNameWhichThisQualifies(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (NameOccurrence occ : names) {
|
||||
result.append(occ);
|
||||
result.append(PMD.EOL);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class OccurrenceFinder extends JavaParserVisitorAdapter {
|
||||
|
||||
// Maybe do some sort of State pattern thingy for when NameDeclaration
|
||||
// is empty/not empty?
|
||||
private final Set<NameDeclaration> declarations = new HashSet<>();
|
||||
|
||||
private final Set<NameDeclaration> additionalDeclarations = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public Object visit(ASTPrimaryExpression node, Object data) {
|
||||
NameFinder nameFinder = new NameFinder(node);
|
||||
|
||||
declarations.clear();
|
||||
additionalDeclarations.clear();
|
||||
|
||||
List<JavaNameOccurrence> names = nameFinder.getNames();
|
||||
for (JavaNameOccurrence occ : names) {
|
||||
Search search = new Search(occ);
|
||||
if (declarations.isEmpty()) {
|
||||
// doing the first name lookup
|
||||
search.execute();
|
||||
declarations.addAll(search.getResult());
|
||||
if (declarations.isEmpty()) {
|
||||
// we can't find it, so just give up
|
||||
// when we decide to do full symbol resolution
|
||||
// force this to either find a symbol or throw a
|
||||
// SymbolNotFoundException
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (NameDeclaration decl : declarations) {
|
||||
// now we've got a scope we're starting with, so work from
|
||||
// there
|
||||
Scope startingScope = decl.getScope();
|
||||
// in case the previous found declaration is a class
|
||||
// reference
|
||||
// for a class inside the same source file
|
||||
// we need to search this class
|
||||
// e.g. the list of name occurrence could come from
|
||||
// outerClassRef.member. See also bug #1302
|
||||
if (decl instanceof VariableNameDeclaration) {
|
||||
String typeImage = ((VariableNameDeclaration) decl).getTypeImage();
|
||||
ClassNameDeclaration clazzDeclaration = startingScope.getEnclosingScope(SourceFileScope.class)
|
||||
.findClassNameDeclaration(typeImage);
|
||||
if (clazzDeclaration != null) {
|
||||
startingScope = clazzDeclaration.getScope();
|
||||
}
|
||||
}
|
||||
search.execute(startingScope);
|
||||
Set<NameDeclaration> result = search.getResult();
|
||||
additionalDeclarations.addAll(result);
|
||||
if (result.isEmpty()) {
|
||||
// nothing found
|
||||
// This seems to be a lack of type resolution here.
|
||||
// Theoretically we have the previous declaration node
|
||||
// and
|
||||
// know from there the Type of
|
||||
// the variable. The current occurrence (occ) should
|
||||
// then be
|
||||
// found in the declaration of
|
||||
// this type. The type however may or may not be known
|
||||
// to
|
||||
// PMD (see aux classpath).
|
||||
|
||||
// we can't find it, so just give up
|
||||
// when we decide to do full symbol resolution
|
||||
// force this to either find a symbol or throw a
|
||||
// SymbolNotFoundException
|
||||
break;
|
||||
}
|
||||
}
|
||||
declarations.addAll(additionalDeclarations);
|
||||
}
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
}
|
||||
-298
@@ -1,298 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnonymousClassDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
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.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
/**
|
||||
* Visitor for scope creation. Visits all nodes of an AST and creates scope
|
||||
* objects for nodes representing syntactic entities which may contain
|
||||
* declarations. For example, a block may contain variable definitions (which
|
||||
* are declarations) and therefore needs a scope object where these declarations
|
||||
* can be associated, whereas an expression can't contain declarations and
|
||||
* therefore doesn't need a scope object. With the exception of global scopes,
|
||||
* each scope object is linked to its parent scope, which is the scope object of
|
||||
* the next embedding syntactic entity that has a scope.
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
* A stack of scopes reflecting the scope hierarchy when a node is visited.
|
||||
* This is used to set the parents of the created scopes correctly.
|
||||
*/
|
||||
private Deque<Scope> scopes = new ArrayDeque<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link ScopeAndDeclarationFinder} using the current class
|
||||
* loader.
|
||||
*/
|
||||
public ScopeAndDeclarationFinder() {
|
||||
this(ScopeAndDeclarationFinder.class.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ScopeAndDeclarationFinder}.
|
||||
*
|
||||
* @param classLoader
|
||||
* the class loader to use to resolve types, see
|
||||
* {@link SourceFileScope} and {@link TypeSet}
|
||||
*/
|
||||
public ScopeAndDeclarationFinder(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scope of a node and adjusts the scope stack accordingly. The
|
||||
* scope on top of the stack is set as the parent of the given scope, which
|
||||
* is then also stored on the scope stack.
|
||||
*
|
||||
* @param newScope
|
||||
* the scope for the node.
|
||||
* @param node
|
||||
* the AST node for which the scope is to be set.
|
||||
* @throws java.util.EmptyStackException
|
||||
* if the scope stack is empty.
|
||||
*/
|
||||
private void addScope(Scope newScope, JavaNode node) {
|
||||
newScope.setParent(scopes.peek());
|
||||
scopes.push(newScope);
|
||||
InternalApiBridge.setScope(node, newScope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new local scope for an AST node. The scope on top of the stack
|
||||
* is set as the parent of the new scope, which is then also stored on the
|
||||
* scope stack.
|
||||
*
|
||||
* @param node
|
||||
* the AST node for which the scope has to be created.
|
||||
* @throws java.util.EmptyStackException
|
||||
* if the scope stack is empty.
|
||||
*/
|
||||
private void createLocalScope(JavaNode node) {
|
||||
addScope(new LocalScope(), node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new method scope for an AST node. The scope on top of the stack
|
||||
* is set as the parent of the new scope, which is then also stored on the
|
||||
* scope stack.
|
||||
*
|
||||
* @param node
|
||||
* the AST node for which the scope has to be created.
|
||||
* @throws java.util.EmptyStackException
|
||||
* if the scope stack is empty.
|
||||
*/
|
||||
private void createMethodScope(JavaNode node) {
|
||||
addScope(new MethodScope(node), node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new class scope for an AST node. The scope on top of the stack
|
||||
* is set as the parent of the new scope, which is then also stored on the
|
||||
* scope stack.
|
||||
*
|
||||
* @param node
|
||||
* the AST node for which the scope has to be created.
|
||||
* @throws java.util.EmptyStackException
|
||||
* if the scope stack is empty.
|
||||
*/
|
||||
private void createClassScope(JavaNode node) {
|
||||
Scope s = ((JavaNode) node.getParent()).getScope();
|
||||
ClassNameDeclaration classNameDeclaration = new ClassNameDeclaration(node);
|
||||
s.addDeclaration(classNameDeclaration);
|
||||
|
||||
if (node instanceof ASTAnonymousClassDeclaration) {
|
||||
addScope(new ClassScope(classNameDeclaration), node);
|
||||
} else {
|
||||
addScope(new ClassScope(node.getImage(), classNameDeclaration), node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new global scope for an AST node. The new scope is stored on
|
||||
* the scope stack.
|
||||
*
|
||||
* @param node
|
||||
* the AST node for which the scope has to be created.
|
||||
*/
|
||||
private void createSourceFileScope(ASTCompilationUnit node) {
|
||||
// When we do full symbol resolution, we'll need to add a truly
|
||||
// top-level GlobalScope.
|
||||
SourceFileScope scope;
|
||||
ASTPackageDeclaration n = node.getPackageDeclaration();
|
||||
if (n != null) {
|
||||
scope = new SourceFileScope(classLoader, n.getName());
|
||||
} else {
|
||||
scope = new SourceFileScope(classLoader);
|
||||
}
|
||||
scope.configureImports(node.findChildrenOfType(ASTImportDeclaration.class));
|
||||
|
||||
scopes.push(scope);
|
||||
InternalApiBridge.setScope(node, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTCompilationUnit node, Object data) {
|
||||
createSourceFileScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTEnumDeclaration node, Object data) {
|
||||
createClassScope(node);
|
||||
((ClassScope) node.getScope()).setIsEnum(true);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTAnnotationTypeDeclaration node, Object data) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTRecordDeclaration node, Object data) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTAnonymousClassDeclaration node, Object data) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTBlock node, Object data) {
|
||||
// top-level blocks for methods should have the same scope as parameters, just skip them
|
||||
// same applies to catch statements defining exceptions + the catch block, and for-blocks
|
||||
if (node.getParent() instanceof ASTMethodDeclaration
|
||||
|| node.getParent() instanceof ASTConstructorDeclaration
|
||||
|| node.getParent() instanceof ASTLambdaExpression
|
||||
|| node.getParent() instanceof ASTCatchClause
|
||||
|| node.getParent() instanceof ASTForStatement) {
|
||||
super.visit(node, null);
|
||||
} else {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTCatchClause node, Object data) {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTConstructorDeclaration node, Object data) {
|
||||
createMethodScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodDeclaration node, Object data) {
|
||||
createMethodScope(node);
|
||||
node.getScope().getEnclosingScope(ClassScope.class).addDeclaration(new MethodNameDeclaration(node));
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTLambdaExpression node, Object data) {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTTryStatement node, Object data) {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
// TODO - what about while loops and do loops?
|
||||
@Override
|
||||
public Object visit(ASTForStatement node, Object data) {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTVariableDeclaratorId node, Object data) {
|
||||
if (node.isPatternBinding()) {
|
||||
// Don't consider type test patterns here. It could bind to a name
|
||||
// that is already in the scope (e.g. field names).
|
||||
// type tests patterns are tricky to implement
|
||||
// and given it's a preview feature, and the sym table will be replaced
|
||||
// for 7.0, it's not useful to support them.
|
||||
// See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
VariableNameDeclaration decl = new VariableNameDeclaration(node);
|
||||
node.getScope().addDeclaration(decl);
|
||||
node.setNameDeclaration(decl);
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSwitchStatement node, Object data) {
|
||||
createLocalScope(node);
|
||||
cont(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
private void cont(JavaNode node) {
|
||||
super.visitJavaNode(node, null);
|
||||
scopes.pop();
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class Search {
|
||||
private static final boolean TRACE = false;
|
||||
|
||||
private NameOccurrence occ;
|
||||
private Set<NameDeclaration> declarations = new HashSet<>();
|
||||
|
||||
public Search(JavaNameOccurrence occ) {
|
||||
if (TRACE) {
|
||||
System.out.println(
|
||||
"new search for " + (occ.isMethodOrConstructorInvocation() ? "method" : "variable") + " " + occ);
|
||||
}
|
||||
this.occ = occ;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
Set<NameDeclaration> found = searchUpward(occ, occ.getLocation().getScope());
|
||||
if (TRACE) {
|
||||
System.out.println("found " + found);
|
||||
}
|
||||
declarations.addAll(found);
|
||||
}
|
||||
|
||||
public void execute(Scope startingScope) {
|
||||
Set<NameDeclaration> found = searchUpward(occ, startingScope);
|
||||
if (TRACE) {
|
||||
System.out.println("found " + found);
|
||||
}
|
||||
declarations.addAll(found);
|
||||
}
|
||||
|
||||
public Set<NameDeclaration> getResult() {
|
||||
return declarations;
|
||||
}
|
||||
|
||||
private Set<NameDeclaration> searchUpward(NameOccurrence nameOccurrence, Scope scope) {
|
||||
if (TRACE) {
|
||||
System.out.println(" checking scope " + scope + " for name occurrence " + nameOccurrence);
|
||||
}
|
||||
final boolean isInScope = scope.contains(nameOccurrence);
|
||||
if (!isInScope && scope.getParent() != null) {
|
||||
if (TRACE) {
|
||||
System.out.println(" moving up from " + scope + " to " + scope.getParent());
|
||||
}
|
||||
return searchUpward(nameOccurrence, scope.getParent());
|
||||
}
|
||||
if (isInScope) {
|
||||
if (TRACE) {
|
||||
System.out.println(" found it!");
|
||||
}
|
||||
return scope.addNameOccurrence(nameOccurrence);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
|
||||
/**
|
||||
* Just stores a type image and a actual type. And makes it easy to compare
|
||||
* these.
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class SimpleTypedNameDeclaration implements TypedNameDeclaration {
|
||||
|
||||
private final String typeImage;
|
||||
private final Class<?> type;
|
||||
private SimpleTypedNameDeclaration next;
|
||||
|
||||
private static Set<String> primitiveTypes = new HashSet<>();
|
||||
|
||||
static {
|
||||
primitiveTypes.add("float");
|
||||
primitiveTypes.add("double");
|
||||
primitiveTypes.add("int");
|
||||
primitiveTypes.add("integer");
|
||||
primitiveTypes.add("long");
|
||||
primitiveTypes.add("byte");
|
||||
primitiveTypes.add("short");
|
||||
primitiveTypes.add("boolean");
|
||||
primitiveTypes.add("char");
|
||||
primitiveTypes.add("character");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleTypedNameDeclaration} with the given type
|
||||
*
|
||||
* @param typeImage
|
||||
* the type image
|
||||
* @param type
|
||||
* the actual type
|
||||
*/
|
||||
public SimpleTypedNameDeclaration(String typeImage, Class<?> type) {
|
||||
this.typeImage = typeImage;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SimpleTypedNameDeclaration(String typeImage, Class<?> type, SimpleTypedNameDeclaration next) {
|
||||
this.typeImage = typeImage;
|
||||
this.type = type;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public void addNext(SimpleTypedNameDeclaration next) {
|
||||
if (next == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.next == null) {
|
||||
this.next = next;
|
||||
} else {
|
||||
this.next.addNext(next);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeNode getTypeNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeImage() {
|
||||
return typeImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String nextString = next != null ? "(next: " + next + ")" : "";
|
||||
return "SimpleType:" + type + "/" + typeImage + nextString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
result = prime * result + ((typeImage == null) ? 0 : typeImage.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Additionally - two {@link SimpleTypedNameDeclaration} are equal, if they
|
||||
* contain types, that can be cast into each other.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return internalEquals(obj) || internalEqualsNext(obj);
|
||||
}
|
||||
|
||||
private boolean internalEqualsNext(Object obj) {
|
||||
if (next != null) {
|
||||
return next.equals(obj);
|
||||
}
|
||||
if (obj instanceof SimpleTypedNameDeclaration) {
|
||||
SimpleTypedNameDeclaration otherNext = ((SimpleTypedNameDeclaration) obj).next;
|
||||
if (otherNext != null) {
|
||||
return otherNext.equals(this);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
private boolean internalEquals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SimpleTypedNameDeclaration other = (SimpleTypedNameDeclaration) obj;
|
||||
if (type == null) {
|
||||
if (other.type == Object.class) {
|
||||
return true;
|
||||
}
|
||||
if (other.type != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (type != null && (type.equals(other.type) || type == Object.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the type is given, only compare the type and don't care about the
|
||||
// type image
|
||||
if (type != null && other.type != null
|
||||
&& (type.isAssignableFrom(other.type) || other.type.isAssignableFrom(type))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeImage == null) {
|
||||
if (other.typeImage != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!typeImage.equals(other.typeImage)) {
|
||||
// consider auto-boxing
|
||||
if (other.typeImage != null) {
|
||||
String lcType = typeImage.toLowerCase(Locale.ROOT);
|
||||
String otherLcType = other.typeImage.toLowerCase(Locale.ROOT);
|
||||
if (primitiveTypes.contains(lcType) && primitiveTypes.contains(otherLcType)) {
|
||||
if (lcType.equals(otherLcType)) {
|
||||
return true;
|
||||
} else if (("char".equals(lcType) || "character".equals(lcType))
|
||||
&& ("char".equals(otherLcType) || "character".equals(otherLcType))) {
|
||||
return true;
|
||||
} else if (("int".equals(lcType) || "integer".equals(lcType))
|
||||
&& ("int".equals(otherLcType) || "integer".equals(otherLcType)
|
||||
|| "short".equals(otherLcType) || "char".equals(otherLcType)
|
||||
|| "character".equals(otherLcType) || "byte".equals(otherLcType))) {
|
||||
return true;
|
||||
} else if ("double".equals(lcType) && ("float".equals(otherLcType) || "int".equals(otherLcType)
|
||||
|| "integer".equals(otherLcType) || "long".equals(otherLcType))) {
|
||||
return true;
|
||||
} else if ("float".equals(lcType) && ("int".equals(otherLcType) || "integer".equals(otherLcType)
|
||||
|| "long".equals(otherLcType))) {
|
||||
return true;
|
||||
} else if ("long".equals(lcType) && ("int".equals(otherLcType) || "integer".equals(otherLcType)
|
||||
|| "char".equals(otherLcType) || "character".equals(otherLcType))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.Applier;
|
||||
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
/**
|
||||
* This scope is the outer most scope of a Java file. A Source File can contain
|
||||
* one ore more classes.
|
||||
*/
|
||||
public class SourceFileScope extends AbstractJavaScope {
|
||||
|
||||
private final String packageImage;
|
||||
private final TypeSet types;
|
||||
private Map<String, Node> qualifiedTypeNames;
|
||||
|
||||
public SourceFileScope(final ClassLoader classLoader) {
|
||||
this(classLoader, "");
|
||||
}
|
||||
|
||||
public SourceFileScope(final ClassLoader classLoader, final String packageImage) {
|
||||
this.types = new TypeSet(classLoader);
|
||||
this.packageImage = packageImage;
|
||||
types.setASTCompilationUnitPackage(packageImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the type resolution for the symbol table.
|
||||
*
|
||||
* @param imports
|
||||
* the import declarations
|
||||
*/
|
||||
public void configureImports(final List<ASTImportDeclaration> imports) {
|
||||
for (ASTImportDeclaration i : imports) {
|
||||
if (i.isImportOnDemand()) {
|
||||
types.addImport(i.getImportedName() + ".*");
|
||||
} else {
|
||||
types.addImport(i.getImportedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getExplicitImports() {
|
||||
return types.getExplicitImports();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an auxclasspath has been configured or not. This can be used to
|
||||
* enable/disable more detailed symbol table analysis and type resolution
|
||||
* can be used - or to fall back to more simple implementation.
|
||||
*
|
||||
* @return <code>true</code> if the auxclasspath is configured and types can
|
||||
* be resolved reliably.
|
||||
* @see #resolveType(String)
|
||||
*/
|
||||
public boolean hasAuxclasspath() {
|
||||
return types.hasAuxclasspath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to resolve a class by name.
|
||||
*
|
||||
* @param name
|
||||
* the name of the class
|
||||
* @return the class or <code>null</code> if no class could be found
|
||||
*/
|
||||
public Class<?> resolveType(String name) {
|
||||
return types.findClass(name);
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageImage;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if declaration is not a {@link ClassNameDeclaration}
|
||||
*/
|
||||
@Override
|
||||
public void addDeclaration(NameDeclaration declaration) {
|
||||
if (!(declaration instanceof ClassNameDeclaration)) {
|
||||
throw new IllegalArgumentException("A SourceFileScope can only contain classes.");
|
||||
}
|
||||
super.addDeclaration(declaration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that casts the declarations to
|
||||
* {@link ClassNameDeclaration}s.
|
||||
*
|
||||
* @see #getDeclarations()
|
||||
* @return all class name declarations
|
||||
*/
|
||||
public Map<ClassNameDeclaration, List<NameOccurrence>> getClassDeclarations() {
|
||||
return getDeclarations(ClassNameDeclaration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SourceFileScope: " + glomNames(getClassDeclarations().keySet());
|
||||
}
|
||||
|
||||
public ClassNameDeclaration findClassNameDeclaration(String name) {
|
||||
ImageFinderFunction finder = new ImageFinderFunction(name);
|
||||
Applier.apply(finder, getClassDeclarations().keySet().iterator());
|
||||
return (ClassNameDeclaration) finder.getDecl();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<NameDeclaration> findVariableHere(JavaNameOccurrence occ) {
|
||||
ImageFinderFunction finder = new ImageFinderFunction(occ.getImage());
|
||||
Applier.apply(finder, getDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all types defined within this source file. This includes
|
||||
* all top-level types and nested types.
|
||||
*
|
||||
* @return set of all types in this source file.
|
||||
*/
|
||||
public Map<String, Node> getQualifiedTypeNames() {
|
||||
if (qualifiedTypeNames != null) {
|
||||
return qualifiedTypeNames;
|
||||
}
|
||||
|
||||
qualifiedTypeNames = getSubTypes(null, this);
|
||||
return qualifiedTypeNames;
|
||||
}
|
||||
|
||||
private Map<String, Node> getSubTypes(String qualifyingName, Scope subType) {
|
||||
Set<ClassNameDeclaration> classDeclarations = subType.getDeclarations(ClassNameDeclaration.class).keySet();
|
||||
if (classDeclarations.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, Node> types = new HashMap<>((int) (classDeclarations.size() / 0.75f) + 1);
|
||||
for (ClassNameDeclaration c : classDeclarations) {
|
||||
String typeName = c.getName();
|
||||
if (qualifyingName != null) {
|
||||
typeName = qualifyingName + "." + typeName;
|
||||
}
|
||||
types.put(typeName, c.getNode());
|
||||
types.putAll(getSubTypes(typeName, c.getScope()));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class SymbolFacade {
|
||||
public void initializeWith(ASTCompilationUnit node) {
|
||||
initializeWith(SymbolFacade.class.getClassLoader(), node);
|
||||
}
|
||||
|
||||
public void initializeWith(ClassLoader classLoader, ASTCompilationUnit node) {
|
||||
ScopeAndDeclarationFinder sc = new ScopeAndDeclarationFinder(classLoader);
|
||||
node.jjtAccept(sc, null);
|
||||
OccurrenceFinder of = new OccurrenceFinder();
|
||||
node.jjtAccept(of, null);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
-20
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
|
||||
public interface TypedNameDeclaration {
|
||||
|
||||
String getTypeImage();
|
||||
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Nullable
|
||||
*/
|
||||
TypeNode getTypeNode();
|
||||
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCatchParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLambdaParameter;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.AccessNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.symboltable.AbstractNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
public class VariableNameDeclaration extends AbstractNameDeclaration implements TypedNameDeclaration {
|
||||
|
||||
public VariableNameDeclaration(ASTVariableDeclaratorId node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scope getScope() {
|
||||
return node.getScope().getEnclosingScope(ClassScope.class);
|
||||
}
|
||||
|
||||
public boolean isArray() {
|
||||
return getDeclaratorId().hasArrayType();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getArrayDepth() {
|
||||
return getExplicitTypeNode().getArrayDepth();
|
||||
}
|
||||
|
||||
public boolean isVarargs() {
|
||||
ASTFormalParameter parameter = node.getFirstParentOfType(ASTFormalParameter.class);
|
||||
return parameter != null && parameter.isVarargs();
|
||||
}
|
||||
|
||||
public boolean isExceptionBlockParameter() {
|
||||
return getDeclaratorId().isExceptionBlockParameter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isTypeInferred()}
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isLambdaTypelessParameter() {
|
||||
return isTypeInferred();
|
||||
}
|
||||
|
||||
public boolean isTypeInferred() {
|
||||
return getDeclaratorId().isTypeInferred();
|
||||
}
|
||||
|
||||
public boolean isPrimitiveType() {
|
||||
return getExplicitTypeNode() instanceof ASTPrimitiveType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeImage() {
|
||||
ASTType typeNode = getExplicitTypeNode();
|
||||
if (typeNode != null) {
|
||||
return typeNode.getTypeImage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that an array of primitive types (int[]) is a reference type.
|
||||
*/
|
||||
public boolean isReferenceType() {
|
||||
return getTypeNode() instanceof ASTReferenceType;
|
||||
}
|
||||
|
||||
public boolean isRecordComponent() {
|
||||
return node.getParent() instanceof ASTRecordComponent;
|
||||
}
|
||||
|
||||
public AccessNode getAccessNodeParent() {
|
||||
if (node.getParent() instanceof ASTFormalParameter) {
|
||||
return (ASTFormalParameter) node.getParent();
|
||||
} else if (node.getParent() instanceof ASTLambdaParameter) {
|
||||
return (ASTLambdaParameter) node.getParent();
|
||||
} else if (node.getParent() instanceof ASTEnumConstant) {
|
||||
return (ASTEnumConstant) node.getParent();
|
||||
} else if (node.getParent() instanceof ASTCatchParameter) {
|
||||
return (AccessNode) node.getParent();
|
||||
} else if (node.getParent() instanceof ASTRecordComponent) {
|
||||
return null;
|
||||
}
|
||||
return (AccessNode) node.getParent().getParent();
|
||||
}
|
||||
|
||||
public ASTVariableDeclaratorId getDeclaratorId() {
|
||||
return (ASTVariableDeclaratorId) node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeNode getTypeNode() {
|
||||
return getDeclaratorId();
|
||||
}
|
||||
|
||||
private ASTType getExplicitTypeNode() {
|
||||
return getDeclaratorId().getTypeNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
TypeNode typeNode = getExplicitTypeNode();
|
||||
if (typeNode != null) {
|
||||
return typeNode.getType();
|
||||
}
|
||||
// if there is no type node, then return the type of the declarator id.
|
||||
// this might be a inferred type
|
||||
return getDeclaratorId().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof VariableNameDeclaration)) {
|
||||
return false;
|
||||
}
|
||||
VariableNameDeclaration n = (VariableNameDeclaration) o;
|
||||
return n.node.getImage().equals(node.getImage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return node.getImage().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Variable: image = '" + node.getImage() + "', line = " + node.getBeginLine();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* This entire package is deprecated.
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
@@ -11,6 +11,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({
|
||||
ParserCornersTest.class,
|
||||
Java14TreeDumpTest.class,
|
||||
Java15TreeDumpTest.class,
|
||||
Java16PreviewTreeDumpTest.class,
|
||||
Java16TreeDumpTest.class,
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
/**
|
||||
* Tests new java14 standard features.
|
||||
*/
|
||||
@Ignore("Needs to be fixed for new AST structure. All of this is already much better tested in Kotlin, I don't want to port these tests...")
|
||||
public class Java14Test {
|
||||
private final JavaParsingHelper java14 =
|
||||
JavaParsingHelper.DEFAULT.withDefaultVersion("14")
|
||||
.withResourceContext(Java14Test.class, "jdkversiontests/java14/");
|
||||
|
||||
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
|
||||
|
||||
/**
|
||||
* Tests switch expressions with yield.
|
||||
*/
|
||||
@Test
|
||||
public void switchExpressions() {
|
||||
parseAndCheckSwitchExpression(java14);
|
||||
}
|
||||
|
||||
/**
|
||||
* In java13, switch expressions are only available with preview.
|
||||
*/
|
||||
@Test(expected = ParseException.class)
|
||||
public void switchExpressions13ShouldFail() {
|
||||
parseAndCheckSwitchExpression(java13);
|
||||
}
|
||||
|
||||
private void parseAndCheckSwitchExpression(JavaParsingHelper parser) {
|
||||
ASTCompilationUnit compilationUnit = parser.parseResource("SwitchExpressions.java");
|
||||
List<ASTSwitchStatement> switchStatements = compilationUnit.findDescendantsOfType(ASTSwitchStatement.class);
|
||||
Assert.assertEquals(2, switchStatements.size());
|
||||
|
||||
Assert.assertTrue(switchStatements.get(0).getChild(0) instanceof ASTExpression);
|
||||
Assert.assertTrue(switchStatements.get(0).getChild(1) instanceof ASTSwitchArrowBranch);
|
||||
Assert.assertTrue(switchStatements.get(0).getChild(1).getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertEquals(3, switchStatements.get(0).getChild(1).getChild(0).getNumChildren());
|
||||
Assert.assertTrue(switchStatements.get(0).getChild(2).getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertFalse(((ASTSwitchLabel) switchStatements.get(0).getChild(2).getChild(0)).isDefault());
|
||||
Assert.assertEquals(1, switchStatements.get(0).getChild(2).getChild(0).getNumChildren());
|
||||
|
||||
Assert.assertTrue(switchStatements.get(1).getChild(3) instanceof ASTSwitchArrowBranch);
|
||||
Assert.assertTrue(switchStatements.get(1).getChild(3).getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(((ASTSwitchLabel) switchStatements.get(1).getChild(3).getChild(0)).isDefault());
|
||||
|
||||
List<ASTSwitchExpression> switchExpressions = compilationUnit.findDescendantsOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(4, switchExpressions.size());
|
||||
|
||||
Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getType());
|
||||
Assert.assertEquals(4, switchExpressions.get(0).findChildrenOfType(ASTSwitchArrowBranch.class).size());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getFirstChildOfType(ASTSwitchArrowBranch.class)
|
||||
.getFirstChildOfType(ASTExpression.class).getType());
|
||||
|
||||
Assert.assertTrue(switchExpressions.get(1).getChild(3) instanceof ASTSwitchArrowBranch);
|
||||
|
||||
Assert.assertEquals(Integer.TYPE, switchExpressions.get(2).getType());
|
||||
List<ASTYieldStatement> yields = switchExpressions.get(2).findDescendantsOfType(ASTYieldStatement.class);
|
||||
Assert.assertEquals(4, yields.size());
|
||||
Assert.assertEquals("SwitchExpressions.BAZ", yields.get(2).getImage());
|
||||
|
||||
Assert.assertEquals(String.class, switchExpressions.get(3).getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkYieldConditionalBehaviour() {
|
||||
checkYieldStatements(java14);
|
||||
}
|
||||
|
||||
private void checkYieldStatements(JavaParsingHelper parser) {
|
||||
ASTCompilationUnit compilationUnit = parser.parseResource("YieldStatements.java");
|
||||
List<ASTBlockStatement> blockStmts = compilationUnit.findDescendantsOfType(ASTBlockStatement.class);
|
||||
List<JavaNode> stmts = new ArrayList<>();
|
||||
// fetch the interesting node, on the java-grammar branch this is not needed
|
||||
for (int i = 0; i < blockStmts.size(); i++) {
|
||||
JavaNode child = blockStmts.get(i).getChild(0);
|
||||
|
||||
if (child instanceof ASTStatement) {
|
||||
stmts.add(child.getChild(0));
|
||||
} else {
|
||||
stmts.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals(18, stmts.size());
|
||||
|
||||
int i = 0;
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTLocalVariableDeclaration.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTIfStatement.class));
|
||||
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class));
|
||||
MatcherAssert.assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class));
|
||||
|
||||
Assert.assertEquals(i, stmts.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCaseLabels() {
|
||||
multipleCaseLabels(java14);
|
||||
}
|
||||
|
||||
private void multipleCaseLabels(JavaParsingHelper parser) {
|
||||
ASTCompilationUnit compilationUnit = parser.parseResource("MultipleCaseLabels.java");
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression);
|
||||
Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabel);
|
||||
ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class);
|
||||
Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchRules() {
|
||||
switchRules(java14);
|
||||
}
|
||||
|
||||
private void switchRules(JavaParsingHelper parser) {
|
||||
ASTCompilationUnit compilationUnit = parser.parseResource("SwitchRules.java");
|
||||
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
|
||||
Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression);
|
||||
Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchArrowBranch);
|
||||
ASTSwitchArrowBranch switchLabeledExpression = (ASTSwitchArrowBranch) switchStatement.getChild(1);
|
||||
Assert.assertEquals(2, switchLabeledExpression.getNumChildren());
|
||||
Assert.assertTrue(switchLabeledExpression.getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledExpression.getChild(1) instanceof ASTExpression);
|
||||
|
||||
ASTSwitchArrowBranch switchLabeledBlock = (ASTSwitchArrowBranch) switchStatement.getChild(4);
|
||||
Assert.assertEquals(2, switchLabeledBlock.getNumChildren());
|
||||
Assert.assertTrue(switchLabeledBlock.getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledBlock.getChild(1) instanceof ASTBlock);
|
||||
|
||||
ASTSwitchArrowBranch switchLabeledThrowStatement = (ASTSwitchArrowBranch) switchStatement.getChild(5);
|
||||
Assert.assertEquals(2, switchLabeledThrowStatement.getNumChildren());
|
||||
Assert.assertTrue(switchLabeledThrowStatement.getChild(0) instanceof ASTSwitchLabel);
|
||||
Assert.assertTrue(switchLabeledThrowStatement.getChild(1) instanceof ASTThrowStatement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleSwitchExpressions() {
|
||||
simpleSwitchExpressions(java14);
|
||||
}
|
||||
|
||||
private void simpleSwitchExpressions(JavaParsingHelper parser) {
|
||||
ASTCompilationUnit compilationUnit = parser.parseResource("SimpleSwitchExpressions.java");
|
||||
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
|
||||
Assert.assertEquals(6, switchExpression.getNumChildren());
|
||||
Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression);
|
||||
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchArrowBranch.class).size());
|
||||
|
||||
ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1);
|
||||
ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class);
|
||||
Assert.assertEquals(Integer.TYPE, localVarDecl.getType());
|
||||
Assert.assertEquals(Integer.TYPE, switchExpression.getType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
|
||||
import net.sourceforge.pmd.lang.java.BaseJavaTreeDumpTest;
|
||||
import net.sourceforge.pmd.lang.java.JavaParsingHelper;
|
||||
|
||||
/**
|
||||
* Tests new java14 standard features.
|
||||
*/
|
||||
public class Java14TreeDumpTest extends BaseJavaTreeDumpTest {
|
||||
|
||||
private final JavaParsingHelper java14 =
|
||||
JavaParsingHelper.DEFAULT.withDefaultVersion("14")
|
||||
.withResourceContext(Java14TreeDumpTest.class, "jdkversiontests/java14/");
|
||||
|
||||
private final JavaParsingHelper java13 = java14.withDefaultVersion("13");
|
||||
|
||||
@Override
|
||||
public @NonNull BaseParsingHelper<?, ?> getParser() {
|
||||
return java14;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests switch expressions with yield.
|
||||
*/
|
||||
@Test
|
||||
public void switchExpressions() {
|
||||
doTest("SwitchExpressions");
|
||||
}
|
||||
|
||||
/**
|
||||
* In java13, switch expressions are only available with preview.
|
||||
*/
|
||||
@Test
|
||||
public void switchExpressions13ShouldFail() {
|
||||
assertThrows(ParseException.class, () -> java13.parseResource("SwitchExpressions.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkYieldConditionalBehaviour() {
|
||||
doTest("YieldStatements");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCaseLabels() {
|
||||
doTest("MultipleCaseLabels");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchRules() {
|
||||
doTest("SwitchRules");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleSwitchExpressions() {
|
||||
doTest("SimpleSwitchExpressions");
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 30 of 50 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user