Merge pull request #9876 from smowton/smowton/feature/interface-forwarding

Kotlin: implement default interface forwarding
This commit is contained in:
Chris Smowton
2022-10-20 10:17:47 +01:00
committed by GitHub
26 changed files with 474 additions and 35 deletions

View File

@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.ir.IrElement
@@ -845,10 +846,68 @@ open class KotlinFileExtractor(
}
}
private fun isKotlinDefinedInterface(cls: IrClass?) =
cls != null && cls.isInterface && cls.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
private fun needsInterfaceForwarder(f: IrFunction) =
// forAllMethodsWithBody means -Xjvm-default=all or all-compatibility, in which case real Java default interfaces are used, and we don't need to do anything.
// Otherwise, for a Kotlin-defined method inheriting a Kotlin-defined default, we need to create a synthetic method like
// `int f(int x) { return super.InterfaceWithDefault.f(x); }`, because kotlinc will generate a public method and Java callers may directly target it.
// (NB. kotlinc's actual implementation strategy is different -- it makes an inner class called InterfaceWithDefault$DefaultImpls and stores the default methods
// there to allow default method usage in Java < 8, but this is hopefully niche.
!pluginContext.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode).forAllMethodsWithBody &&
f.parentClassOrNull.let { it != null && it.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && it.modality != Modality.ABSTRACT } &&
f.realOverrideTarget.let { it != f && (it as? IrSimpleFunction)?.modality != Modality.ABSTRACT && isKotlinDefinedInterface(it.parentClassOrNull) }
private fun makeInterfaceForwarder(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
forceExtractFunction(f, parentId, extractBody = false, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, overriddenAttributes = OverriddenFunctionAttributes(visibility = DescriptorVisibilities.PUBLIC)).also { functionId ->
tw.writeCompiler_generated(functionId, CompilerGeneratedKinds.INTERFACE_FORWARDER.kind)
if (extractBody) {
val realFunctionLocId = tw.getLocation(f)
val inheritedDefaultFunction = f.realOverrideTarget
val directlyInheritedSymbol =
when(f) {
is IrSimpleFunction ->
f.overriddenSymbols.find { it.owner === inheritedDefaultFunction }
?: f.overriddenSymbols.find { it.owner.realOverrideTarget === inheritedDefaultFunction }
?: inheritedDefaultFunction.symbol
else -> inheritedDefaultFunction.symbol // This is strictly invalid, since we shouldn't use A.super.f(...) where A may not be a direct supertype, but this path should also be unreachable.
}
val defaultDefiningInterfaceType = (directlyInheritedSymbol.owner.parentClassOrNull ?: return functionId).typeWith()
extractExpressionBody(functionId, realFunctionLocId).also { returnId ->
extractRawMethodAccess(
f,
realFunctionLocId,
f.returnType,
functionId,
returnId,
0,
returnId,
f.valueParameters.size,
{ argParentId, idxOffset ->
f.valueParameters.mapIndexed { idx, param ->
val syntheticParamId = useValueParameter(param, functionId)
extractVariableAccess(syntheticParamId, param.type, realFunctionLocId, argParentId, idxOffset + idx, functionId, returnId)
}
},
f.dispatchReceiverParameter?.type,
{ callId ->
extractSuperAccess(defaultDefiningInterfaceType, functionId, callId, -1, returnId, realFunctionLocId)
},
null
)
}
}
}
private fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
if (isFake(f))
null
else {
if (isFake(f)) {
if (needsInterfaceForwarder(f))
makeInterfaceForwarder(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses)
else
null
} else {
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
// The defaults-forwarder function is a static utility, not a member, so we only need to extract this for the unspecialised instance of this class.
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
@@ -1163,7 +1222,7 @@ open class KotlinFileExtractor(
extractBody(body, id)
}
extractVisibility(f, id, f.visibility)
extractVisibility(f, id, overriddenAttributes?.visibility ?: f.visibility)
if (f.isInline) {
addModifiers(id, "inline")
@@ -1227,7 +1286,9 @@ open class KotlinFileExtractor(
private fun extractProperty(p: IrProperty, parentId: Label<out DbReftype>, extractBackingField: Boolean, extractFunctionBodies: Boolean, extractPrivateMembers: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) {
with("property", p) {
if (isFake(p)) return
fun needsInterfaceForwarderQ(f: IrFunction?) = f?.let { needsInterfaceForwarder(f) } ?: false
if (isFake(p) && !needsInterfaceForwarderQ(p.getter) && !needsInterfaceForwarderQ(p.setter)) return
DeclarationStackAdjuster(p).use {
@@ -5375,7 +5436,9 @@ open class KotlinFileExtractor(
val sourceLoc: Label<DbLocation>? = null,
val valueParameters: List<IrValueParameter>? = null,
val typeParameters: List<IrTypeParameter>? = null,
val isStatic: Boolean? = null)
val isStatic: Boolean? = null,
val visibility: DescriptorVisibility? = null,
)
private fun peekDeclStackAsDeclarationParent(elementToReportOn: IrElement): IrDeclarationParent? {
val trapWriter = tw
@@ -5400,6 +5463,7 @@ open class KotlinFileExtractor(
DELEGATED_PROPERTY_SETTER(7),
JVMSTATIC_PROXY_METHOD(8),
JVMOVERLOADS_METHOD(9),
DEFAULT_ARGUMENTS_METHOD(10)
DEFAULT_ARGUMENTS_METHOD(10),
INTERFACE_FORWARDER(11),
}
}

View File

@@ -425,6 +425,15 @@ app/src/main/kotlin/testProject/App.kt:
# 7| -1: [ThisAccess] $serializer.this
# 7| 0: [TypeAccess] $serializer
# 7| 1: [VarAccess] tmp0_serialDesc
# 7| 7: [Method] typeParametersSerializers
# 7| 3: [TypeAccess] KSerializer<?>[]
# 7| 0: [TypeAccess] KSerializer<?>
# 7| 0: [WildcardTypeAccess] ? ...
# 7| 5: [BlockStmt] { ... }
# 7| 0: [ReturnStmt] return ...
# 7| 0: [MethodAccess] typeParametersSerializers(...)
# 7| -1: [SuperAccess] GeneratedSerializer.super
# 7| 0: [TypeAccess] GeneratedSerializer
# 7| 11: [Class] Companion
# 0| 1: [Method] serializer
# 0| 3: [TypeAccess] KSerializer<Project>

View File

@@ -0,0 +1,25 @@
public class User {
public static void sink(int x) { }
// Real is compiled with synthetic interface method forwarders, so it appears from a Java perspective to override the interface Test.
// RealNoForwards is compiled with -Xjvm-default=all, meaning real Java 8 default interface methods are used, no synthetic forwarders
// are created, and call resolution should go straight to the default.
// RealIndirect is similar to Real, except it inherits its methods indirectly via MiddleInterface.
public static void test(Real r1, RealNoForwards r2, RealIndirect r3) {
sink(r1.f());
sink(r1.g(2));
sink(r1.getX());
sink(r2.f());
sink(r2.g(5));
sink(r2.getX());
sink(r3.f());
sink(r3.g(8));
sink(r3.getX());
}
}

View File

@@ -0,0 +1,12 @@
interface NoForwards {
fun f() = 4
fun g(x: Int) = x
val x : Int
get() = 6
}
class RealNoForwards : NoForwards { }

View File

@@ -0,0 +1,36 @@
callables
| User.java:1:14:1:17 | User | User.java:1:14:1:17 | User | from source |
| User.java:3:22:3:25 | sink | User.java:1:14:1:17 | User | from source |
| User.java:9:22:9:25 | test | User.java:1:14:1:17 | User | from source |
| noforwards.kt:3:3:3:13 | f | noforwards.kt:1:1:10:1 | NoForwards | from source |
| noforwards.kt:5:3:5:19 | g | noforwards.kt:1:1:10:1 | NoForwards | from source |
| noforwards.kt:8:5:8:13 | getX | noforwards.kt:1:1:10:1 | NoForwards | from source |
| noforwards.kt:12:1:12:37 | RealNoForwards | noforwards.kt:12:1:12:37 | RealNoForwards | from source |
| test.kt:3:3:3:13 | f | test.kt:1:1:10:1 | Test | from source |
| test.kt:5:3:5:19 | g | test.kt:1:1:10:1 | Test | from source |
| test.kt:8:5:8:13 | getX | test.kt:1:1:10:1 | Test | from source |
| test.kt:12:1:12:21 | Real | test.kt:12:1:12:21 | Real | from source |
| test.kt:12:1:12:21 | f | test.kt:12:1:12:21 | Real | Forwarder for a Kotlin class inheriting an interface default method |
| test.kt:12:1:12:21 | g | test.kt:12:1:12:21 | Real | Forwarder for a Kotlin class inheriting an interface default method |
| test.kt:12:1:12:21 | getX | test.kt:12:1:12:21 | Real | Forwarder for a Kotlin class inheriting an interface default method |
| test.kt:16:1:16:40 | RealIndirect | test.kt:16:1:16:40 | RealIndirect | from source |
| test.kt:16:1:16:40 | f | test.kt:16:1:16:40 | RealIndirect | Forwarder for a Kotlin class inheriting an interface default method |
| test.kt:16:1:16:40 | g | test.kt:16:1:16:40 | RealIndirect | Forwarder for a Kotlin class inheriting an interface default method |
| test.kt:16:1:16:40 | getX | test.kt:16:1:16:40 | RealIndirect | Forwarder for a Kotlin class inheriting an interface default method |
superAccesses
| test.kt:12:1:12:21 | Test.super | test.kt:12:1:12:21 | Real | test.kt:12:1:12:21 | f | test.kt:12:1:12:21 | Test |
| test.kt:12:1:12:21 | Test.super | test.kt:12:1:12:21 | Real | test.kt:12:1:12:21 | g | test.kt:12:1:12:21 | Test |
| test.kt:12:1:12:21 | Test.super | test.kt:12:1:12:21 | Real | test.kt:12:1:12:21 | getX | test.kt:12:1:12:21 | Test |
| test.kt:16:1:16:40 | MiddleInterface.super | test.kt:16:1:16:40 | RealIndirect | test.kt:16:1:16:40 | f | test.kt:16:1:16:40 | MiddleInterface |
| test.kt:16:1:16:40 | MiddleInterface.super | test.kt:16:1:16:40 | RealIndirect | test.kt:16:1:16:40 | g | test.kt:16:1:16:40 | MiddleInterface |
| test.kt:16:1:16:40 | MiddleInterface.super | test.kt:16:1:16:40 | RealIndirect | test.kt:16:1:16:40 | getX | test.kt:16:1:16:40 | MiddleInterface |
#select
| User.java:12:15:12:15 | 2 | User.java:12:10:12:16 | g(...) |
| User.java:16:15:16:15 | 5 | User.java:16:10:16:16 | g(...) |
| User.java:20:15:20:15 | 8 | User.java:20:10:20:16 | g(...) |
| noforwards.kt:3:13:3:13 | 4 | User.java:15:10:15:15 | f(...) |
| noforwards.kt:8:13:8:13 | 6 | User.java:17:10:17:18 | getX(...) |
| test.kt:3:13:3:13 | 1 | User.java:11:10:11:15 | f(...) |
| test.kt:3:13:3:13 | 1 | User.java:19:10:19:15 | f(...) |
| test.kt:8:13:8:13 | 3 | User.java:13:10:13:18 | getX(...) |
| test.kt:8:13:8:13 | 3 | User.java:21:10:21:18 | getX(...) |

View File

@@ -0,0 +1,16 @@
interface Test {
fun f() = 1
fun g(x: Int) = x
val x : Int
get() = 3
}
class Real : Test { }
interface MiddleInterface : Test { }
class RealIndirect : MiddleInterface { }

View File

@@ -0,0 +1,6 @@
from create_database_utils import *
import glob
os.mkdir('build')
run_codeql_database_create(["kotlinc test.kt -d build", "kotlinc noforwards.kt -d build -Xjvm-default=all", "javac User.java -cp build"], lang="java")

View File

@@ -0,0 +1,36 @@
import java
import semmle.code.java.dataflow.DataFlow
query predicate callables(Callable c, RefType declType, string kind) {
c.fromSource() and
declType = c.getDeclaringType() and
(
kind = c.compilerGeneratedReason()
or
not exists(c.compilerGeneratedReason()) and kind = "from source"
)
}
query predicate superAccesses(
SuperAccess sa, RefType enclosingType, Callable enclosingCallable, Expr qualifier
) {
sa.getQualifier() = qualifier and
enclosingCallable = sa.getEnclosingCallable() and
enclosingType = enclosingCallable.getDeclaringType()
}
class Config extends DataFlow::Configuration {
Config() { this = "testconfig" }
override predicate isSource(DataFlow::Node x) {
x.asExpr() instanceof IntegerLiteral and x.getEnclosingCallable().fromSource()
}
override predicate isSink(DataFlow::Node x) {
x.asExpr().(Argument).getCall().getCallee().getName() = "sink"
}
}
from Config c, DataFlow::Node source, DataFlow::Node sink
where c.hasFlow(source, sink)
select source, sink

View File

@@ -67,6 +67,8 @@ class Element extends @element, Top {
i = 9 and result = "Forwarder for a @JvmOverloads-annotated function"
or
i = 10 and result = "Forwarder for Kotlin calls that need default arguments filling in"
or
i = 11 and result = "Forwarder for a Kotlin class inheriting an interface default method"
)
}
}
@@ -77,7 +79,18 @@ class Element extends @element, Top {
private predicate hasChildElement(Element parent, Element e) {
cupackage(e, parent)
or
enclInReftype(e, parent)
enclInReftype(e, parent) and
not e instanceof LocalClassOrInterface
or
// Reasoning: any specialised instance of a local class is supposed to belong to the general
// case of its enclosing method because we don't instantiate specialised variants of either generic
// functions or function bodies, and therefore the local class cannot be specialised with respect
// to its enclosing reftypes.
e.(LocalClassOrInterface)
.getSourceDeclaration()
.(LocalClassOrInterface)
.getLocalTypeDeclStmt()
.getEnclosingCallable() = parent
or
not enclInReftype(e, _) and
e.(Class).getCompilationUnit() = parent

View File

@@ -471,7 +471,12 @@ class Method extends Callable, @method {
}
override predicate isAbstract() {
Callable.super.isAbstract()
// The combination `abstract default` isn't legal in Java,
// but it occurs when the Kotlin extractor records a default
// body, but the output class file in fact uses an abstract
// method and an associated static helper, which we don't
// extract as an implementation detail.
Callable.super.isAbstract() and not this.isDefault()
or
// JLS 9.4: An interface method lacking a `private`, `default`, or `static` modifier
// is implicitly abstract.

View File

@@ -107,7 +107,21 @@ classes.kt:
# 28| 5: [BlockStmt] { ... }
# 28| 0: [SuperConstructorInvocationStmt] super(...)
# 28| 1: [BlockStmt] { ... }
# 29| 2: [Constructor] ClassSix
# 28| 2: [Method] funIF1
# 28| 3: [TypeAccess] Unit
# 28| 5: [BlockStmt] { ... }
# 28| 0: [ReturnStmt] return ...
# 28| 0: [MethodAccess] funIF1(...)
# 28| -1: [SuperAccess] IF1.super
# 28| 0: [TypeAccess] IF1
# 28| 3: [Method] funIF2
# 28| 3: [TypeAccess] Unit
# 28| 5: [BlockStmt] { ... }
# 28| 0: [ReturnStmt] return ...
# 28| 0: [MethodAccess] funIF2(...)
# 28| -1: [SuperAccess] IF2.super
# 28| 0: [TypeAccess] IF2
# 29| 4: [Constructor] ClassSix
#-----| 4: (Parameters)
# 29| 0: [Parameter] i
# 29| 0: [TypeAccess] int
@@ -725,6 +739,20 @@ generic_anonymous.kt:
# 26| 5: [BlockStmt] { ... }
# 26| 0: [SuperConstructorInvocationStmt] super(...)
# 26| 1: [BlockStmt] { ... }
# 26| 2: [Method] fn0
# 26| 3: [TypeAccess] U2
# 26| 5: [BlockStmt] { ... }
# 26| 0: [ReturnStmt] return ...
# 26| 0: [MethodAccess] fn0(...)
# 26| -1: [SuperAccess] C0.super
# 26| 0: [TypeAccess] C0
# 26| 3: [Method] fn1
# 26| 3: [TypeAccess] U3
# 26| 5: [BlockStmt] { ... }
# 26| 0: [ReturnStmt] return ...
# 26| 0: [MethodAccess] fn1(...)
# 26| -1: [SuperAccess] C1.super
# 26| 0: [TypeAccess] C1
# 26| 1: [ExprStmt] <Expr>;
# 26| 0: [ClassInstanceExpr] new (...)
# 26| -3: [TypeAccess] Object
@@ -739,6 +767,20 @@ generic_anonymous.kt:
# 27| 5: [BlockStmt] { ... }
# 27| 0: [SuperConstructorInvocationStmt] super(...)
# 27| 1: [BlockStmt] { ... }
# 27| 2: [Method] fn0
# 27| 3: [TypeAccess] U2
# 27| 5: [BlockStmt] { ... }
# 27| 0: [ReturnStmt] return ...
# 27| 0: [MethodAccess] fn0(...)
# 27| -1: [SuperAccess] C0.super
# 27| 0: [TypeAccess] C0
# 27| 3: [Method] fn1
# 27| 3: [TypeAccess] U2
# 27| 5: [BlockStmt] { ... }
# 27| 0: [ReturnStmt] return ...
# 27| 0: [MethodAccess] fn1(...)
# 27| -1: [SuperAccess] C1.super
# 27| 0: [TypeAccess] C1
# 27| 1: [ExprStmt] <Expr>;
# 27| 0: [ClassInstanceExpr] new (...)
# 27| -3: [TypeAccess] Object
@@ -753,6 +795,20 @@ generic_anonymous.kt:
# 28| 5: [BlockStmt] { ... }
# 28| 0: [SuperConstructorInvocationStmt] super(...)
# 28| 1: [BlockStmt] { ... }
# 28| 2: [Method] fn0
# 28| 3: [TypeAccess] U2
# 28| 5: [BlockStmt] { ... }
# 28| 0: [ReturnStmt] return ...
# 28| 0: [MethodAccess] fn0(...)
# 28| -1: [SuperAccess] C0.super
# 28| 0: [TypeAccess] C0
# 28| 3: [Method] fn1
# 28| 3: [TypeAccess] String
# 28| 5: [BlockStmt] { ... }
# 28| 0: [ReturnStmt] return ...
# 28| 0: [MethodAccess] fn1(...)
# 28| -1: [SuperAccess] C1.super
# 28| 0: [TypeAccess] C1
# 28| 1: [ExprStmt] <Expr>;
# 28| 0: [ClassInstanceExpr] new (...)
# 28| -3: [TypeAccess] Object
@@ -767,6 +823,13 @@ generic_anonymous.kt:
# 29| 5: [BlockStmt] { ... }
# 29| 0: [SuperConstructorInvocationStmt] super(...)
# 29| 1: [BlockStmt] { ... }
# 29| 2: [Method] fn0
# 29| 3: [TypeAccess] U2
# 29| 5: [BlockStmt] { ... }
# 29| 0: [ReturnStmt] return ...
# 29| 0: [MethodAccess] fn0(...)
# 29| -1: [SuperAccess] C0.super
# 29| 0: [TypeAccess] C0
# 29| 1: [ExprStmt] <Expr>;
# 29| 0: [ClassInstanceExpr] new (...)
# 29| -3: [TypeAccess] C0<U2>
@@ -781,6 +844,13 @@ generic_anonymous.kt:
# 30| 5: [BlockStmt] { ... }
# 30| 0: [SuperConstructorInvocationStmt] super(...)
# 30| 1: [BlockStmt] { ... }
# 30| 2: [Method] fn0
# 30| 3: [TypeAccess] String
# 30| 5: [BlockStmt] { ... }
# 30| 0: [ReturnStmt] return ...
# 30| 0: [MethodAccess] fn0(...)
# 30| -1: [SuperAccess] C0.super
# 30| 0: [TypeAccess] C0
# 30| 1: [ExprStmt] <Expr>;
# 30| 0: [ClassInstanceExpr] new (...)
# 30| -3: [TypeAccess] C0<String>

View File

@@ -52,26 +52,58 @@
| generic_anonymous.kt:25:9:31:9 | Unit | Unit |
| generic_anonymous.kt:26:13:26:37 | <Stmt> | new Object(...) { ... } |
| generic_anonymous.kt:26:13:26:37 | <implicit coercion to unit> | Unit |
| generic_anonymous.kt:26:13:26:37 | C0 | C0 |
| generic_anonymous.kt:26:13:26:37 | C0.super | C0 |
| generic_anonymous.kt:26:13:26:37 | C1 | C1 |
| generic_anonymous.kt:26:13:26:37 | C1.super | C1 |
| generic_anonymous.kt:26:13:26:37 | Object | Object |
| generic_anonymous.kt:26:13:26:37 | U2 | U2 |
| generic_anonymous.kt:26:13:26:37 | U3 | U3 |
| generic_anonymous.kt:26:13:26:37 | Unit | Unit |
| generic_anonymous.kt:26:13:26:37 | fn0(...) | U2 |
| generic_anonymous.kt:26:13:26:37 | fn1(...) | U3 |
| generic_anonymous.kt:26:13:26:37 | new (...) | new Object(...) { ... } |
| generic_anonymous.kt:27:13:27:37 | <Stmt> | new Object(...) { ... } |
| generic_anonymous.kt:27:13:27:37 | <implicit coercion to unit> | Unit |
| generic_anonymous.kt:27:13:27:37 | C0 | C0 |
| generic_anonymous.kt:27:13:27:37 | C0.super | C0 |
| generic_anonymous.kt:27:13:27:37 | C1 | C1 |
| generic_anonymous.kt:27:13:27:37 | C1.super | C1 |
| generic_anonymous.kt:27:13:27:37 | Object | Object |
| generic_anonymous.kt:27:13:27:37 | U2 | U2 |
| generic_anonymous.kt:27:13:27:37 | U2 | U2 |
| generic_anonymous.kt:27:13:27:37 | Unit | Unit |
| generic_anonymous.kt:27:13:27:37 | fn0(...) | U2 |
| generic_anonymous.kt:27:13:27:37 | fn1(...) | U2 |
| generic_anonymous.kt:27:13:27:37 | new (...) | new Object(...) { ... } |
| generic_anonymous.kt:28:13:28:41 | <Stmt> | new Object(...) { ... } |
| generic_anonymous.kt:28:13:28:41 | <implicit coercion to unit> | Unit |
| generic_anonymous.kt:28:13:28:41 | C0 | C0 |
| generic_anonymous.kt:28:13:28:41 | C0.super | C0 |
| generic_anonymous.kt:28:13:28:41 | C1 | C1 |
| generic_anonymous.kt:28:13:28:41 | C1.super | C1 |
| generic_anonymous.kt:28:13:28:41 | Object | Object |
| generic_anonymous.kt:28:13:28:41 | String | String |
| generic_anonymous.kt:28:13:28:41 | U2 | U2 |
| generic_anonymous.kt:28:13:28:41 | Unit | Unit |
| generic_anonymous.kt:28:13:28:41 | fn0(...) | U2 |
| generic_anonymous.kt:28:13:28:41 | fn1(...) | String |
| generic_anonymous.kt:28:13:28:41 | new (...) | new Object(...) { ... } |
| generic_anonymous.kt:29:13:29:29 | <Stmt> | new C0<U2>(...) { ... } |
| generic_anonymous.kt:29:13:29:29 | <implicit coercion to unit> | Unit |
| generic_anonymous.kt:29:13:29:29 | C0 | C0 |
| generic_anonymous.kt:29:13:29:29 | C0.super | C0 |
| generic_anonymous.kt:29:13:29:29 | C0<U2> | C0<U2> |
| generic_anonymous.kt:29:13:29:29 | U2 | U2 |
| generic_anonymous.kt:29:13:29:29 | Unit | Unit |
| generic_anonymous.kt:29:13:29:29 | fn0(...) | U2 |
| generic_anonymous.kt:29:13:29:29 | new (...) | new C0<U2>(...) { ... } |
| generic_anonymous.kt:30:13:30:33 | <Stmt> | new C0<String>(...) { ... } |
| generic_anonymous.kt:30:13:30:33 | <implicit coercion to unit> | Unit |
| generic_anonymous.kt:30:13:30:33 | C0 | C0 |
| generic_anonymous.kt:30:13:30:33 | C0.super | C0 |
| generic_anonymous.kt:30:13:30:33 | C0<String> | C0<String> |
| generic_anonymous.kt:30:13:30:33 | String | String |
| generic_anonymous.kt:30:13:30:33 | Unit | Unit |
| generic_anonymous.kt:30:13:30:33 | fn0(...) | String |
| generic_anonymous.kt:30:13:30:33 | new (...) | new C0<String>(...) { ... } |

View File

@@ -263,29 +263,42 @@ modifiers
| reflection.kt:162:25:162:45 | ...::... | reflection.kt:162:25:162:45 | invoke | override |
| reflection.kt:162:25:162:45 | ...::... | reflection.kt:162:25:162:45 | invoke | public |
compGenerated
| file://<external>/Class2.class:0:0:0:0 | getValue | 3 |
| file://<external>/Class2.class:0:0:0:0 | getValue | 3 |
| file://<external>/KTypeProjection.class:0:0:0:0 | contravariant | 8 |
| file://<external>/KTypeProjection.class:0:0:0:0 | copy$default | 10 |
| file://<external>/KTypeProjection.class:0:0:0:0 | covariant | 8 |
| file://<external>/KTypeProjection.class:0:0:0:0 | invariant | 8 |
| reflection.kt:33:9:33:23 | getP0 | 3 |
| reflection.kt:34:9:34:23 | getP1 | 3 |
| reflection.kt:34:9:34:23 | setP1 | 3 |
| reflection.kt:83:17:83:28 | getValue | 3 |
| reflection.kt:105:18:105:31 | getProp1 | 3 |
| reflection.kt:105:18:105:31 | setProp1 | 3 |
| reflection.kt:126:9:126:13 | | 1 |
| reflection.kt:131:1:131:50 | takesOptionalParam$default | 10 |
| reflection.kt:134:21:134:40 | | 1 |
| reflection.kt:140:5:140:54 | takesOptionalParam$default | 10 |
| reflection.kt:144:21:144:41 | | 1 |
| reflection.kt:145:32:145:70 | | 1 |
| reflection.kt:150:1:150:60 | extTakesOptionalParam$default | 10 |
| reflection.kt:153:21:153:44 | | 1 |
| reflection.kt:154:33:154:61 | | 1 |
| reflection.kt:157:1:157:49 | ConstructorOptional | 10 |
| reflection.kt:162:25:162:45 | | 1 |
| file://<external>/CharProgression.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/CharProgression.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/CharRange.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/CharRange.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/Class2.class:0:0:0:0 | getValue | Default property accessor |
| file://<external>/Class2.class:0:0:0:0 | getValue | Default property accessor |
| file://<external>/IntProgression.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/IntProgression.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/IntRange.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/IntRange.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/KTypeProjection.class:0:0:0:0 | contravariant | Proxy static method for a @JvmStatic-annotated function or property |
| file://<external>/KTypeProjection.class:0:0:0:0 | copy$default | Forwarder for Kotlin calls that need default arguments filling in |
| file://<external>/KTypeProjection.class:0:0:0:0 | covariant | Proxy static method for a @JvmStatic-annotated function or property |
| file://<external>/KTypeProjection.class:0:0:0:0 | invariant | Proxy static method for a @JvmStatic-annotated function or property |
| file://<external>/LongProgression.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/LongProgression.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/LongRange.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/LongRange.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file://<external>/String.class:0:0:0:0 | isEmpty | Forwarder for a Kotlin class inheriting an interface default method |
| reflection.kt:33:9:33:23 | getP0 | Default property accessor |
| reflection.kt:34:9:34:23 | getP1 | Default property accessor |
| reflection.kt:34:9:34:23 | setP1 | Default property accessor |
| reflection.kt:83:17:83:28 | getValue | Default property accessor |
| reflection.kt:105:18:105:31 | getProp1 | Default property accessor |
| reflection.kt:105:18:105:31 | setProp1 | Default property accessor |
| reflection.kt:126:9:126:13 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:131:1:131:50 | takesOptionalParam$default | Forwarder for Kotlin calls that need default arguments filling in |
| reflection.kt:134:21:134:40 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:140:5:140:54 | takesOptionalParam$default | Forwarder for Kotlin calls that need default arguments filling in |
| reflection.kt:144:21:144:41 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:145:32:145:70 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:150:1:150:60 | extTakesOptionalParam$default | Forwarder for Kotlin calls that need default arguments filling in |
| reflection.kt:153:21:153:44 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:154:33:154:61 | | Declaring classes of adapter functions in Kotlin |
| reflection.kt:157:1:157:49 | ConstructorOptional | Forwarder for Kotlin calls that need default arguments filling in |
| reflection.kt:162:25:162:45 | | Declaring classes of adapter functions in Kotlin |
propertyReferenceOverrides
| reflection.kt:10:38:10:42 | ...::... | reflection.kt:10:38:10:42 | get | kotlin.reflect.KProperty1<C,Integer>.get(Reflection.C) |
| reflection.kt:10:38:10:42 | ...::... | reflection.kt:10:38:10:42 | invoke | kotlin.jvm.functions.Function1<C,Integer>.invoke(Reflection.C) |

View File

@@ -86,7 +86,7 @@ query predicate modifiers(ClassInstanceExpr e, Method m, string modifier) {
m.hasModifier(modifier)
}
query predicate compGenerated(Element e, int i) { compiler_generated(e, i) }
query predicate compGenerated(Element e, string reason) { reason = e.compilerGeneratedReason() }
query predicate propertyReferenceOverrides(PropertyRefExpr e, Method m, string overridden) {
e.getAnonymousClass().getAMember() = m and

View File

@@ -13,6 +13,8 @@
| D | D |
| Diamond1 | Diamond1 |
| Diamond2 | Diamond2 |
| DoublyLocalClass | DoublyLocalClass |
| DoublyLocalClass | doublyLocalClassMethod |
| I1 | m1 |
| I1other | m1 |
| I2 | f |
@@ -26,6 +28,7 @@
| ITop | f2 |
| ITop | f3 |
| LocalClass | LocalClass |
| LocalClass | localClassMethod |
| LocalClass | n |
| MemberClass | MemberClass |
| Object | Object |

View File

@@ -2,6 +2,8 @@
| structure/A.java:7:2:7:4 | int | --none-- |
| structure/A.java:9:2:9:5 | void | m |
| structure/A.java:10:22:10:24 | int | --none-- |
| structure/A.java:10:29:10:32 | void | localClassMethod |
| structure/A.java:10:80:10:83 | void | doublyLocalClassMethod |
| structure/A.java:11:3:11:5 | m(...) | m |
| structure/A.java:15:17:15:17 | A | --none-- |
| structure/A.java:16:2:16:4 | int | --none-- |

View File

@@ -2,6 +2,8 @@
| structure/A.java:7:2:7:4 | int | --none-- |
| structure/A.java:9:2:9:5 | void | --none-- |
| structure/A.java:10:22:10:24 | int | --none-- |
| structure/A.java:10:29:10:32 | void | --none-- |
| structure/A.java:10:80:10:83 | void | --none-- |
| structure/A.java:11:3:11:5 | m(...) | stmt on line 11 |
| structure/A.java:15:17:15:17 | A | --none-- |
| structure/A.java:16:2:16:4 | int | --none-- |

View File

@@ -0,0 +1,27 @@
| structure/A.java:0:0:0:0 | A | structure/A.java:3:11:3:11 | I |
| structure/A.java:0:0:0:0 | A | structure/A.java:5:14:5:14 | A |
| structure/A.java:0:0:0:0 | A | structure/A.java:15:7:15:7 | B |
| structure/A.java:0:0:0:0 | A | structure/A.java:20:7:20:7 | C |
| structure/A.java:0:0:0:0 | A | structure/A.java:24:7:24:7 | D |
| structure/A.java:5:14:5:14 | A | structure/A.java:5:14:5:14 | A |
| structure/A.java:5:14:5:14 | A | structure/A.java:6:6:6:6 | x |
| structure/A.java:5:14:5:14 | A | structure/A.java:7:6:7:6 | y |
| structure/A.java:5:14:5:14 | A | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:9:7:9:7 | m |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:9:7:9:7 | m | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:15:7:15:7 | B | structure/A.java:15:7:15:7 | B |
| structure/A.java:15:7:15:7 | B | structure/A.java:16:6:16:6 | z |
| structure/A.java:15:7:15:7 | B | structure/A.java:17:12:17:26 | MemberInterface |
| structure/A.java:20:7:20:7 | C | structure/A.java:20:7:20:7 | C |
| structure/A.java:20:7:20:7 | C | structure/A.java:21:6:21:6 | w |
| structure/A.java:24:7:24:7 | D | structure/A.java:24:7:24:7 | <obinit> |
| structure/A.java:24:7:24:7 | D | structure/A.java:24:7:24:7 | D |
| structure/A.java:24:7:24:7 | D | structure/A.java:25:8:25:8 | new C(...) { ... } |
| structure/A.java:25:8:25:8 | new C(...) { ... } | structure/A.java:25:8:25:8 | |

View File

@@ -0,0 +1,7 @@
import java
from Element e1, Element e2
where
e1.hasChildElement(e2) and
e1.getFile().toString() = "A"
select e1, e2

View File

@@ -1,4 +1,6 @@
| structure/A.java:5:14:5:14 | A | structure/A.java:9:7:9:7 | m | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:15:7:15:7 | B | structure/A.java:9:7:9:7 | m | structure/A.java:5:14:5:14 | A |
| structure/A.java:24:7:24:7 | D | structure/A.java:9:7:9:7 | m | structure/A.java:5:14:5:14 | A |
| structure/A.java:24:7:24:7 | D | structure/A.java:24:7:24:7 | <obinit> | structure/A.java:24:7:24:7 | D |

View File

@@ -14,6 +14,14 @@
| structure/A.java:5:14:5:14 | A | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:26:10:26 | n |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:26:10:26 | n |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:5:14:5:14 | A | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:6:6:6:6 | x | structure/A.java:7:6:7:6 | y |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:6:6:6:6 | x |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:6:6:6:6 | x |
@@ -23,6 +31,10 @@
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:9:7:9:7 | m |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:9:7:9:7 | m | structure/A.java:6:6:6:6 | x |
| structure/A.java:9:7:9:7 | m | structure/A.java:7:6:7:6 | y |
| structure/A.java:9:7:9:7 | m | structure/A.java:10:26:10:26 | n |
@@ -38,8 +50,41 @@
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:9:7:9:7 | m |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:10:26:10:26 | n | structure/A.java:6:6:6:6 | x |
| structure/A.java:10:26:10:26 | n | structure/A.java:7:6:7:6 | y |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:6:6:6:6 | x |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:7:6:7:6 | y |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:9:7:9:7 | m |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:6:6:6:6 | x |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:6:6:6:6 | x |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:7:6:7:6 | y |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:7:6:7:6 | y |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:9:7:9:7 | m |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:9:7:9:7 | m |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:85:10:106 | doublyLocalClassMethod |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:6:6:6:6 | x |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:7:6:7:6 | y |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:9:7:9:7 | m |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:10:26:10:26 | n |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:10:34:10:49 | localClassMethod |
| structure/A.java:15:7:15:7 | B | structure/A.java:16:6:16:6 | z |
| structure/A.java:15:7:15:7 | B | structure/A.java:16:6:16:6 | z |
| structure/A.java:15:7:15:7 | B | structure/A.java:17:12:17:26 | MemberInterface |

View File

@@ -14,6 +14,17 @@
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:26:10:26 | n | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:26:10:26 | n | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:34:10:49 | localClassMethod | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:85:10:106 | doublyLocalClassMethod | structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:15:7:15:7 | B | structure/A.java:15:7:15:7 | B |
| structure/A.java:15:7:15:7 | B | structure/A.java:15:7:15:7 | B |
| structure/A.java:16:6:16:6 | z | structure/A.java:15:7:15:7 | B |

View File

@@ -1,4 +1,5 @@
| structure/A.java:8:8:8:18 | MemberClass | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:9:10:18 | LocalClass | structure/A.java:5:14:5:14 | A |
| structure/A.java:10:61:10:76 | DoublyLocalClass | structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:17:12:17:26 | MemberInterface | structure/A.java:15:7:15:7 | B |
| structure/A.java:25:8:25:8 | new C(...) { ... } | structure/A.java:24:7:24:7 | D |

View File

@@ -2,6 +2,7 @@
| structure/A.java:5:14:5:14 | A |
| structure/A.java:8:8:8:18 | MemberClass |
| structure/A.java:10:9:10:18 | LocalClass |
| structure/A.java:10:61:10:76 | DoublyLocalClass |
| structure/A.java:15:7:15:7 | B |
| structure/A.java:17:12:17:26 | MemberInterface |
| structure/A.java:20:7:20:7 | C |

View File

@@ -2,6 +2,7 @@
| structure/A.java:5:14:5:14 | A | file://:0:0:0:0 | structure |
| structure/A.java:8:8:8:18 | MemberClass | file://:0:0:0:0 | structure |
| structure/A.java:10:9:10:18 | LocalClass | file://:0:0:0:0 | structure |
| structure/A.java:10:61:10:76 | DoublyLocalClass | file://:0:0:0:0 | structure |
| structure/A.java:15:7:15:7 | B | file://:0:0:0:0 | structure |
| structure/A.java:17:12:17:26 | MemberInterface | file://:0:0:0:0 | structure |
| structure/A.java:20:7:20:7 | C | file://:0:0:0:0 | structure |

View File

@@ -7,7 +7,7 @@ public class A {
int y;
class MemberClass { }
void m() {
class LocalClass { int n; }
class LocalClass { int n; void localClassMethod() { class DoublyLocalClass { void doublyLocalClassMethod() { } } } }
m();
}
}