Skip to content

Commit 28c05e7

Browse files
authored
Merge pull request #9704 from smowton/smowton/fix/generic-inner-class
Kotlin: note that raw inner classes nest within a raw outer
2 parents 51e3ff9 + ab52a02 commit 28c05e7

File tree

7 files changed

+176
-3
lines changed

7 files changed

+176
-3
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.github.codeql.utils.versions.functionN
66
import com.github.codeql.utils.versions.getIrStubFromDescriptor
77
import com.semmle.extractor.java.OdasaOutput
88
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
9+
import org.jetbrains.kotlin.backend.common.lower.parents
910
import org.jetbrains.kotlin.backend.common.pop
1011
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
1112
import org.jetbrains.kotlin.descriptors.*
@@ -314,8 +315,21 @@ open class KotlinFileExtractor(
314315
val locId = getLocation(c, argsIncludingOuterClasses)
315316
tw.writeHasLocation(id, locId)
316317

317-
// Extract the outer <-> inner class relationship, passing on any type arguments in excess to this class' parameters.
318-
extractEnclosingClass(c, id, locId, argsIncludingOuterClasses?.drop(c.typeParameters.size) ?: listOf())
318+
// Extract the outer <-> inner class relationship, passing on any type arguments in excess to this class' parameters if this is an inner class.
319+
// For example, in `class Outer<T> { inner class Inner<S> { } }`, `Inner<Int, String>` nests within `Outer<Int>` and raw `Inner<>` within `Outer<>`,
320+
// but for a similar non-`inner` (in Java terms, static nested) class both `Inner<Int>` and `Inner<>` nest within the unbound type `Outer`.
321+
val useBoundOuterType = (c.isInner || c.isLocal) && (c.parents.map { // Would use `firstNotNullOfOrNull`, but this doesn't exist in Kotlin 1.4
322+
when(it) {
323+
is IrClass -> when {
324+
it.typeParameters.isNotEmpty() -> true // Type parameters visible to this class -- extract an enclosing bound or raw type.
325+
!(it.isInner || it.isLocal) -> false // No type parameters seen yet, and this is a static class -- extract an enclosing unbound type.
326+
else -> null // No type parameters seen here, but may be visible enclosing type parameters; keep searching.
327+
}
328+
else -> null // Look through enclosing non-class entities (this may need to change)
329+
}
330+
}.firstOrNull { it != null } ?: false)
331+
332+
extractEnclosingClass(c, id, locId, if (useBoundOuterType) argsIncludingOuterClasses?.drop(c.typeParameters.size) else listOf())
319333

320334
return id
321335
}
@@ -458,7 +472,8 @@ open class KotlinFileExtractor(
458472
}
459473
}
460474

