Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[java] More parser edge cases #3643

Closed
adangel opened this issue Nov 23, 2021 · 2 comments · Fixed by #4197
Closed

[java] More parser edge cases #3643

adangel opened this issue Nov 23, 2021 · 2 comments · Fixed by #4197
Assignees
Labels
a:bug PMD crashes or fails to analyse a file. in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception
Milestone

Comments

@adangel
Copy link
Member

adangel commented Nov 23, 2021

Affects PMD Version: 6.40.0
Description: Found in checkstyle sources in #3640

There are a couple of samples - we might want to split these into separate issues when solving them. But for now, I collect all cases in one issue.

Annotated Array Type

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeAnnotations.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespaceafter/InputNoWhitespaceAfterArrayDeclarationsAndAnno.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespaceafter/InputNoWhitespaceAfterNewTypeStructure.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/java8/InputAnnotations12.java
@Target(ElementType.TYPE_USE)
@interface NonNull {}

class AnnotedArrayType {
    @NonNull int @NonNull[] @NonNull[] field1;
    @NonNull int @NonNull [] @NonNull [] field2;
    public String m2()@NonNull[]@NonNull[] { return null; }
    public String@NonNull[]@NonNull[] m2a() { return null; }
    public void run() {
        for (String a@NonNull[] : m2()) {
        }
    }
    void vararg(@NonNull String @NonNull [] @NonNull ... vararg2) { }
    public void vararg2(@NonNull int @NonNull ... vararg) {}
    public void vararg3(@NonNull int[] @NonNull ... vararg) {}
}

Error while type resolution

This stacktrace only appears with type resolution. Didn't dig deeper into this, but here's the stacktrace

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/avoidnoargumentsuperconstructorcall/InputAvoidNoArgumentSuperConstructorCall.java

net.sourceforge.pmd.PMDException: Error while processing $FILE
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCodeWithoutCache(SourceCodeProcessor.java:128)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCode(SourceCodeProcessor.java:100)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCode(SourceCodeProcessor.java:62)
    at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:85)
    at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:29)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 0
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:372)
    at java.base/java.util.ArrayList.get(ArrayList.java:459)
    at net.sourceforge.pmd.lang.java.symboltable.NameFinder.checkForNameChild(NameFinder.java:62)
    at net.sourceforge.pmd.lang.java.symboltable.NameFinder.<init>(NameFinder.java:37)
    at net.sourceforge.pmd.lang.java.symboltable.OccurrenceFinder.visit(OccurrenceFinder.java:46)
    at net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression.jjtAccept(ASTPrimaryExpression.java:25)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:478)
    at net.sourceforge.pmd.lang.java.ast.ASTStatementExpression.jjtAccept(ASTStatementExpression.java:25)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:448)
    at net.sourceforge.pmd.lang.java.ast.ASTStatement.jjtAccept(ASTStatement.java:25)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:463)
    at net.sourceforge.pmd.lang.java.ast.ASTBlockStatement.jjtAccept(ASTBlockStatement.java:25)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:258)
    at net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration.jjtAccept(ASTConstructorDeclaration.java:35)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:58)
    at net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration.jjtAccept(ASTClassOrInterfaceBodyDeclaration.java:44)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:53)
    at net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody.jjtAccept(ASTClassOrInterfaceBody.java:35)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:23)
    at net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration.jjtAccept(ASTClassOrInterfaceDeclaration.java:55)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:208)
    at net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration.jjtAccept(ASTTypeDeclaration.java:39)
    at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:62)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:13)
    at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:183)
    at net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit.jjtAccept(ASTCompilationUnit.java:44)
    at net.sourceforge.pmd.lang.java.symboltable.SymbolFacade.initializeWith(SymbolFacade.java:21)
    at net.sourceforge.pmd.lang.java.AbstractJavaHandler$4.start(AbstractJavaHandler.java:111)
    at net.sourceforge.pmd.SourceCodeProcessor.symbolFacade(SourceCodeProcessor.java:144)
    at net.sourceforge.pmd.SourceCodeProcessor.processSource(SourceCodeProcessor.java:202)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCodeWithoutCache(SourceCodeProcessor.java:118)
    ... 10 more

