Skip to content

Commit 674a7d0

Browse files
authored
Fix CT_CONSTRUCTOR_THROW FP when Supertype has final finalize (#2666)
* Fix constructorthrow FP when superclass has final finalize * Add changelog entry * spotlessApply
1 parent a834b53 commit 674a7d0

File tree

5 files changed

+55
-6
lines changed

5 files changed

+55
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Currently the versioning policy of this project follows [Semantic Versioning v2.
1515
- Fix exception escapes when calling functions of JUnit Assert or Assertions ([[#2640](https://github.com/spotbugs/spotbugs/issues/2640)])
1616
- Fixed an error in the SARIF export when a bug annotation is missing ([[#2632](https://github.com/spotbugs/spotbugs/issues/2632)])
1717
- Fixed false positive RV_EXCEPTION_NOT_THROWN when asserting to exception throws ([[#2628](https://github.com/spotbugs/spotbugs/issues/2628)])
18+
- Fix false positive CT_CONSTRUCTOR_THROW when supertype has final finalize ([[#2665](https://github.com/spotbugs/spotbugs/issues/2665)])
1819

1920
### Build
2021
- Fix deprecated GHA on '::set-output' by using GITHUB_OUTPUT ([[#2651](https://github.com/spotbugs/spotbugs/pull/2651)])

spotbugs-tests/src/test/java/edu/umd/cs/findbugs/detect/ConstructorThrowTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,19 @@ void testGoodConstructorThrowCheck11() {
190190
assertNumOfCTBugs(0);
191191
}
192192

193+
@Test
194+
void testGoodConstructorThrowCheck12() {
195+
performAnalysis("constructorthrow/ConstructorThrowNegativeTest12.class");
196+
assertNumOfCTBugs(0);
197+
}
198+
199+
@Test
200+
void testGoodConstructorThrowCheck13() {
201+
performAnalysis("constructorthrow/ConstructorThrowNegativeTest12.class",
202+
"constructorthrow/ConstructorThrowNegativeTest13.class");
203+
assertNumOfCTBugs(0);
204+
}
205+
193206
private void assertNumOfCTBugs(int num) {
194207
final BugInstanceMatcher bugTypeMatcher = new BugInstanceMatcherBuilder()
195208
.bugType("CT_CONSTRUCTOR_THROW").build();

spotbugs/src/main/java/edu/umd/cs/findbugs/detect/ConstructorThrow.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,29 @@ public void visit(JavaClass obj) {
7878
isFinalClass = true;
7979
return;
8080
}
81+
82+
isFinalFinalizer = hasFinalFinalizer(obj);
83+
try {
84+
for (JavaClass cl : obj.getSuperClasses()) {
85+
isFinalFinalizer |= hasFinalFinalizer(cl);
86+
}
87+
} catch (ClassNotFoundException e) {
88+
AnalysisContext.reportMissingClass(e);
89+
}
90+
8191
for (Method m : obj.getMethods()) {
8292
doVisitMethod(m);
83-
// Check for final finalizer.
84-
// Signature of the finalizer is also needed to be checked
85-
if ("finalize".equals(m.getName()) && "()V".equals(m.getSignature()) && m.isFinal()) {
86-
isFinalFinalizer = true;
87-
}
8893
}
8994
isFirstPass = false;
9095
}
9196

97+
private static boolean hasFinalFinalizer(JavaClass jc) {
98+
// Check for final finalizer.
99+
// Signature of the finalizer is also needed to be checked
100+
return Arrays.stream(jc.getMethods())
101+
.anyMatch(m -> "finalize".equals(m.getName()) && "()V".equals(m.getSignature()) && m.isFinal());
102+
}
103+
92104
@Override
93105
public void visit(Method obj) {
94106
if (isFinalClass || isFinalFinalizer) {
@@ -135,7 +147,6 @@ public void sawOpcode(int seen) {
135147
/**
136148
* Reports ContructorThrow bug if there is an unhandled unchecked exception thrown directly or indirectly
137149
* from the currently visited method.
138-
*
139150
* If the exception is thrown directly, the bug is reported at the throw.
140151
* If the exception is thrown indirectly (through a method call), the bug is reported at the call of the method
141152
* which throws the exception.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package constructorthrow;
2+
3+
/**
4+
* However the constructor throws an unchecked exception, there is an empty finalize in this class.
5+
*/
6+
public class ConstructorThrowNegativeTest12 {
7+
public ConstructorThrowNegativeTest12() {
8+
throw new RuntimeException(); // No error, final finalize.
9+
}
10+
11+
@Override
12+
protected final void finalize(){}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package constructorthrow;
2+
3+
/**
4+
* However there is an unchecked exception thrown from the constructor, the superclass contains a final finalize.
5+
* @see <a href="https://github.com/spotbugs/spotbugs/issues/2665">GitHub issue</a>
6+
*/
7+
public class ConstructorThrowNegativeTest13 extends ConstructorThrowNegativeTest12 {
8+
public ConstructorThrowNegativeTest13() {
9+
throw new RuntimeException(); // No error, final finalize.
10+
}
11+
}

0 commit comments

Comments
 (0)