Skip to content

Commit 7812c56

Browse files
Copilotlaeubi
authored andcommitted
Fix false positive for static inner class implementing parent interface
When a static inner class implements its parent interface (e.g., StateObjectFactory containing StateObjectFactoryProxy implements StateObjectFactory), API tools was incorrectly reporting "implements non-API interface" leak warnings. Root cause: ReferenceExtractor.consider() only checked if referenced type starts with current type name (to exclude member type references), but didn't check the reverse case where current type is a member of referenced type. Fix: Added check in ReferenceExtractor.consider() to also exclude references when the current type name starts with referencedTypeName + "$", indicating a member type referencing its enclosing type. Test: Added Etest15.java test case and corresponding test methods in InterfaceExtendsLeak.java to verify static inner classes implementing parent interfaces don't produce false positive warnings.
1 parent a4050fe commit 7812c56

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/builder/tests/leak/InterfaceExtendsLeak.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,4 +371,28 @@ private void x14(boolean inc) {
371371
String typename = "Etest14"; //$NON-NLS-1$
372372
deployLeakTest(typename + ".java", inc);//$NON-NLS-1$
373373
}
374+
375+
/**
376+
* Tests that a static inner class implementing its parent interface does NOT produce
377+
* a leak warning (inner class referencing enclosing type should be excluded)
378+
* using a full build
379+
*/
380+
public void testStaticInnerClassImplementsParent15F() {
381+
x15(false);
382+
}
383+
384+
/**
385+
* Tests that a static inner class implementing its parent interface does NOT produce
386+
* a leak warning (inner class referencing enclosing type should be excluded)
387+
* using an incremental build
388+
*/
389+
public void testStaticInnerClassImplementsParent15I() {
390+
x15(true);
391+
}
392+
393+
private void x15(boolean inc) {
394+
expectingNoProblems();
395+
String typename = "Etest15"; //$NON-NLS-1$
396+
deployLeakTest(typename + ".java", inc);//$NON-NLS-1$
397+
}
374398
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package x.y.z;
15+
16+
/**
17+
* Test case for static inner class implementing parent interface.
18+
* This pattern should NOT produce a leak warning as the inner class
19+
* is referencing its enclosing type which has the same visibility.
20+
*/
21+
public interface Etest15 {
22+
23+
/**
24+
* Static inner class implementing the parent interface.
25+
* This should not be reported as leaking non-API interface.
26+
*/
27+
static class Etest15Impl implements Etest15 {
28+
// Implementation
29+
}
30+
}

apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ReferenceExtractor.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,15 @@ protected boolean consider(Reference ref) {
10101010
}
10111011
return false;
10121012
}
1013+
// Also check the reverse: if this type is a member of the referenced type
1014+
// (e.g., inner class referencing its enclosing type)
1015+
if (fType.getName().startsWith(referencedTypeName)) {
1016+
int refLength = referencedTypeName.length();
1017+
if (fType.getName().length() > refLength && fType.getName().charAt(refLength) == '$') {
1018+
// This is a member type referencing its enclosing type - exclude it
1019+
return false;
1020+
}
1021+
}
10131022
return true;
10141023
}
10151024

0 commit comments

Comments
 (0)