Type Annotations

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/avoidnoargumentsuperconstructorcall/InputAvoidNoArgumentSuperConstructorCall.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionAnnotationOnQualifiedTypes.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionNestedTypeParametersAndArrayDeclarators.java
@Target({
    ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER,
    ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface TypeAnnotation {
}

class TypeAnnotations {
    // We can use type Annotations with generic type arguments
    private Map.@TypeAnnotation Entry entry;
    // Type annotations in instanceof statements
    boolean isNonNull = "string" instanceof @TypeAnnotation String;
    // java.awt.geom.Rectangle2D
    public final Rectangle2D.@TypeAnnotation Double getRect1() {
        return new Rectangle2D.Double();
    }
    public final Rectangle2D.Double getRect2() {
        return new Rectangle2D.@TypeAnnotation Double();
    }
    public final Rectangle2D.Double getRect3() {
        Rectangle2D.@TypeAnnotation Double rect = null;
        return rect;
    }

    class Outer {
        class Inner {
            class Inner2 {
            }
        }
        class GInner<X> {
            class GInner2<Y, Z> {}
        }
        class Static {}
        class GStatic<X, Y> {
            class GStatic2<Z> {}
        }
    }
    class MyList<K> { }
    class Test1 {
        @TypeAnnotation Outer . @TypeAnnotation GInner<@TypeAnnotation MyList<@TypeAnnotation Object @TypeAnnotation[] @TypeAnnotation[]>>
                .@TypeAnnotation GInner2<@TypeAnnotation Integer, @TypeAnnotation Object> @TypeAnnotation[] @TypeAnnotation[] f4arrtop;
    }
}

Generic Constructor call

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/genericwhitespace/InputGenericWhitespaceDefault.java
// and https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionUncommon4.java
class GenericConstructor {
    Object ok = new <String>Object();
    Object okWithPackage = new <String>java.lang.Object();
    Object ok2 = new <String>Outer.Inner();
    Object o3 = new <String>Outer().new <String>NonStatic();
    Object o4 = new <String>GenericOuter<String>();
    Object o5 = new <String>GenericOuter<String>().new <String>GenericInner<String>();
}
class Outer {
    static class Inner {}
    class NonStatic {}
}
class GenericOuter<T> {
    class GenericInner<U> { }
}

Generic super call

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/InputRegressionJavaClass2.java
class c4<A,B> {
    class c4a {}

    public c4() { <String>super(); }
}
class c5 extends c4.c4a {
    c5() { new c4().super(); }
    c5(int a) { new c4().<String>super(); }
}

Annotation Comma Array Initializer

// From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionSingleCommaInArrayInit.java
class AnnotationCommaArrayInit {
    @Foo({,}) void b() { }
    @interface Foo { int[] value(); }
}

Qualified Constructor Parameter

From https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionQualifiedConstructorParameter.java

//non-compiled with eclipse: 'The explicit 'this' parameter is expected to be qualified with Inner'
package com.puppycrawl.tools.checkstyle.grammar.antlr4;

public class InputAntlr4AstRegressionQualifiedConstructorParameter {
    class Inner {
        class Inner2 {
            Inner2(InputAntlr4AstRegressionQualifiedConstructorParameter.Inner
                           InputAntlr4AstRegressionQualifiedConstructorParameter.Inner.this) { }
        }
    }
}

⚠️ ⚠️

About the last code sample here (Qualified Constructor Parameter), this is not valid Java code according to the JLS. The JLS is very clear that the receiver parameter can only be preceded by a simple name: https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-ReceiverParameter

ReceiverParameter: {Annotation} UnannType [Identifier .] this

In an inner class's constructor, the type of the receiver parameter must be the class or interface which is the immediately enclosing type declaration of the inner class, and the name of the receiver parameter must be Identifier . this where Identifier is the simple name of the class or interface which is the immediately enclosing type declaration of the inner class; otherwise, a compile-time error occurs.

While Javac accepts this without complaining, this will probably never be found in the wild, and I don't think we should try to support it.

@adangel adangel added a:bug PMD crashes or fails to analyse a file. in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception labels Nov 23, 2021
@oowekyala oowekyala added this to the 6.52.0 milestone Nov 5, 2022
@oowekyala oowekyala self-assigned this Nov 5, 2022
oowekyala added a commit to oowekyala/pmd that referenced this issue Nov 5, 2022
oowekyala added a commit to oowekyala/pmd that referenced this issue Nov 5, 2022
@oowekyala
Copy link
Member

About the last code sample here (Qualified Constructor Parameter), this is not valid Java code according to the JLS. The JLS is very clear that the receiver parameter can only be preceded by a simple name: https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-ReceiverParameter

ReceiverParameter: {Annotation} UnannType [Identifier .] this

In an inner class's constructor, the type of the receiver parameter must be the class or interface which is the immediately enclosing type declaration of the inner class, and the name of the receiver parameter must be Identifier . this where Identifier is the simple name of the class or interface which is the immediately enclosing type declaration of the inner class; otherwise, a compile-time error occurs.

While Javac accepts this without complaining, this will probably never be found in the wild, and I don't think we should try to support it.

@adangel
Copy link
Member Author

adangel commented Nov 8, 2022

While Javac accepts this without complaining, this will probably never be found in the wild, and I don't think we should try to support it.

Yes, I agree. It could even be seen as a bug in javac.
Let's not bother to support this very unlikely syntax.

adangel added a commit to adangel/pmd that referenced this issue Nov 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:bug PMD crashes or fails to analyse a file. in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants