Remove old symbol table

This commit is contained in:
Clément Fournier committed 2022-03-10 15:11:18 +01:00
1 parent aead02ba89
commit 07549b1283
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);
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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
@@ -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;
}
}
@@ -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());
}
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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
@@ -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();
}
@@ -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