From 8b8cc6cddbf5af0c93c4ceffd015f6328c932149 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Fri, 31 Jul 2015 20:52:58 +0200 Subject: [PATCH] wip --- .../symbolsolver/JavaParserFacade.java | 43 +++++++++++++++- .../symbolsolver/model/Context.java | 4 +- .../symbolsolver/model/MethodDeclaration.java | 2 + .../symbolsolver/model/SymbolSolver.java | 9 ++-- .../symbolsolver/model/TypeDeclaration.java | 4 ++ .../{TypeReference.java => TypeUsage.java} | 7 ++- .../model/TypeUsageOfTypeDeclaration.java | 50 +++++++++++++++++++ .../ClassOrInterfaceDeclarationContext.java | 2 +- .../contexts/CompilationUnitContext.java | 2 +- .../contexts/MethodCallExprContext.java | 14 ++---- .../javaparser/contexts/MethodContext.java | 3 +- .../javaparser/contexts/StatementContext.java | 3 +- .../JavaParserClassDeclaration.java | 11 ++-- .../symbolsolver/model/ContextTest.java | 38 ++++++++++++-- 14 files changed, 155 insertions(+), 37 deletions(-) rename src/main/java/me/tomassetti/symbolsolver/model/{TypeReference.java => TypeUsage.java} (82%) create mode 100644 src/main/java/me/tomassetti/symbolsolver/model/TypeUsageOfTypeDeclaration.java diff --git a/src/main/java/me/tomassetti/symbolsolver/JavaParserFacade.java b/src/main/java/me/tomassetti/symbolsolver/JavaParserFacade.java index a826b39718..10fe7a7fdc 100644 --- a/src/main/java/me/tomassetti/symbolsolver/JavaParserFacade.java +++ b/src/main/java/me/tomassetti/symbolsolver/JavaParserFacade.java @@ -1,11 +1,17 @@ package me.tomassetti.symbolsolver; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; -import javassist.compiler.ast.Expr; import me.tomassetti.symbolsolver.model.*; import me.tomassetti.symbolsolver.model.MethodDeclaration; +import me.tomassetti.symbolsolver.model.javaparser.JavaParserFactory; +import me.tomassetti.symbolsolver.model.javaparser.UnsolvedSymbolException; +import me.tomassetti.symbolsolver.model.javaparser.contexts.MethodCallExprContext; + +import java.util.ArrayList; +import java.util.List; /** * Class to be used by final users to solve symbols for JavaParser ASTs. @@ -39,4 +45,39 @@ public SymbolReference solve(MethodCallExpr methodCallExpr) { throw new UnsupportedOperationException(); } + /** + * Should return more like a TypeApplication: a TypeDeclaration and possible parameters or array modifiers. + * @return + */ + public TypeUsage getType(Node node) { + if (node instanceof NameExpr) { + NameExpr nameExpr = (NameExpr) node; + SymbolReference ref = new SymbolSolver(typeSolver).solveSymbol(nameExpr.getName(), nameExpr); + if (!ref.isSolved()) { + throw new UnsolvedSymbolException(JavaParserFactory.getContext(nameExpr), nameExpr.getName()); + } + return new TypeUsageOfTypeDeclaration(ref.getCorrespondingDeclaration().getType()); + } else if (node instanceof MethodCallExpr) { + // first solve the method + SymbolReference ref = new JavaParserFacade(typeSolver).solveMethod((MethodCallExpr)node); + if (!ref.isSolved()) { + throw new UnsolvedSymbolException(JavaParserFactory.getContext(node), ((MethodCallExpr)node).getName()); + } + return new TypeUsageOfTypeDeclaration(ref.getCorrespondingDeclaration().getReturnType()); + // the type is the return type of the method + } else { + throw new UnsupportedOperationException(node.getClass().getCanonicalName()); + } + } + + private SymbolReference solveMethod(MethodCallExpr methodCallExpr) { + List params = new ArrayList<>(); + if (methodCallExpr.getArgs() != null) { + for (Expression param : methodCallExpr.getArgs()) { + params.add(getType(param)); + } + } + return new MethodCallExprContext(methodCallExpr).solveMethod(methodCallExpr.getName(), params, typeSolver); + } + } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/Context.java b/src/main/java/me/tomassetti/symbolsolver/model/Context.java index 79e621b021..9b29c112ad 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/Context.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/Context.java @@ -1,7 +1,5 @@ package me.tomassetti.symbolsolver.model; -import com.github.javaparser.ast.type.Type; - import java.util.List; /** @@ -10,7 +8,7 @@ public interface Context { public SymbolReference solveSymbol(String name, TypeSolver typeSolver); public SymbolReference solveType(String name, TypeSolver typeSolver); - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver); + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver); public Context getParent(); public boolean isRoot(); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/MethodDeclaration.java b/src/main/java/me/tomassetti/symbolsolver/model/MethodDeclaration.java index c8fe3d552d..e9effddc99 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/MethodDeclaration.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/MethodDeclaration.java @@ -5,4 +5,6 @@ */ public interface MethodDeclaration extends SymbolDeclaration { TypeDeclaration getType(); + + TypeDeclaration getReturnType(); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/SymbolSolver.java b/src/main/java/me/tomassetti/symbolsolver/model/SymbolSolver.java index 9397fe4b25..74bb1c23ae 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/SymbolSolver.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/SymbolSolver.java @@ -1,9 +1,6 @@ package me.tomassetti.symbolsolver.model; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.body.Parameter; -import com.github.javaparser.ast.body.TypeDeclaration; -import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; @@ -41,11 +38,11 @@ public SymbolReference solveTy return solveType(name, JavaParserFactory.getContext(node)); } - public SymbolReference solveMethod(String methodName, List params, Context context) { + public SymbolReference solveMethod(String methodName, List params, Context context) { return context.solveMethod(methodName, params, typeSolver); } - public SymbolReference solveMethod(String methodName, List params, Node node) { + public SymbolReference solveMethod(String methodName, List params, Node node) { return solveMethod(methodName, params, JavaParserFactory.getContext(node)); } @@ -61,7 +58,7 @@ public me.tomassetti.symbolsolver.model.TypeDeclaration solveType(Type type) { throw new UnsolvedSymbolException(JavaParserFactory.getContext(type), classType.getName()); } if (!(ref.getCorrespondingDeclaration().isType())) { - throw new IllegalStateException(); + throw new IllegalStateException(ref.getCorrespondingDeclaration().toString()); } return ref.getCorrespondingDeclaration().asTypeDeclaration(); } else { diff --git a/src/main/java/me/tomassetti/symbolsolver/model/TypeDeclaration.java b/src/main/java/me/tomassetti/symbolsolver/model/TypeDeclaration.java index 443e1a3b3a..65fa20a753 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/TypeDeclaration.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/TypeDeclaration.java @@ -1,9 +1,13 @@ package me.tomassetti.symbolsolver.model; +import java.util.List; + /** * Created by federico on 31/07/15. */ public interface TypeDeclaration extends SymbolDeclaration { String getQualifiedName(); Context getContext(); + + SymbolReference solveMethod(String name, List parameterTypes); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/TypeReference.java b/src/main/java/me/tomassetti/symbolsolver/model/TypeUsage.java similarity index 82% rename from src/main/java/me/tomassetti/symbolsolver/model/TypeReference.java rename to src/main/java/me/tomassetti/symbolsolver/model/TypeUsage.java index 0e06a570f8..072268dc36 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/TypeReference.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/TypeUsage.java @@ -1,5 +1,7 @@ package me.tomassetti.symbolsolver.model; +import java.util.List; + /** * Reference to a type. A TypeRef could be a primitive type or a reference type (enum, class, interface). * In the later case it could take type parameters (other TypeRefs). It could also be a TypeVariable, like in: @@ -8,7 +10,7 @@ * * where B is a TypeVariable. It could also be Wildcard Type, possibly with constraints. */ -public interface TypeReference { +public interface TypeUsage { boolean isArray(); boolean isPrimitive(); @@ -21,7 +23,7 @@ public interface TypeReference { String getTypeName(); - TypeReference getBaseType(); + TypeUsage getBaseType(); /* Represent the position of the reference, it is used when solving symbols * because a reference to a class A could be related to different classes depending on the position @@ -29,4 +31,5 @@ public interface TypeReference { */ Context getContext(); + SymbolReference solveMethod(String name, List parameterTypes); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/TypeUsageOfTypeDeclaration.java b/src/main/java/me/tomassetti/symbolsolver/model/TypeUsageOfTypeDeclaration.java new file mode 100644 index 0000000000..011a3ccc61 --- /dev/null +++ b/src/main/java/me/tomassetti/symbolsolver/model/TypeUsageOfTypeDeclaration.java @@ -0,0 +1,50 @@ +package me.tomassetti.symbolsolver.model; + +import java.util.List; + +/** + * Created by federico on 31/07/15. + */ +public class TypeUsageOfTypeDeclaration implements TypeUsage { + + private TypeDeclaration typeDeclaration; + + public TypeUsageOfTypeDeclaration(TypeDeclaration typeDeclaration) { + this.typeDeclaration = typeDeclaration; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isPrimitive() { + return false; + } + + @Override + public boolean isReferenceType() { + return true; + } + + @Override + public String getTypeName() { + return typeDeclaration.getName(); + } + + @Override + public TypeUsage getBaseType() { + throw new UnsupportedOperationException(); + } + + @Override + public Context getContext() { + throw new UnsupportedOperationException(); + } + + @Override + public SymbolReference solveMethod(String name, List parameterTypes) { + return typeDeclaration.solveMethod(name, parameterTypes); + } +} diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/ClassOrInterfaceDeclarationContext.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/ClassOrInterfaceDeclarationContext.java index 6577b176d1..1eff17ed9e 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/ClassOrInterfaceDeclarationContext.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/ClassOrInterfaceDeclarationContext.java @@ -61,7 +61,7 @@ public SymbolReference solveType(String name, TypeSolver typeSo } @Override - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { for (BodyDeclaration member : this.wrappedNode.getMembers()) { if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { com.github.javaparser.ast.body.MethodDeclaration method = (com.github.javaparser.ast.body.MethodDeclaration)member; diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/CompilationUnitContext.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/CompilationUnitContext.java index 7ac790c5fe..0f12161574 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/CompilationUnitContext.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/CompilationUnitContext.java @@ -83,7 +83,7 @@ private static boolean isQualifiedName(String name) { } @Override - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { throw new UnsupportedOperationException(); } } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodCallExprContext.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodCallExprContext.java index 6c97c1660e..430192ab6e 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodCallExprContext.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodCallExprContext.java @@ -4,7 +4,6 @@ import me.tomassetti.symbolsolver.JavaParserFacade; import me.tomassetti.symbolsolver.model.*; import me.tomassetti.symbolsolver.model.javaparser.JavaParserFactory; -import me.tomassetti.symbolsolver.model.javaparser.UnsolvedSymbolException; import java.util.List; @@ -28,17 +27,10 @@ public SymbolReference solveType(String name, TypeSolver typeSo } @Override - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { if (wrappedNode.getScope() != null) { - // TODO resolve the scope and get a context from there - SymbolReference declScope = new JavaParserFacade(typeSolver).solve(wrappedNode.getScope()); - if (declScope.isSolved()) { - TypeDeclaration typeOfDeclScope = declScope.getCorrespondingDeclaration().getType(); - return typeOfDeclScope.getContext().solveMethod(name, parameterTypes, typeSolver); - } else { - // TODO this should be improved to indicate that is the scope that has not been solved - throw new UnsolvedSymbolException(this, name); - } + TypeUsage typeOfScope = new JavaParserFacade(typeSolver).getType(wrappedNode.getScope()); + return typeOfScope.solveMethod(name, parameterTypes); } else { return JavaParserFactory.getContext(wrappedNode.getParentNode()).solveSymbol(name, typeSolver); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodContext.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodContext.java index 56ac7469d6..764d82e06c 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodContext.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/MethodContext.java @@ -4,7 +4,6 @@ import com.github.javaparser.ast.body.MethodDeclaration; import me.tomassetti.symbolsolver.model.*; import me.tomassetti.symbolsolver.model.javaparser.JavaParserFactory; -import me.tomassetti.symbolsolver.model.javaparser.contexts.AbstractJavaParserContext; import java.util.List; @@ -38,7 +37,7 @@ public SymbolReference solveTy } @Override - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { if (wrappedNode.getName().equals(name)) { // TODO understand if signature is compatible throw new UnsupportedOperationException(); diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/StatementContext.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/StatementContext.java index 16f445b32f..8ff2014635 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/StatementContext.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/contexts/StatementContext.java @@ -6,7 +6,6 @@ import me.tomassetti.symbolsolver.model.MethodDeclaration; import me.tomassetti.symbolsolver.model.TypeDeclaration; import me.tomassetti.symbolsolver.model.javaparser.JavaParserFactory; -import me.tomassetti.symbolsolver.model.javaparser.contexts.AbstractJavaParserContext; import java.util.List; @@ -48,7 +47,7 @@ public SymbolReference solveSymbol(String name, TypeSolver typeSolver) { } @Override - public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { + public SymbolReference solveMethod(String name, List parameterTypes, TypeSolver typeSolver) { return getParent().solveMethod(name, parameterTypes, typeSolver); } diff --git a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/declarations/JavaParserClassDeclaration.java b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/declarations/JavaParserClassDeclaration.java index c354c05f3e..d57245cb13 100644 --- a/src/main/java/me/tomassetti/symbolsolver/model/javaparser/declarations/JavaParserClassDeclaration.java +++ b/src/main/java/me/tomassetti/symbolsolver/model/javaparser/declarations/JavaParserClassDeclaration.java @@ -1,11 +1,11 @@ package me.tomassetti.symbolsolver.model.javaparser.declarations; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import me.tomassetti.symbolsolver.model.ClassDeclaration; -import me.tomassetti.symbolsolver.model.Context; -import me.tomassetti.symbolsolver.model.TypeDeclaration; +import me.tomassetti.symbolsolver.model.*; import me.tomassetti.symbolsolver.model.javaparser.JavaParserFactory; +import java.util.List; + /** * Created by federico on 30/07/15. */ @@ -22,6 +22,11 @@ public Context getContext() { return JavaParserFactory.getContext(wrappedNode); } + @Override + public SymbolReference solveMethod(String name, List parameterTypes) { + throw new UnsupportedOperationException(); + } + @Override public String getName() { return wrappedNode.getName(); diff --git a/src/test/java/me/tomassetti/symbolsolver/model/ContextTest.java b/src/test/java/me/tomassetti/symbolsolver/model/ContextTest.java index 91bde4b092..76934f499b 100644 --- a/src/test/java/me/tomassetti/symbolsolver/model/ContextTest.java +++ b/src/test/java/me/tomassetti/symbolsolver/model/ContextTest.java @@ -186,16 +186,13 @@ public void resolveReferenceToMethod() throws ParseException { expect(compilationUnit.isType()).andReturn(true); expect(compilationUnit.asTypeDeclaration()).andReturn(compilationUnit); expect(compilationUnit.getContext()).andReturn(compilationUnitCtx); + expect(compilationUnit.solveMethod("getTypes", Collections.emptyList())).andReturn(SymbolReference.solved(getTypes)); expect(getTypes.getType()).andReturn(compilationUnit); TypeSolver typeSolver = createMock(TypeSolver.class); expect(typeSolver.tryToSolveType("com.github.javaparser.ast.CompilationUnit")).andReturn(SymbolReference.solved(compilationUnit)); - expect(compilationUnitCtx.solveMethod("getTypes", Collections.emptyList(), typeSolver)).andReturn(SymbolReference.solved(getTypes)); + //expect(compilationUnitCtx.solveMethod("getTypes", Collections.emptyList(), typeSolver)).andReturn(SymbolReference.solved(getTypes)); SymbolSolver symbolSolver = new SymbolSolver(typeSolver); replay(typeSolver, compilationUnit, compilationUnitCtx, getTypes); - Node ctx = callToGetTypes; - System.out.println("CTX "+ctx+" "+ctx.getClass()); - ctx = ctx.getParentNode(); - System.out.println("SCOPE "+callToGetTypes.getScope()+" "+callToGetTypes.getScope().getClass()); SymbolReference ref = symbolSolver.solveMethod("getTypes", Collections.emptyList(), callToGetTypes); assertEquals(true, ref.isSolved()); @@ -205,4 +202,35 @@ public void resolveReferenceToMethod() throws ParseException { verify(typeSolver); } + /*@Test + public void resolveCascadeOfReferencesToMethod() throws ParseException { + CompilationUnit cu = parseSample("Navigator"); + ClassOrInterfaceDeclaration referencesToField = Navigator.demandClass(cu, "Navigator"); + MethodDeclaration method = Navigator.demandMethod(referencesToField, "findType"); + MethodCallExpr callToStream = Navigator.findMethodCall(method, "stream"); + + AVOID MOCKING SO MUCH + + ClassDeclaration compilationUnit = createMock(ClassDeclaration.class); + //expect(compilationUnit.getName()).andReturn("CompilationUnit"); + //expect(compilationUnit.getQualifiedName()).andReturn("com.github.javaparser.ast.CompilationUnit"); + expect(compilationUnit.isType()).andReturn(true); + expect(compilationUnit.asTypeDeclaration()).andReturn(compilationUnit); + //expect(compilationUnit.getContext()).andReturn(compilationUnitCtx); + //expect(getTypes.getType()).andReturn(compilationUnit); + TypeSolver typeSolver = createMock(TypeSolver.class); + expect(typeSolver.tryToSolveType("com.github.javaparser.ast.CompilationUnit")).andReturn(SymbolReference.solved(compilationUnit)); + //expect(compilationUnitCtx.solveMethod("getTypes", Collections.emptyList(), typeSolver)).andReturn(SymbolReference.solved(getTypes)); + SymbolSolver symbolSolver = new SymbolSolver(typeSolver); + replay(typeSolver, compilationUnit); + //replay(typeSolver, compilationUnit, compilationUnitCtx, getTypes); + SymbolReference ref = symbolSolver.solveMethod("stream", Collections.emptyList(), callToStream); + + assertEquals(true, ref.isSolved()); + assertEquals("stream", ref.getCorrespondingDeclaration().getName()); + assertEquals("java.util.Collection", ref.getCorrespondingDeclaration().getType().getQualifiedName()); + + verify(typeSolver); + }*/ + }