From 2cf5b6f35d582447cd6e9b2e30b20b3d1cff5f17 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 14 Sep 2021 22:10:16 +0200 Subject: [PATCH] Recognize OpenDaylight's Immutable interface OpenDaylight has a type-safe marker interface which acts as API contract specification of effective immutability. Recognize this contract as equivalent to an inherited @Immutable annotation. Fixes #1697. Signed-off-by: Robert Varga --- CHANGELOG.md | 1 + spotbugs/build.gradle | 1 + .../umd/cs/findbugs/util/MutableClasses.java | 8 ++++++++ .../cs/findbugs/util/MutableClassesTest.java | 20 +++++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a85ab526d5f..b9bcd830611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Currently the versioning policy of this project follows [Semantic Versioning v2. `SW_SWING_METHODS_INVOKED_IN_SWING_THREAD` ([#1664](https://github.com/spotbugs/spotbugs/pull/1664)) - Wrong description of the `SE_TRANSIENT_FIELD_OF_NONSERIALIZABLE_CLASS` ([#1664](https://github.com/spotbugs/spotbugs/pull/1664)) - Treat types with `@com.google.errorprone.annotations.Immutable` as immutable ([#1705](https://github.com/spotbugs/spotbugs/pull/1705)) +- Treat types which implement `org.opendaylight.yangtools.concepts.Immutable` as immutable ([#1697](https://github.com/spotbugs/spotbugs/issues/1697)) ## 4.4.1 - 2021-09-07 ### Changed diff --git a/spotbugs/build.gradle b/spotbugs/build.gradle index 0b578c9c0ab..8126f87b829 100644 --- a/spotbugs/build.gradle +++ b/spotbugs/build.gradle @@ -98,6 +98,7 @@ dependencies { testImplementation 'org.apache.ant:ant:1.10.11' testImplementation 'org.apache.logging.log4j:log4j-slf4j18-impl:2.14.0' testImplementation 'com.google.errorprone:error_prone_annotations:2.9.0' + testImplementation 'org.opendaylight.yangtools:concepts:7.0.7' guiImplementation sourceSets.main.runtimeClasspath guiCompileOnly 'com.apple:AppleJavaExtensions:1.4' diff --git a/spotbugs/src/main/java/edu/umd/cs/findbugs/util/MutableClasses.java b/spotbugs/src/main/java/edu/umd/cs/findbugs/util/MutableClasses.java index 2ffa9ed6bcb..6e6429ca3fe 100644 --- a/spotbugs/src/main/java/edu/umd/cs/findbugs/util/MutableClasses.java +++ b/spotbugs/src/main/java/edu/umd/cs/findbugs/util/MutableClasses.java @@ -171,6 +171,14 @@ private boolean computeByImmutableContract() { } } + // We are not considering transitive interfaces for now to side-step class loading + for (String iface : cls.getInterfaceNames()) { + // OpenDaylight's Immutable interface is an explicit contract + if (iface.equals("org.opendaylight.yangtools.concepts.Immutable")) { + return true; + } + } + final ClassAnalysis maybeSuper = getSuperAnalysis(); return maybeSuper != null && maybeSuper.isImmutableByContract(); } diff --git a/spotbugs/src/test/java/edu/umd/cs/findbugs/util/MutableClassesTest.java b/spotbugs/src/test/java/edu/umd/cs/findbugs/util/MutableClassesTest.java index 691b1393714..eff10ba7013 100644 --- a/spotbugs/src/test/java/edu/umd/cs/findbugs/util/MutableClassesTest.java +++ b/spotbugs/src/test/java/edu/umd/cs/findbugs/util/MutableClassesTest.java @@ -116,4 +116,24 @@ public void TestErrorProneImmutable() { Assert.assertFalse(MutableClasses.mutableSignature( "Ledu/umd/cs/findbugs/util/MutableClassesTest$ErrorProneImmutableSubclass;")); } + + public static class OpenDaylightImmutable implements org.opendaylight.yangtools.concepts.Immutable { + public void clear() { + // Does not matter + } + } + + public static class OpenDaylightImmutableSubclass extends OpenDaylightImmutable { + public String put(String str) { + return ""; + } + } + + @Test + public void TestOpenDaylightImmutable() { + Assert.assertFalse(MutableClasses.mutableSignature( + "Ledu/umd/cs/findbugs/util/MutableClassesTest$OpenDaylightImmutable;")); + Assert.assertFalse(MutableClasses.mutableSignature( + "Ledu/umd/cs/findbugs/util/MutableClassesTest$OpenDaylightImmutableSubclass;")); + } }