Skip to content

Commit

Permalink
Cache results in AST instead of a map
Browse files Browse the repository at this point in the history
  • Loading branch information
matozoid committed Oct 12, 2018
1 parent 3f74f84 commit 949e006
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 69 deletions.
18 changes: 13 additions & 5 deletions javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
Expand Up @@ -39,6 +39,7 @@
import com.github.javaparser.printer.PrettyPrinter; import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.PrettyPrinterConfiguration; import com.github.javaparser.printer.PrettyPrinterConfiguration;
import com.github.javaparser.resolution.SymbolResolver; import com.github.javaparser.resolution.SymbolResolver;
import com.github.javaparser.resolution.types.ResolvedType;


import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
Expand All @@ -53,10 +54,6 @@
import static java.util.Spliterator.DISTINCT; import static java.util.Spliterator.DISTINCT;
import static java.util.Spliterator.NONNULL; import static java.util.Spliterator.NONNULL;


import com.github.javaparser.metamodel.NodeMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.ast.Node;

/** /**
* Base class for all nodes of the abstract syntax tree. * Base class for all nodes of the abstract syntax tree.
* <h2>Construction</h2> * <h2>Construction</h2>
Expand Down Expand Up @@ -477,12 +474,23 @@ public <M> void setData(DataKey<M> key, M object) {


/** /**
* @return does this node have data for this key? * @return does this node have data for this key?
* @see DataKey
*/ */
public boolean containsData(DataKey<?> key) { public boolean containsData(DataKey<?> key) {
if (data == null) { if (data == null) {
return false; return false;
} }
return data.get(key) != null; return data.containsKey(key);
}

/**
* Remove data by key.
* @see DataKey
*/
public void removeData(DataKey<ResolvedType> key){
if(data!=null){
data.remove(key);
}
} }


/** /**
Expand Down
Expand Up @@ -17,10 +17,13 @@
package com.github.javaparser.symbolsolver.javaparsermodel; package com.github.javaparser.symbolsolver.javaparsermodel;


import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.DataKey;
import com.github.javaparser.ast.Node; import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration; import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
import com.github.javaparser.ast.type.*; import com.github.javaparser.ast.type.*;
Expand All @@ -30,10 +33,12 @@
import com.github.javaparser.resolution.types.*; import com.github.javaparser.resolution.types.*;
import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.contexts.FieldAccessContext; import com.github.javaparser.symbolsolver.javaparsermodel.contexts.FieldAccessContext;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnonymousClassDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeVariableDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.*; import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic; import com.github.javaparser.symbolsolver.resolution.ConstructorResolutionLogic;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver; import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
Expand All @@ -51,12 +56,15 @@
*/ */
public class JavaParserFacade { public class JavaParserFacade {


private static Map<TypeSolver, JavaParserFacade> instances = new WeakHashMap<>(); private static final DataKey<ResolvedType> TYPE_WITH_LAMBDAS_RESOLVED = new DataKey<ResolvedType>() {
private TypeSolver typeSolver; };
private SymbolSolver symbolSolver; private static final DataKey<ResolvedType> TYPE_WITHOUT_LAMBDAS_RESOLVED = new DataKey<ResolvedType>() {
private Map<Node, ResolvedType> cacheWithLambdasSolved = new IdentityHashMap<>(); };
private Map<Node, ResolvedType> cacheWithoutLambdasSolved = new IdentityHashMap<>();
private TypeExtractor typeExtractor; private static final Map<TypeSolver, JavaParserFacade> instances = new WeakHashMap<>();
private final TypeSolver typeSolver;
private final TypeExtractor typeExtractor;
private final SymbolSolver symbolSolver;


private JavaParserFacade(TypeSolver typeSolver) { private JavaParserFacade(TypeSolver typeSolver) {
this.typeSolver = typeSolver.getRoot(); this.typeSolver = typeSolver.getRoot();
Expand Down Expand Up @@ -255,27 +263,27 @@ public SymbolReference<ResolvedValueDeclaration> solve(FieldAccessExpr fieldAcce


/** /**
* Get the type associated with the node. * Get the type associated with the node.
* * <p>
* This method was originally intended to get the type of a value: any value has a type. * This method was originally intended to get the type of a value: any value has a type.
* * <p>
* For example: * For example:
* <code> * <code>
* int foo(int a) { * int foo(int a) {
* return a; // when getType is invoked on "a" it returns the type "int" * return a; // when getType is invoked on "a" it returns the type "int"
* } * }
* </code> * </code>
* * <p>
* Now, users started using also of names of types itself, which do not have a type. * Now, users started using also of names of types itself, which do not have a type.
* * <p>
* For example: * For example:
* <code> * <code>
* class A { * class A {
* int foo(int a) { * int foo(int a) {
* return A.someStaticField; // when getType is invoked on "A", which represents a class, it returns * return A.someStaticField; // when getType is invoked on "A", which represents a class, it returns
* // the type "A" itself while it used to throw UnsolvedSymbolException * // the type "A" itself while it used to throw UnsolvedSymbolException
* } * }
* </code> * </code>
* * <p>
* To accomodate this usage and avoid confusion this method return * To accomodate this usage and avoid confusion this method return
* the type itself when used on the name of type. * the type itself when used on the name of type.
*/ */
Expand All @@ -284,7 +292,7 @@ public ResolvedType getType(Node node) {
return getType(node, true); return getType(node, true);
} catch (UnsolvedSymbolException e) { } catch (UnsolvedSymbolException e) {
if (node instanceof NameExpr) { if (node instanceof NameExpr) {
NameExpr nameExpr = (NameExpr)node; NameExpr nameExpr = (NameExpr) node;
SymbolReference<ResolvedTypeDeclaration> typeDeclaration = JavaParserFactory.getContext(node, typeSolver) SymbolReference<ResolvedTypeDeclaration> typeDeclaration = JavaParserFactory.getContext(node, typeSolver)
.solveType(nameExpr.getNameAsString(), typeSolver); .solveType(nameExpr.getNameAsString(), typeSolver);
if (typeDeclaration.isSolved() && typeDeclaration.getCorrespondingDeclaration() instanceof ResolvedReferenceTypeDeclaration) { if (typeDeclaration.isSolved() && typeDeclaration.getCorrespondingDeclaration() instanceof ResolvedReferenceTypeDeclaration) {
Expand All @@ -298,66 +306,49 @@ public ResolvedType getType(Node node) {


public ResolvedType getType(Node node, boolean solveLambdas) { public ResolvedType getType(Node node, boolean solveLambdas) {
if (solveLambdas) { if (solveLambdas) {
if (!cacheWithLambdasSolved.containsKey(node)) { if (!node.containsData(TYPE_WITH_LAMBDAS_RESOLVED)) {
ResolvedType res = getTypeConcrete(node, solveLambdas); ResolvedType res = getTypeConcrete(node, solveLambdas);


cacheWithLambdasSolved.put(node, res); node.setData(TYPE_WITH_LAMBDAS_RESOLVED, res);


boolean secondPassNecessary = false; boolean secondPassNecessary = false;
if (node instanceof MethodCallExpr) { if (node instanceof MethodCallExpr) {
MethodCallExpr methodCallExpr = (MethodCallExpr) node; MethodCallExpr methodCallExpr = (MethodCallExpr) node;
for (Node arg : methodCallExpr.getArguments()) { for (Node arg : methodCallExpr.getArguments()) {
if (!cacheWithLambdasSolved.containsKey(arg)) { if (!arg.containsData(TYPE_WITH_LAMBDAS_RESOLVED)) {
getType(arg, true); getType(arg, true);
secondPassNecessary = true; secondPassNecessary = true;
} }
} }
} }
if (secondPassNecessary) { if (secondPassNecessary) {
cacheWithLambdasSolved.remove(node); node.removeData(TYPE_WITH_LAMBDAS_RESOLVED);
cacheWithLambdasSolved.put(node, getType(node, true)); ResolvedType type = getType(node, true);
node.setData(TYPE_WITH_LAMBDAS_RESOLVED, type);

} }
Log.trace("getType on %s -> %s" ,node, res); Log.trace("getType on %s -> %s" ,node, res);
} }
return cacheWithLambdasSolved.get(node); return node.getData(TYPE_WITH_LAMBDAS_RESOLVED);
} else { } else {
Optional<ResolvedType> res = find(cacheWithLambdasSolved, node); Optional<ResolvedType> res = find(TYPE_WITH_LAMBDAS_RESOLVED, node);
if (res.isPresent()) { if (res.isPresent()) {
return res.get(); return res.get();
} }
res = find(cacheWithoutLambdasSolved, node); res = find(TYPE_WITHOUT_LAMBDAS_RESOLVED, node);
if (!res.isPresent()) { if (!res.isPresent()) {
ResolvedType resType = getTypeConcrete(node, solveLambdas); ResolvedType resType = getTypeConcrete(node, solveLambdas);
cacheWithoutLambdasSolved.put(node, resType); node.setData(TYPE_WITHOUT_LAMBDAS_RESOLVED, resType);
Log.trace("getType on %s (no solveLambdas) -> %s", node, res); Log.trace("getType on %s (no solveLambdas) -> %s", node, res);
return resType; return resType;
} }
return res.get(); return res.get();
} }
} }


private Optional<ResolvedType> find(Map<Node, ResolvedType> map, Node node) { private Optional<ResolvedType> find(DataKey<ResolvedType> dataKey, Node node) {
if (map.containsKey(node)) { if (node.containsData(dataKey)) {
return Optional.of(map.get(node)); return Optional.of(node.getData(dataKey));
}
if (node instanceof LambdaExpr) {
return find(map, (LambdaExpr) node);
} else {
return Optional.empty();
}
}

/**
* For some reasons LambdaExprs are duplicate and the equals method is not implemented correctly.
*/
private Optional<ResolvedType> find(Map<Node, ResolvedType> map, LambdaExpr lambdaExpr) {
for (Node key : map.keySet()) {
if (key instanceof LambdaExpr) {
LambdaExpr keyLambdaExpr = (LambdaExpr) key;
if (keyLambdaExpr.toString().equals(lambdaExpr.toString()) && requireParentNode(keyLambdaExpr) == requireParentNode(lambdaExpr)) {
return Optional.of(map.get(keyLambdaExpr));
}
}
} }
return Optional.empty(); return Optional.empty();
} }
Expand Down
Expand Up @@ -22,27 +22,17 @@
import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.type.TypeParameter; import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.core.resolution.Context; import com.github.javaparser.symbolsolver.core.resolution.Context;
import com.github.javaparser.symbolsolver.javaparsermodel.contexts.*; import com.github.javaparser.symbolsolver.javaparsermodel.contexts.*;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnnotationDeclaration; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.*;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeParameter;
import com.github.javaparser.symbolsolver.javaparsermodel.declarators.FieldSymbolDeclarator; import com.github.javaparser.symbolsolver.javaparsermodel.declarators.FieldSymbolDeclarator;
import com.github.javaparser.symbolsolver.javaparsermodel.declarators.NoSymbolDeclarator; import com.github.javaparser.symbolsolver.javaparsermodel.declarators.NoSymbolDeclarator;
import com.github.javaparser.symbolsolver.javaparsermodel.declarators.ParameterSymbolDeclarator; import com.github.javaparser.symbolsolver.javaparsermodel.declarators.ParameterSymbolDeclarator;
import com.github.javaparser.symbolsolver.javaparsermodel.declarators.VariableSymbolDeclarator; import com.github.javaparser.symbolsolver.javaparsermodel.declarators.VariableSymbolDeclarator;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;


import static com.github.javaparser.symbolsolver.javaparser.Navigator.getParentNode;
import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode; import static com.github.javaparser.symbolsolver.javaparser.Navigator.requireParentNode;


/** /**
Expand Down
Expand Up @@ -16,7 +16,6 @@


package com.github.javaparser.symbolsolver.resolution; package com.github.javaparser.symbolsolver.resolution;


import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.Expression;
Expand All @@ -27,6 +26,7 @@
import com.github.javaparser.symbolsolver.javaparser.Navigator; import com.github.javaparser.symbolsolver.javaparser.Navigator;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import com.github.javaparser.utils.Log;
import org.junit.Test; import org.junit.Test;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
Expand Down

0 comments on commit 949e006

Please sign in to comment.