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

NotJavadoc: IllegalArgumentException: Overlapping ranges not permitted but found [89..95] overlapping [89..95] #4040

Closed
remal opened this issue Aug 3, 2023 · 8 comments

Comments

@remal
Copy link

remal commented Aug 3, 2023

error-prone version: 2.21.0
BugPattern: NotJavadoc
Stack Trace:

java.lang.IllegalArgumentException: Overlapping ranges not permitted but found [89..95] overlapping [89..95]
    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:445)
    at com.google.common.collect.ImmutableRangeSet$Builder.build(ImmutableRangeSet.java:807)
    at com.google.errorprone.bugpatterns.BugChecker.suppressedRegions(BugChecker.java:321)
    at com.google.errorprone.bugpatterns.javadoc.NotJavadoc.matchCompilationUnit(NotJavadoc.java:62)
    at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449)
    at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:555)
    at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:591)
    at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
    at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
    at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
    at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:156)
    at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
    at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1418)
    at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1365)
    at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:960)
    at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
    at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
    at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
    at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
    at ...

The class that fails:

package name.remal.gradle_plugins.toolkit;

import lombok.Builder;
import lombok.Value;

@Value
@Builder
class CrossCompileServiceImpl {

    String className;

    CrossCompileServiceDependencyVersion dependencyVersion;

    public boolean isFallback() {
        return getDependencyVersion().getVersion() == null;
    }

}

lombok.config:

config.stopBubbling = true

lombok.addNullAnnotations = javax

lombok.fieldDefaults.defaultPrivate = true
lombok.toString.callSuper = call
lombok.equalsAndHashCode.callSuper = call
lombok.noArgsConstructor.extraPrivate = true
lombok.singular.auto = true
lombok.fieldNameConstants.uppercase = true

lombok.anyConstructor.addConstructorProperties = false

lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
lombok.copyableAnnotations += org.mockito.Mock
lombok.copyableAnnotations += org.mockito.Spy
lombok.copyableAnnotations += name.remal.gradle_plugins.toolkit.testkit.ChildProjectOf
lombok.copyableAnnotations += name.remal.gradle_plugins.toolkit.testkit.ApplyPlugin

lombok.accessors.flagUsage = warning

lombok.log.fieldname = logger
#lombok.log.custom.flagUsage = warning
lombok.log.custom.declaration = org.gradle.api.logging.Logger org.gradle.api.logging.Logging.getLogger(TYPE)
lombok.log.apacheCommons.flagUsage = warning
lombok.log.flogger.flagUsage = warning
lombok.log.javaUtilLogging.flagUsage = warning
lombok.log.jbosslog.flagUsage = warning
lombok.log.log4j.flagUsage = warning
lombok.log.log4j2.flagUsage = warning
lombok.log.slf4j.flagUsage = warning
lombok.log.xslf4j.flagUsage = warning

lombok.addLombokGeneratedAnnotation = true

lombok.addSuppressWarnings = true
lombok.extern.findbugs.addSuppressFBWarnings = true

lombok.utilityClass.flagUsage = error
@cushon
Copy link
Collaborator

cushon commented Aug 3, 2023

This looks like the same crash as #4034

Do you know what code lombok is generating, e.g. what the output of https://projectlombok.org/features/delombok is?

@remal
Copy link
Author

remal commented Aug 4, 2023

@cushon,

Delombok output.
package name.remal.gradle_plugins.toolkit;

final class CrossCompileServiceImpl {
    private final String className;
    private final CrossCompileServiceDependencyVersion dependencyVersion;

    public boolean isFallback() {
        return getDependencyVersion().getVersion() == null;
    }

    @Override
    public String toString() {
        return getClassName() + " (" + "dependency=" + getDependencyVersion().getDependency() + ", version=" + getDependencyVersion().getVersion() + ", earlierIncluded=" + getDependencyVersion().isEarlierIncluded() + ", selfIncluded=" + getDependencyVersion().isSelfIncluded() + ", laterIncluded=" + getDependencyVersion().isLaterIncluded() + ')';
    }

    CrossCompileServiceImpl(final String className, final CrossCompileServiceDependencyVersion dependencyVersion) {
        this.className = className;
        this.dependencyVersion = dependencyVersion;
    }


    public static class CrossCompileServiceImplBuilder {
        private String className;
        private CrossCompileServiceDependencyVersion dependencyVersion;

        CrossCompileServiceImplBuilder() {
        }

        /**
         * @return {@code this}.
         */
        @javax.annotation.Nonnull
        public CrossCompileServiceImpl.CrossCompileServiceImplBuilder className(final String className) {
            this.className = className;
            return this;
        }