461-
private fun extractEnclosingClass(innerDeclaration: IrDeclaration, innerId: Label<out DbClassorinterface>, innerLocId: Label<DbLocation>, parentClassTypeArguments: List<IrTypeArgument>) {
475+
// If `parentClassTypeArguments` is null, the parent class is a raw type.
476+
private fun extractEnclosingClass(innerDeclaration: IrDeclaration, innerId: Label<out DbClassorinterface>, innerLocId: Label<DbLocation>, parentClassTypeArguments: List<IrTypeArgument>?) {
462477
with("enclosing class", innerDeclaration) {
463478
var parent: IrDeclarationParent? = innerDeclaration.parent
464479
while (parent != null) {

java/ql/integration-tests/posix-only/kotlin/nested_generic_types/JavaUser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ public static void test() {
2121
String result4 = d.identity("goodbye");
2222
Short result5 = e.returnSixth(1, "hello", 1.0f, 1.0, 1L, (short)1);
2323

24+
OuterGeneric<String>.InnerNotGeneric innerGetterTest = (new OuterGeneric<String>()).getInnerNotGeneric();
25+
OuterNotGeneric.InnerGeneric<String> innerGetterTest2 = (new OuterNotGeneric()).getInnerGeneric();
26+
27+
TypeParamVisibility<String> tpv = new TypeParamVisibility<String>();
28+
TypeParamVisibility<String>.VisibleBecauseInner<String> visibleBecauseInner = tpv.getVisibleBecauseInner();
29+
TypeParamVisibility<String>.VisibleBecauseInnerIndirectContainer.VisibleBecauseInnerIndirect<String> visibleBecauseInnerIndirect = tpv.getVisibleBecauseInnerIndirect();
30+
TypeParamVisibility.NotVisibleBecauseStatic<String> notVisibleBecauseStatic = tpv.getNotVisibleBecauseStatic();
31+
TypeParamVisibility.NotVisibleBecauseStaticIndirectContainer.NotVisibleBecauseStaticIndirect<String> notVisibleBecauseStaticIndirect = tpv.getNotVisibleBecauseStaticIndirect();
32+
2433
}
2534

2635
}

java/ql/integration-tests/posix-only/kotlin/nested_generic_types/KotlinUser.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ class User {
2222
val result4 = d.identity("goodbye")
2323
val result5 = e.returnSixth(1, "hello", 1.0f, 1.0, 1L, 1.toShort())
2424

25+
val innerGetterTest = OuterGeneric<String>().getInnerNotGeneric()
26+
val innerGetterTest2 = OuterNotGeneric().getInnerGeneric()
27+
28+
val tpv = TypeParamVisibility<String>()
29+
val visibleBecauseInner = tpv.getVisibleBecauseInner();
30+
val visibleBecauseInnerIndirect = tpv.getVisibleBecauseInnerIndirect()
31+
val notVisibleBecauseStatic = tpv.getNotVisibleBecauseStatic()
32+
val notVisibleBecauseStaticIndirect = tpv.getNotVisibleBecauseStaticIndirect()
33+
2534
}
2635

2736
}

java/ql/integration-tests/posix-only/kotlin/nested_generic_types/libsrc/extlib/OuterGeneric.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public class InnerNotGeneric {
88

99
}
1010

11+
public InnerNotGeneric getInnerNotGeneric() { return null; }
12+
1113
public class InnerGeneric<S> {
1214

1315
public <R> InnerGeneric(R r) { }

java/ql/integration-tests/posix-only/kotlin/nested_generic_types/libsrc/extlib/OuterNotGeneric.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,10 @@ public class InnerGeneric<S> {
88

99
}
1010

11+
public InnerGeneric<String> getInnerGeneric() {
12+
13+
return new InnerGeneric<String>();
14+
15+
}
16+
1117
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package extlib;
2+
3+
public class TypeParamVisibility<T> {
4+
5+
public class VisibleBecauseInner<S> { }
6+
7+
public class VisibleBecauseInnerIndirectContainer {
8+
9+
public class VisibleBecauseInnerIndirect<S> { }
10+
11+
}
12+
13+
public static class NotVisibleBecauseStatic<S> { }
14+
15+
public static class NotVisibleBecauseStaticIndirectContainer {
16+
17+
public class NotVisibleBecauseStaticIndirect<S> { }
18+
19+
}
20+
21+
public VisibleBecauseInner<String> getVisibleBecauseInner() { return new VisibleBecauseInner<String>(); }
22+
23+
public VisibleBecauseInnerIndirectContainer.VisibleBecauseInnerIndirect<String> getVisibleBecauseInnerIndirect() { return (new VisibleBecauseInnerIndirectContainer()).new VisibleBecauseInnerIndirect<String>(); }
24+
25+
public NotVisibleBecauseStatic<String> getNotVisibleBecauseStatic() { return new NotVisibleBecauseStatic(); }
26+
27+
public NotVisibleBecauseStaticIndirectContainer.NotVisibleBecauseStaticIndirect<String> getNotVisibleBecauseStaticIndirect() { return (new NotVisibleBecauseStaticIndirectContainer()).new NotVisibleBecauseStaticIndirect<String>(); }
28+
29+
}

0 commit comments

Comments
 (0)