Skip to content

Commit

Permalink
Fixed issue #2909 + Added general test
Browse files Browse the repository at this point in the history
  • Loading branch information
deadlocklogic committed Nov 17, 2020
1 parent 045575a commit 5419a83
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.github.javaparser.ast.expr.ThisExpr;
import com.github.javaparser.ast.expr.TypeExpr;
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt;
import com.github.javaparser.ast.type.ArrayType;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.PrimitiveType;
Expand Down Expand Up @@ -575,6 +576,47 @@ protected TypeDeclaration<?> findContainingTypeDecl(Node node) {

}

protected TypeDeclaration<?> findContainingTypeDecl(Node node, String className) {
return findContainingTypeDecl(node, className, node.findCompilationUnit().map(cu -> cu.getPackageDeclaration().map(pd -> pd.getNameAsString()).orElse("")), "", null);
}

protected TypeDeclaration<?> findContainingTypeDecl(Node node, String className, Optional<String> packageName, String pseudoName, TypeDeclaration<?> result) {
if (node instanceof TypeDeclaration) {
boolean flagMatches = false;
TypeDeclaration<?> typeDecl = (TypeDeclaration<?>) node;
if (typeDecl.getFullyQualifiedName().isPresent()) {
if (typeDecl.getFullyQualifiedName().get().equals(className)) {
return typeDecl;
} else {
if (packageName.isPresent() && typeDecl.getFullyQualifiedName().get().equals(packageName.get() + "." + className)) {
return typeDecl;
} else {
if (pseudoName.isEmpty()) {
result = typeDecl;
pseudoName = typeDecl.getNameAsString();
} else {
pseudoName = typeDecl.getNameAsString() + "." + pseudoName;
}
if (className.endsWith(pseudoName)) {
if (className.equals(pseudoName)) {
return result;
}
flagMatches = true;
}
}
}
}
if (!flagMatches) {
pseudoName = "";
}
} else if (node instanceof LocalClassDeclarationStmt) {
pseudoName = "";
} else if (node instanceof ObjectCreationExpr) {
pseudoName = "";
}
return findContainingTypeDecl(demandParentNode(node), className, packageName, pseudoName, result);
}

/**
* Where a node has an interface/class/enum declaration -- or an object creation expression (anonymous inner class)
* -- as its ancestor, return the nearest one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,17 @@ public ResolvedType visit(ThisExpr node, Boolean solveLambdas) {
if (node.getTypeName().isPresent()) {
// Get the class name
String className = node.getTypeName().get().asString();
// Attempt to resolve using a typeSolver
SymbolReference<ResolvedReferenceTypeDeclaration> clazz = typeSolver.tryToSolveType(className);
if (clazz.isSolved()) {
return new ReferenceTypeImpl(clazz.getCorrespondingDeclaration(), typeSolver);
}
// Attempt to resolve locally in Compilation unit
Optional<CompilationUnit> cu = node.findAncestor(CompilationUnit.class);
if (cu.isPresent()) {
// Try to resolve the class name from the compilation unit (the last statement is considered to be the most relevant)
List<ClassOrInterfaceDeclaration> localDeclarations = cu.get().getLocalDeclarationFromClassname(className);
if (!localDeclarations.isEmpty()) {
return new ReferenceTypeImpl(facade.getTypeDeclaration(localDeclarations.get(localDeclarations.size()-1)), typeSolver);
try {
return new ReferenceTypeImpl(facade.getTypeDeclaration(facade.findContainingTypeDecl(node, className)), typeSolver);
} catch (Exception e) {
// Attempt to resolve using a typeSolver
SymbolReference<ResolvedReferenceTypeDeclaration> clazz = typeSolver.tryToSolveType(className);
if (clazz.isSolved()) {
return new ReferenceTypeImpl(clazz.getCorrespondingDeclaration(), typeSolver);
}
}
return new ReferenceTypeImpl(facade.getTypeDeclaration(facade.findContainingTypeDeclOrObjectCreationExpr(node, className)), typeSolver);
throw new IllegalStateException("Couldn't resolve typeName of ThisExpr: " + className);
}
return new ReferenceTypeImpl(facade.getTypeDeclaration(facade.findContainingTypeDeclOrObjectCreationExpr(node)), typeSolver);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.nio.file.Path;
import java.util.List;

import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import org.junit.jupiter.api.Test;

import com.github.javaparser.ParserConfiguration;
Expand All @@ -21,35 +24,35 @@ void testResolvingLocallyFromCompleteReferenceToInnerClass() {
config.setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver(false)));
StaticJavaParser.setConfiguration(config);

String s =
"public class Program {\n" +
"\n" +
" public class OuterClass {\n" +
" int field = 0;\n" +
"\n" +
" public class InnerClass {\n" +
" InnerClass() {\n" +
" OuterClass outer = Program.OuterClass.this;\n" +
" Program.OuterClass.this.field = 1;\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
String s =
"public class Program {\n" +
"\n" +
" public class OuterClass {\n" +
" int field = 0;\n" +
"\n" +
" public class InnerClass {\n" +
" InnerClass() {\n" +
" OuterClass outer = Program.OuterClass.this;\n" +
" Program.OuterClass.this.field = 1;\n" +
" }\n" +
" }\n" +
" }\n" +
"}";

CompilationUnit cu = StaticJavaParser.parse(s);
List<ThisExpr> exprs = cu.findAll(ThisExpr.class);
exprs.forEach(expr-> {
assertEquals("Program.OuterClass",expr.calculateResolvedType().describe());
});
}

@Test
void testResolvingLocallyFromPartialReferenceToInnerClass() {
ParserConfiguration config = new ParserConfiguration();
config.setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver(false)));
StaticJavaParser.setConfiguration(config);

String s =
String s =
"public class Program {\n" +
"\n" +
" public class OuterClass {\n" +
Expand All @@ -63,18 +66,21 @@ void testResolvingLocallyFromPartialReferenceToInnerClass() {
" }\n" +
" }\n" +
"}";

CompilationUnit cu = StaticJavaParser.parse(s);
List<ThisExpr> exprs = cu.findAll(ThisExpr.class);
exprs.forEach(expr-> {
assertEquals("Program.OuterClass",expr.calculateResolvedType().describe());
});
}

@Test
void test() {
void test1() {
Path rootSourceDir = adaptPath("src/test/resources/issue2909");

ParserConfiguration config = new ParserConfiguration();
config.setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver(false)));
CombinedTypeSolver cts = new CombinedTypeSolver(new ReflectionTypeSolver(false), new JavaParserTypeSolver(rootSourceDir.toFile()));
config.setSymbolResolver(new JavaSymbolSolver(cts));
StaticJavaParser.setConfiguration(config);

String s = "package test;\n" +
Expand Down Expand Up @@ -105,7 +111,53 @@ void test() {
" }\n" +
" }\n" +
"}";


CompilationUnit cu = StaticJavaParser.parse(s);
List<ThisExpr> exprs = cu.findAll(ThisExpr.class);
exprs.forEach(expr-> {
assertEquals("test.Program.FarOuterClass.OuterClass",expr.calculateResolvedType().describe());
System.out.println(String.format("%s is resolved to %s", expr.toString(), expr.calculateResolvedType().describe()));
});
}

@Test
void test2() {
Path rootSourceDir = adaptPath("src/test/resources/issue2909");

ParserConfiguration config = new ParserConfiguration();
CombinedTypeSolver cts = new CombinedTypeSolver(new ReflectionTypeSolver(false), new JavaParserTypeSolver(rootSourceDir.toFile()));
config.setSymbolResolver(new JavaSymbolSolver(cts));
StaticJavaParser.setConfiguration(config);

String s = "package test;\n" +
"\n" +
"public class Program {\n" +
"\n" +
" public class FarOuterClass {\n" +
"\n" +
" public class OuterClass {\n" +
" int field = 0;\n" +
"\n" +
" public class InnerClass {\n" +
" InnerClass() {\n" +
" // Different cases to refer to enclosing type\n" +
" OuterClass outer1 = OuterClass.this; // case1\n" +
" OuterClass.this.field = 1; // case1\n" +
" OuterClass outer2 = FarOuterClass.OuterClass.this; // case2\n" +
" FarOuterClass.OuterClass.this.field = 1; // case2\n" +
" OuterClass outer3 = Program.FarOuterClass.OuterClass.this; // case3\n" +
" Program.FarOuterClass.OuterClass.this.field = 1; // case3\n" +
" OuterClass outer4 = test.Program.FarOuterClass.OuterClass.this; // case4\n" +
" test.Program.FarOuterClass.OuterClass.this.field = 1; // case4\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"\n" +
" public class OuterClass {\n" +
" }\n" +
"}";

CompilationUnit cu = StaticJavaParser.parse(s);
List<ThisExpr> exprs = cu.findAll(ThisExpr.class);
exprs.forEach(expr-> {
Expand Down

0 comments on commit 5419a83

Please sign in to comment.