        /**
         * @return {@code this}.
         */
        @javax.annotation.Nonnull
        public CrossCompileServiceImpl.CrossCompileServiceImplBuilder dependencyVersion(final CrossCompileServiceDependencyVersion dependencyVersion) {
            this.dependencyVersion = dependencyVersion;
            return this;
        }

        @javax.annotation.Nonnull
        public CrossCompileServiceImpl build() {
            return new CrossCompileServiceImpl(this.className, this.dependencyVersion);
        }

        @javax.annotation.Nonnull
        @Override
        public String toString() {
            return "CrossCompileServiceImpl.CrossCompileServiceImplBuilder(className=" + this.className + ", dependencyVersion=" + this.dependencyVersion + ")";
        }
    }

    @javax.annotation.Nonnull
    public static CrossCompileServiceImpl.CrossCompileServiceImplBuilder builder() {
        return new CrossCompileServiceImpl.CrossCompileServiceImplBuilder();
    }

    private CrossCompileServiceImpl() {
        this.className = null;
        this.dependencyVersion = null;
    }

    public String getClassName() {
        return this.className;
    }

    public CrossCompileServiceDependencyVersion getDependencyVersion() {
        return this.dependencyVersion;
    }

    @Override
    public boolean equals(@javax.annotation.Nullable final Object o) {
        if (o == this) return true;
        if (!(o instanceof CrossCompileServiceImpl)) return false;
        final CrossCompileServiceImpl other = (CrossCompileServiceImpl) o;
        final Object this$className = this.getClassName();
        final Object other$className = other.getClassName();
        if (this$className == null ? other$className != null : !this$className.equals(other$className)) return false;
        final Object this$dependencyVersion = this.getDependencyVersion();
        final Object other$dependencyVersion = other.getDependencyVersion();
        if (this$dependencyVersion == null ? other$dependencyVersion != null : !this$dependencyVersion.equals(other$dependencyVersion)) return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final Object $className = this.getClassName();
        result = result * PRIME + ($className == null ? 43 : $className.hashCode());
        final Object $dependencyVersion = this.getDependencyVersion();
        result = result * PRIME + ($dependencyVersion == null ? 43 : $dependencyVersion.hashCode());
        return result;
    }
}

 

I also set a breakpoint to BugChecker:321.

What ErrorProne sees.
package name.remal.gradle_plugins.toolkit;

import lombok.Builder;
import lombok.Value;

@Value()
@Builder()
final class CrossCompileServiceImpl {
    private final String className;
    private final CrossCompileServiceDependencyVersion dependencyVersion;
    
    public boolean isFallback() {
        return getDependencyVersion().getVersion() == null;
    }
    
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    CrossCompileServiceImpl(final String className, final CrossCompileServiceDependencyVersion dependencyVersion) {
        super();
        this.className = className;
        this.dependencyVersion = dependencyVersion;
    }
    
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public static class CrossCompileServiceImplBuilder {
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        private String className;
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        private CrossCompileServiceDependencyVersion dependencyVersion;
        
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        CrossCompileServiceImplBuilder() {
            super();
        }
        
        /**
         * @return {@code this}.
         */
        @javax.annotation.Nonnull()
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        public CrossCompileServiceImpl.CrossCompileServiceImplBuilder className(final String className) {
            this.className = className;
            return this;
        }
        
        /**
         * @return {@code this}.
         */
        @javax.annotation.Nonnull()
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        public CrossCompileServiceImpl.CrossCompileServiceImplBuilder dependencyVersion(final CrossCompileServiceDependencyVersion dependencyVersion) {
            this.dependencyVersion = dependencyVersion;
            return this;
        }
        
        @javax.annotation.Nonnull()
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        public CrossCompileServiceImpl build() {
            return new CrossCompileServiceImpl(this.className, this.dependencyVersion);
        }
        
        @javax.annotation.Nonnull()
        @java.lang.Override()
        @java.lang.SuppressWarnings(value = "all")
        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
        @lombok.Generated()
        public java.lang.String toString() {
            return "CrossCompileServiceImpl.CrossCompileServiceImplBuilder(className=" + this.className + ", dependencyVersion=" + this.dependencyVersion + ")";
        }
    }
    
    @javax.annotation.Nonnull()
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public static CrossCompileServiceImpl.CrossCompileServiceImplBuilder builder() {
        return new CrossCompileServiceImpl.CrossCompileServiceImplBuilder();
    }
    
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    private CrossCompileServiceImpl() {
        super();
        this.className = null;
        this.dependencyVersion = null;
    }
    
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public String getClassName() {
        return this.className;
    }
    
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public CrossCompileServiceDependencyVersion getDependencyVersion() {
        return this.dependencyVersion;
    }
    
