rewrite-static-analysis icon indicating copy to clipboard operation
rewrite-static-analysis copied to clipboard

`org.openrewrite.staticanalysis.FinalClass` is wrong for nested sub classes

Open Bananeweizen opened this issue 1 year ago • 1 comments

org.openrewrite.staticanalysis.FinalClass works on wrong assumptions. A non-final class with no public constructor can have nested static sub classes, and in that case it cannot be made final.

What is the smallest, simplest way to reproduce the problem?

public class Reproducer {

    private Reproducer(final String name) {
        //...
    }

    public static final class Sub extends Reproducer {

        public Sub() {
            super("subclass");
        }
    }
}

What did you expect to see?

no change

What did you see instead?

final added to the top level class

Are you interested in contributing a fix to OpenRewrite?

Maybe. Have to look for how to get the information that there are nested sub classes.

Bananeweizen avatar Oct 16 '24 08:10 Bananeweizen

Thanks for reporting this variant! To detect sub classes you can either expand this loop https://github.com/openrewrite/rewrite-static-analysis/blob/2163f0f05dd6fe7f4762e3486c8f16a9a5787036/src/main/java/org/openrewrite/staticanalysis/FinalClassVisitor.java#L72-L83

Or add a new JavaIsoVisitor<>() { ... } that overrides visitClassDeclaration, and visit on the outer classDeclaration.getBody() and set an AtomicBoolean if any matching nested class declarations are found.

timtebeek avatar Oct 16 '24 09:10 timtebeek

This issue is stale because it has not had any activity for 60 days. Remove question label or comment or this will be closed in two weeks. Issues may be reopened when there is renewed interest.

github-actions[bot] avatar Jul 28 '25 11:07 github-actions[bot]

We're running into this with:

  • org.openrewrite:rewrite-core:8.62.4
  • org.openrewrite.recipe:rewrite-static-analysis:2.18.0

Here's a test case:

  @Test
  void dontFinalClassWithNestedInheritedClasses() {
    rewriteRun(
        spec -> spec.recipe(new FinalClass()),
        // language=java
        java(
            """
             public class Foo<T> {
                  private Foo() {}
            
                  public static final class Bar extends Foo<String> {}
              }
            """));
  }
org.opentest4j.AssertionFailedError: [Expected recipe to complete in 0 cycles, but took at least one more cycle. Between the last two executed cycles there were changes to "Foo.java"]
expected:
  "public class Foo<T> {
       private Foo() {}

       public static final class Bar extends Foo<String> {}
   }"
 but was:
  "public final class Foo<T> {
       private Foo() {}

       public static final class Bar extends Foo<String> {}
   }"
	at org.openrewrite.test.LargeSourceSetCheckingExpectedCycles.afterCycle(LargeSourceSetCheckingExpectedCycles.java:97)
	at org.openrewrite.RecipeScheduler.runRecipeCycles(RecipeScheduler.java:95)
	at org.openrewrite.RecipeScheduler.scheduleRun(RecipeScheduler.java:41)
	at org.openrewrite.Recipe.run(Recipe.java:442)
	at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:382)
	at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)

protocol7 avatar Sep 27 '25 09:09 protocol7

Thanks both! Fixed just now in

  • #742

timtebeek avatar Sep 27 '25 10:09 timtebeek

Thanks!

protocol7 avatar Sep 27 '25 12:09 protocol7

Just verified that we are still seeing this issue, with the above test case. This is with:

  • org.openrewrite:rewrite-core:8.63.3
  • org.openrewrite.recipe:rewrite-static-analysis:2.19.0

Has this not yet made it into a release, or is there something off with the fix?

protocol7 avatar Oct 17 '25 08:10 protocol7

The associated fix made it into 2.19.0, with the test added in https://github.com/openrewrite/rewrite-static-analysis/commit/6d6fe5e495330d851e1c8257270263337b994a02 Is there any change you can make to the test to reproduce the issue you're seeing?

timtebeek avatar Oct 17 '25 09:10 timtebeek

I did some testing and it comes down to a difference in the tests. In my test above, the subclass is final, which still triggers the bug, in your test case it is not.

protocol7 avatar Oct 17 '25 10:10 protocol7

That helps, thanks! I've pushed up another change in https://github.com/openrewrite/rewrite-static-analysis/commit/c195a4ff79d01c7b147eab35f49fbf211c00b3a3

timtebeek avatar Oct 17 '25 11:10 timtebeek