javaparser icon indicating copy to clipboard operation
javaparser copied to clipboard

StackOverflowError in ClassLoaderTypeSolver.tryToSolveType

Open Ruil1n opened this issue 1 year ago • 2 comments

test case, no com.example.core.service.impl.RecordServiceImpl and CreateProcessor defined

https://github.com/Ruil1n/javaparser/blob/Issue4187Test/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4187Test.java

    @Test
    void issue4187() throws IOException {
        // Setup symbol solver
        JavaParserTypeSolver javaParserTypeSolver = new JavaParserTypeSolver(adaptPath("src/test/resources/issue4187/"));
        StaticJavaParser.getConfiguration()
                .setSymbolResolver(new JavaSymbolSolver(
                        new CombinedTypeSolver(new ReflectionTypeSolver(), javaParserTypeSolver))
                );

        // Parse the File
        Path filePath = adaptPath("src/test/resources/issue4187/com/example/service/impl/RecordServiceImpl.java");

        StaticJavaParser.parse(filePath).accept(new VoidVisitorAdapter<String>() {
            @Override
            public void visit(MethodDeclaration methodDeclaration, String arg) {
                try {
                    System.out.println(methodDeclaration.resolve().getQualifiedName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, null);
    }

add path (javaparser/javaparser-symbol-solver-testing/src/test/resources/issue4187/com/example/service/impl/) and file (RecordServiceImpl.java)

package com.example.service.impl;
import com.example.service.*;

public class RecordServiceImpl
        extends com.example.core.service.impl.RecordServiceImpl
{

    private static final CreateProcessor createProcessor = new CreateProcessor() {
        @Override
        public void after(Record record) {

        }
    };
}
java.lang.StackOverflowError
	at com.github.javaparser.ast.expr.Name.asString(Name.java:118)
	at com.github.javaparser.ast.expr.Name.asString(Name.java:118)
	at com.github.javaparser.ast.nodeTypes.NodeWithName.getNameAsString(NodeWithName.java:49)
	at com.github.javaparser.ast.body.TypeDeclaration.lambda$null$4(TypeDeclaration.java:206)
	at java.util.Optional.map(Optional.java:215)
	at com.github.javaparser.ast.body.TypeDeclaration.lambda$getFullyQualifiedName$6(TypeDeclaration.java:206)
	at java.util.Optional.map(Optional.java:215)
	at com.github.javaparser.ast.body.TypeDeclaration.getFullyQualifiedName(TypeDeclaration.java:206)
	at com.github.javaparser.ast.body.ClassOrInterfaceDeclaration.getFullyQualifiedName(ClassOrInterfaceDeclaration.java:242)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.CompilationUnitContext.solveType(CompilationUnitContext.java:128)
	at com.github.javaparser.resolution.Context.solveType(Context.java:97)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.CompilationUnitContext.solveType(CompilationUnitContext.java:152)
	at com.github.javaparser.resolution.Context.solveType(Context.java:97)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.solveType(JavaParserClassDeclaration.java:323)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.toReferenceType(JavaParserClassDeclaration.java:468)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.getSuperClass(JavaParserClassDeclaration.java:200)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.getAncestors(JavaParserClassDeclaration.java:353)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:205)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.checkAncestorsForType(JavaParserTypeDeclarationAdapter.java:229)

Ruil1n avatar Nov 02 '23 09:11 Ruil1n

In some special cases some code will be in the three-party jar package, and our analysis can not get it, so in this case for the robustness of the program, I think we can not throw a stack overflow error here, which will affect the normal progress of our entire analysis process

Ruil1n avatar Nov 02 '23 09:11 Ruil1n

This is an edge case that is not currently supported by JP.

When JP tries to resolve the declaration of the "public void after(Record record)" method, JP detects that it is declared in an anonymous class "CreateProcessor" which he in turn tries to resolve in the RecordServiceImpl class or the ancestors of this class. In the resolution strategy JP tries to detect a member of the class which would correspond to a type declaration. If it does not find a type declaration, JP searches among the ancestors if it finds it.

In this specific case, JP is therefore looking for an internal declaration of the "CreateProcessor" in the ancestor of the class RecordServiceImpl. JP therefore searches for members of class/interface types in this compilation unit. For example, if the given name is "A.B", there may be a class or interface in this compilation unit called "A" that has another member class or interface called "B".

In our case JP is looking for a type "impl.RecordServiceImpl". However, during the analysis JP detects that through the import "import com.example.service.*" he finds a type called "com.example.service.impl.RecordServiceImpl". As it still does not find a type declaration corresponding to "CreateProcessor" it continues its search indefinitely.

jlerbsc avatar Nov 02 '23 15:11 jlerbsc