    @java.lang.Override()
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public boolean equals(@javax.annotation.Nullable()
    final java.lang.Object o) {
        if (o == this) return true;
        if (!(o instanceof CrossCompileServiceImpl)) return false;
        final CrossCompileServiceImpl other = (CrossCompileServiceImpl)o;
        final java.lang.Object this$className = this.getClassName();
        final java.lang.Object other$className = other.getClassName();
        if (this$className == null ? other$className != null : !this$className.equals(other$className)) return false;
        final java.lang.Object this$dependencyVersion = this.getDependencyVersion();
        final java.lang.Object other$dependencyVersion = other.getDependencyVersion();
        if (this$dependencyVersion == null ? other$dependencyVersion != null : !this$dependencyVersion.equals(other$dependencyVersion)) return false;
        return true;
    }
    
    @java.lang.Override()
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final java.lang.Object $className = this.getClassName();
        result = result * PRIME + ($className == null ? 43 : $className.hashCode());
        final java.lang.Object $dependencyVersion = this.getDependencyVersion();
        result = result * PRIME + ($dependencyVersion == null ? 43 : $dependencyVersion.hashCode());
        return result;
    }
    
    @javax.annotation.Nonnull()
    @java.lang.Override()
    @java.lang.SuppressWarnings(value = "all")
    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
    @lombok.Generated()
    public java.lang.String toString() {
        return "CrossCompileServiceImpl(className=" + this.getClassName() + ", dependencyVersion=" + this.getDependencyVersion() + ")";
    }
}

@msridhar
Copy link
Contributor

msridhar commented Aug 4, 2023

We are seeing this same new crash in the NullAway repo when updating to EP 2.21.0. To repro, check out this branch:

https://github.com/msridhar/NullAway/tree/not-javadoc-lombok-crash-repro

And then run ./gradlew :test-java-lib-lombok:compileJava. When building on either JDK 11 or JDK 17 I get this crash:

NullAway/test-java-lib-lombok/src/main/java/com/uber/lombok/LombokDTO.java:23: error: An unhandled exception was thrown by the Error Prone static analysis plugin.
package com.uber.lombok;
^
     Please report this at https://github.com/google/error-prone/issues/new and include the following:

     error-prone version: 2.21.0
     BugPattern: NotJavadoc
     Stack Trace:
     java.lang.IllegalArgumentException: Overlapping ranges not permitted but found [1233..1241] overlapping [1233..1241]
        at com.google.common.base.Preconditions.checkArgument(Preconditions.java:445)
        at com.google.common.collect.ImmutableRangeSet$Builder.build(ImmutableRangeSet.java:807)
        at com.google.errorprone.bugpatterns.BugChecker.suppressedRegions(BugChecker.java:321)
        at com.google.errorprone.bugpatterns.javadoc.NotJavadoc.matchCompilationUnit(NotJavadoc.java:62)
        at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:555)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:591)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
        at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
        at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:156)
        at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
        [...]

I see the same crash when updating our Lombok dependence to the latest version, 1.18.28.

@cushon
Copy link
Collaborator

cushon commented Aug 4, 2023

Some printf debugging with the NullAway repro shows the usual issue with Lombok generating AST nodes with synthetic nodes with bogus positions that overlap, e.g.

[1233,1241]
@java.lang.SuppressWarnings(value = "all")
@lombok.Generated
private static String $default$fieldWithDefault() {
    return "Default";
}
[1233,1241]
@java.lang.SuppressWarnings(value = "all")
@lombok.Generated
private static String $default$fieldWithNullDefault() {
    return null;
}

@msridhar
Copy link
Contributor

msridhar commented Aug 4, 2023

Also reported at projectlombok/lombok#3476 in case it can be fixed on the Lombok side

@cushon
Copy link
Collaborator

cushon commented Aug 4, 2023

I have a pending fix to handle the overlapping ranges, I think it's harmless to ignore the overlaps and that will result in NotJavadoc successfully handling those @SuppressWarnings annotations

copybara-service bot pushed a commit that referenced this issue Aug 4, 2023
copybara-service bot pushed a commit that referenced this issue Aug 4, 2023
@cushon cushon closed this as completed Aug 4, 2023
@msridhar
Copy link
Contributor

msridhar commented Aug 4, 2023

Confirmed that Error Prone 2.21.1 works without crashing for NullAway's Lombok test. Thanks @cushon!

@Stephan202
Copy link
Contributor

I referenced this issue in google/guava#3033; that feature could prevent issues such as this one in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants