javaparser icon indicating copy to clipboard operation
javaparser copied to clipboard

record in an interface throw IllegalArgumentException

Open Fioooooooo opened this issue 1 year ago • 10 comments

My Environment

javaparser 3.25.8

Current Behavior

When try to resolve a MethodCallExpr got an exception.

Here is my test code for reproduce.

@Test
public void testStaticMethod() {
    CompilationUnit compilationUnit = StaticJavaParser.parse("""
            public interface IUtil {
                record WrapperRecord(String name){}
            }
            
            public class Util implements IUtil {
                public static Util create(String key) {
                    return new Util();
                }
            }
                            
            public class Test {
                            
                public void test() {
                    Util.create("foo");
                }
                            
            }
            """);

    for (MethodDeclaration method : compilationUnit.findAll(MethodDeclaration.class)) {
        for (MethodCallExpr call : method.findAll(MethodCallExpr.class)) {
            String qualifiedSignature = call.resolve().getQualifiedSignature();
            log.info("QualifiedSignature: {}", qualifiedSignature);
        }
    }
}
  • Here is an interface named IUtil, and it has a record member.
  • A class named Util implement IUtil.
  • A test class Test has a method call Util.create().

The test code will throw an exception

java.lang.IllegalArgumentException: Cannot get a reference type declaration from com.github.javaparser.ast.body.RecordDeclaration

	at com.github.javaparser.symbolsolver.JavaSymbolSolver.toTypeDeclaration(JavaSymbolSolver.java:426)
	at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.getTypeDeclaration(JavaParserFacade.java:698)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeAdapter.internalTypes(JavaParserTypeAdapter.java:196)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration.internalTypes(JavaParserInterfaceDeclaration.java:366)
	at com.github.javaparser.resolution.declarations.ResolvedTypeDeclaration.hasInternalType(ResolvedTypeDeclaration.java:61)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.isAncestor(JavaParserClassDeclaration.java:396)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.getAncestors(JavaParserClassDeclaration.java:373)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.JavaParserTypeDeclarationAdapter.solveMethod(JavaParserTypeDeclarationAdapter.java:251)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.ClassOrInterfaceDeclarationContext.solveMethod(ClassOrInterfaceDeclarationContext.java:106)
	at com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration.solveMethod(JavaParserClassDeclaration.java:329)
	at com.github.javaparser.resolution.logic.MethodResolutionLogic.solveMethodInType(MethodResolutionLogic.java:887)
	at com.github.javaparser.symbolsolver.javaparsermodel.contexts.MethodCallExprContext.solveMethod(MethodCallExprContext.java:161)
	at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:273)
	at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:134)
	at com.github.javaparser.symbolsolver.JavaSymbolSolver.resolveDeclaration(JavaSymbolSolver.java:172)
	at com.github.javaparser.ast.expr.MethodCallExpr.resolve(MethodCallExpr.java:319)



I tried to debug JP. I found when resolve the method call(Util.create()), JP will get Util ancestors and try get internal types.

In JavaParserTypeAdapter, the record WrapperRecord in IUtil is instance of RecordDeclaration, and then exception occurred.

public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
        // Use a special Set implementation that avoids calculating the hashCode of the node,
        // since this can be very time-consuming for big node trees, and we are sure there are
        // no duplicates in the members list.
        Set<ResolvedReferenceTypeDeclaration> res = Collections.newSetFromMap(new IdentityHashMap<>());
        for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) {
            if (member instanceof TypeDeclaration) {
                res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((TypeDeclaration) member));
            }
        }
        return res;
    }

My Question

I want to know what did i wrong if i try to get the method qualified signature? Or dose JP not support parsing record in interfaces?

Fioooooooo avatar Jan 31 '24 10:01 Fioooooooo

It seems to be a bug in the symbol solver. Records resolution is not fully supported in Symbol Solver.

jlerbsc avatar Jan 31 '24 13:01 jlerbsc

It seems to be a bug in the symbol solver. Records resolution is not fully supported in Symbol Solver.

Thank you for the reply, will JP fix the issue next version?

Fioooooooo avatar Feb 01 '24 01:02 Fioooooooo

The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.

jlerbsc avatar Feb 01 '24 06:02 jlerbsc

The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.

Thank you for your reply.

Fioooooooo avatar Feb 01 '24 10:02 Fioooooooo

Related to https://github.com/javaparser/javaparser/issues/3556#issuecomment-1102609775

jlerbsc avatar Feb 02 '24 16:02 jlerbsc

The integration of Records resolution is a fairly lengthy process. It is very likely that this issue will not be corrected in the next version.

I'm not a developer of JP, but if I want to fix this, can anyone give me some guidance on how to do it and an estimate of how much time it takes?

secanalyzer avatar Apr 25 '24 12:04 secanalyzer

Thank you for your offer, but it's currently under development.

jlerbsc avatar Apr 25 '24 14:04 jlerbsc

@jlerbsc It would be incredibly helpful to have support for records as well. Do we have any timelines on when we can expect this fix?

vimalmeena238 avatar Jun 25 '24 08:06 vimalmeena238

Records resolution support is currently being developed. Thanks to @johannescoetzee for his contribution on this subject.

jlerbsc avatar Jun 25 '24 08:06 jlerbsc

This will certainly be available in the next version, which will be released at the end of July.

jlerbsc avatar Jun 25 '24 08:06 jlerbsc

@johannescoetzee can ensure that the resolution of the records takes this issue into account. Thank you for your help.

jlerbsc avatar Jul 11 '24 14:07 jlerbsc

I've slightly modified the example given here to be java 8 compatible, to add some StaticJavaParser setup, and to allow automated testing:

    @Test
    @EnabledForJreRange(min = org.junit.jupiter.api.condition.JRE.JAVA_14)
    public void testStaticMethod() {
    
        ParserConfiguration.LanguageLevel oldLevel = StaticJavaParser.getParserConfiguration().getLanguageLevel();
        StaticJavaParser.getParserConfiguration().setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_16);
        StaticJavaParser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(new ReflectionTypeSolver()));
        
        CompilationUnit compilationUnit = StaticJavaParser.parse(
                "public interface IUtil {\n" +
                        "    record WrapperRecord(String name){}\n" +
                        "}\n" +
                        "\n" +
                        "public class Util implements IUtil {\n" +
                        "    public static Util create(String key) {\n" +
                        "        return new Util();\n" +
                        "    }\n" +
                        "}\n" +
                        "                \n" +
                        "public class Test {\n" +
                        "                \n" +
                        "    public void test() {\n" +
                        "        Util.create(\"foo\");\n" +
                        "    }\n" +
                        "                \n" +
                        "}\n" );
                        
        StaticJavaParser.getParserConfiguration().setLanguageLevel(oldLevel);

        for (MethodDeclaration method : compilationUnit.findAll(MethodDeclaration.class)) {
            for (MethodCallExpr call : method.findAll(MethodCallExpr.class)) {
                assertEquals("create", call.getNameAsString());
                assertEquals("Util.create(java.lang.String)", call.resolve().getQualifiedSignature());
            }
        }
    }

I can confirm this version passes on my branch. The only significant change I made that wasn't mentioned in the original report was adding the reflection symbol solver, but I don't think that explains the difference in results so I'm reasonably confident that this case is handled along with record resolution.

johannescoetzee avatar Jul 11 '24 14:07 johannescoetzee

This bug has been fixed in the version currently under development. Thanks to @johannescoetzee

jlerbsc avatar Jul 12 '24 16:07 jlerbsc