Refine INSTANCE_ACCESS_BEFORE_SUPER_CALL check

- Detect usages of unitialized `this` as extension receiver argument
- Make it work within object literal created before super call

 #KT-9120 Fixed
 #KT-8289 Fixed
This commit is contained in:
Denis Zharkov
2015-12-17 16:49:11 +03:00
parent ba180f915a
commit 0d7c8635b3
17 changed files with 182 additions and 62 deletions
@@ -135,17 +135,22 @@ public class BodyResolver {
) { ) {
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations()); ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations());
final CallChecker callChecker = new ConstructorHeaderCallChecker(descriptor);
resolveFunctionBody(outerDataFlowInfo, trace, constructor, descriptor, declaringScope, resolveFunctionBody(outerDataFlowInfo, trace, constructor, descriptor, declaringScope,
new Function1<LexicalScope, DataFlowInfo>() { new Function1<LexicalScope, DataFlowInfo>() {
@Override @Override
public DataFlowInfo invoke(@NotNull LexicalScope headerInnerScope) { public DataFlowInfo invoke(@NotNull LexicalScope headerInnerScope) {
return resolveSecondaryConstructorDelegationCall(outerDataFlowInfo, trace, headerInnerScope, return resolveSecondaryConstructorDelegationCall(outerDataFlowInfo, trace, headerInnerScope,
constructor, descriptor, constructor, descriptor);
callChecker);
} }
}, },
callChecker); new Function1<LexicalScope, LexicalScope>() {
@Override
public LexicalScope invoke(LexicalScope scope) {
return new LexicalScopeImpl(
scope, descriptor, scope.isOwnerDescriptorAccessibleByLabel(), scope.getImplicitReceiver(),
LexicalScopeKind.CONSTRUCTOR_HEADER);
}
});
} }
@Nullable @Nullable
@@ -154,13 +159,11 @@ public class BodyResolver {
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@NotNull KtSecondaryConstructor constructor, @NotNull KtSecondaryConstructor constructor,
@NotNull ConstructorDescriptor descriptor, @NotNull ConstructorDescriptor descriptor
@NotNull CallChecker callChecker
) { ) {
OverloadResolutionResults<?> results = callResolver.resolveConstructorDelegationCall( OverloadResolutionResults<?> results = callResolver.resolveConstructorDelegationCall(
trace, scope, outerDataFlowInfo, trace, scope, outerDataFlowInfo,
descriptor, constructor.getDelegationCall(), descriptor, constructor.getDelegationCall());
callChecker);
if (results != null && results.isSingleResult()) { if (results != null && results.isSingleResult()) {
ResolvedCall<? extends CallableDescriptor> resolvedCall = results.getResultingCall(); ResolvedCall<? extends CallableDescriptor> resolvedCall = results.getResultingCall();
@@ -775,27 +778,29 @@ public class BodyResolver {
) { ) {
computeDeferredType(functionDescriptor.getReturnType()); computeDeferredType(functionDescriptor.getReturnType());
resolveFunctionBody(outerDataFlowInfo, trace, function, functionDescriptor, declaringScope, null, CallChecker.DoNothing.INSTANCE$); resolveFunctionBody(outerDataFlowInfo, trace, function, functionDescriptor, declaringScope, null, null);
assert functionDescriptor.getReturnType() != null; assert functionDescriptor.getReturnType() != null;
} }
public void resolveFunctionBody( private void resolveFunctionBody(
@NotNull DataFlowInfo outerDataFlowInfo, @NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull KtDeclarationWithBody function, @NotNull KtDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@Nullable Function1<LexicalScope, DataFlowInfo> beforeBlockBody, @Nullable Function1<LexicalScope, DataFlowInfo> beforeBlockBody,
@NotNull CallChecker callChecker // Creates wrapper scope for header resolution if necessary (see resolveSecondaryConstructorBody)
@Nullable Function1<LexicalScope, LexicalScope> headerScopeFactory
) { ) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace); PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace); LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace);
List<KtParameter> valueParameters = function.getValueParameters(); List<KtParameter> valueParameters = function.getValueParameters();
List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters();
LexicalScope headerScope = headerScopeFactory != null ? headerScopeFactory.invoke(innerScope) : innerScope;
valueParameterResolver.resolveValueParameters( valueParameterResolver.resolveValueParameters(
valueParameters, valueParameterDescriptors, innerScope, outerDataFlowInfo, trace, callChecker valueParameters, valueParameterDescriptors, headerScope, outerDataFlowInfo, trace
); );
// Synthetic "field" creation // Synthetic "field" creation
@@ -823,7 +828,7 @@ public class BodyResolver {
DataFlowInfo dataFlowInfo = null; DataFlowInfo dataFlowInfo = null;
if (beforeBlockBody != null) { if (beforeBlockBody != null) {
dataFlowInfo = beforeBlockBody.invoke(innerScope); dataFlowInfo = beforeBlockBody.invoke(headerScope);
} }
if (function.hasBody()) { if (function.hasBody()) {
@@ -19,40 +19,40 @@ package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
import org.jetbrains.kotlin.psi.KtInstanceExpressionWithLabel import org.jetbrains.kotlin.psi.KtInstanceExpressionWithLabel
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasImplicitThisOrSuperDispatchReceiver import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
public class ConstructorHeaderCallChecker(constructor: ConstructorDescriptor) : CallChecker { import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
private val containingClass = constructor.getContainingDeclaration()
public object ConstructorHeaderCallChecker : CallChecker {
override fun <F : CallableDescriptor> check(resolvedCall: ResolvedCall<F>, context: BasicCallResolutionContext) { override fun <F : CallableDescriptor> check(resolvedCall: ResolvedCall<F>, context: BasicCallResolutionContext) {
if (resolvedCall.getStatus().isSuccess() && val dispatchReceiverClass = resolvedCall.dispatchReceiver.classDescriptorForImplicitReceiver
resolvedCall.hasImplicitThisOrSuperDispatchReceiver(context.trace.getBindingContext()) && val extensionReceiverClass = resolvedCall.extensionReceiver.classDescriptorForImplicitReceiver
containingClass == resolvedCall.getResultingDescriptor().getOwnerForEffectiveDispatchReceiverParameter()
) {
reportError(context, resolvedCall)
}
else {
val callElement = resolvedCall.getCall().getCallElement()
if (callElement is KtInstanceExpressionWithLabel) {
val descriptor = context.trace.get(BindingContext.REFERENCE_TARGET, callElement.getInstanceReference())
if (containingClass == descriptor) {
reportError(context, resolvedCall)
}
}
}
}
private fun reportError(context: BasicCallResolutionContext, resolvedCall: ResolvedCall<*>) { val labelReferenceClass =
context.trace.report( (resolvedCall.call.callElement as? KtInstanceExpressionWithLabel)?.let {
Errors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(context.call.getCalleeExpression(), resolvedCall.getResultingDescriptor())) instanceExpressionWithLabel ->
context.trace.get(BindingContext.REFERENCE_TARGET, instanceExpressionWithLabel.instanceReference) as? ClassDescriptor
}
if (dispatchReceiverClass == null && extensionReceiverClass == null && labelReferenceClass == null) return
if (context.scope.parentsWithSelf.any() {
it is LexicalScope && it.kind == LexicalScopeKind.CONSTRUCTOR_HEADER
&& (it.ownerDescriptor as ConstructorDescriptor).containingDeclaration in
setOf(dispatchReceiverClass, extensionReceiverClass, labelReferenceClass)
}) {
context.trace.report(
Errors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(context.call.calleeExpression ?: return, resolvedCall.resultingDescriptor))
}
} }
} }
private val Receiver?.classDescriptorForImplicitReceiver: ClassDescriptor?
get() = (this as? ImplicitReceiver)?.declarationDescriptor as? ClassDescriptor
@@ -61,7 +61,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
InfixModifierChecker()) InfixModifierChecker())
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker()) SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
ConstructorHeaderCallChecker)
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>() private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), OperatorValidator(), InfixValidator()) private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), OperatorValidator(), InfixValidator())
@@ -387,7 +387,7 @@ public class CallResolver {
public OverloadResolutionResults<FunctionDescriptor> resolveConstructorDelegationCall( public OverloadResolutionResults<FunctionDescriptor> resolveConstructorDelegationCall(
@NotNull BindingTrace trace, @NotNull LexicalScope scope, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace, @NotNull LexicalScope scope, @NotNull DataFlowInfo dataFlowInfo,
@NotNull ConstructorDescriptor constructorDescriptor, @NotNull ConstructorDescriptor constructorDescriptor,
@NotNull KtConstructorDelegationCall call, @NotNull CallChecker callChecker @NotNull KtConstructorDelegationCall call
) { ) {
// Method returns `null` when there is nothing to resolve in trivial cases like `null` call expression or // Method returns `null` when there is nothing to resolve in trivial cases like `null` call expression or
// when super call should be conventional enum constructor and super call should be empty // when super call should be conventional enum constructor and super call should be empty
@@ -397,7 +397,7 @@ public class CallResolver {
CallMaker.makeCall(null, null, call), CallMaker.makeCall(null, null, call),
NO_EXPECTED_TYPE, NO_EXPECTED_TYPE,
dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
callChecker, false); CallChecker.DoNothing.INSTANCE, false);
if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context); if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context);
@@ -33,26 +33,18 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
// val x // val x
// val y = other.x // return false for `other.x` as it's receiver is not `this` // val y = other.x // return false for `other.x` as it's receiver is not `this`
// } // }
public fun ResolvedCall<*>.hasThisOrNoDispatchReceiver(context: BindingContext): Boolean = fun ResolvedCall<*>.hasThisOrNoDispatchReceiver(
hasThisOrNoDispatchReceiver(context, true, true) context: BindingContext
public fun ResolvedCall<*>.hasImplicitThisOrSuperDispatchReceiver(context: BindingContext): Boolean =
hasThisOrNoDispatchReceiver(context, false, false)
private fun ResolvedCall<*>.hasThisOrNoDispatchReceiver(
context: BindingContext,
returnForNoReceiver: Boolean,
considerExplicitReceivers: Boolean
): Boolean { ): Boolean {
val dispatchReceiverValue = getDispatchReceiver() val dispatchReceiverValue = dispatchReceiver
if (getResultingDescriptor().getDispatchReceiverParameter() == null || dispatchReceiverValue == null) return returnForNoReceiver if (resultingDescriptor.dispatchReceiverParameter == null || dispatchReceiverValue == null) return true
var dispatchReceiverDescriptor: DeclarationDescriptor? = null var dispatchReceiverDescriptor: DeclarationDescriptor? = null
if (dispatchReceiverValue is ImplicitReceiver) { if (dispatchReceiverValue is ImplicitReceiver) {
// foo() -- implicit receiver // foo() -- implicit receiver
dispatchReceiverDescriptor = dispatchReceiverValue.declarationDescriptor dispatchReceiverDescriptor = dispatchReceiverValue.declarationDescriptor
} }
else if (dispatchReceiverValue is ExpressionReceiver && considerExplicitReceivers) { else if (dispatchReceiverValue is ExpressionReceiver) {
val expression = KtPsiUtil.deparenthesize(dispatchReceiverValue.expression) val expression = KtPsiUtil.deparenthesize(dispatchReceiverValue.expression)
if (expression is KtThisExpression) { if (expression is KtThisExpression) {
// this.foo() -- explicit receiver // this.foo() -- explicit receiver
@@ -36,18 +36,16 @@ public class ValueParameterResolver(
private val constantExpressionEvaluator: ConstantExpressionEvaluator private val constantExpressionEvaluator: ConstantExpressionEvaluator
) { ) {
@JvmOverloads
public fun resolveValueParameters( public fun resolveValueParameters(
valueParameters: List<KtParameter>, valueParameters: List<KtParameter>,
valueParameterDescriptors: List<ValueParameterDescriptor>, valueParameterDescriptors: List<ValueParameterDescriptor>,
declaringScope: LexicalScope, declaringScope: LexicalScope,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
trace: BindingTrace, trace: BindingTrace
callChecker: CallChecker = CallChecker.DoNothing
) { ) {
val scopeForDefaultValue = LexicalScopeImpl(declaringScope, declaringScope.ownerDescriptor, false, null, LexicalScopeKind.DEFAULT_VALUE) val scopeForDefaultValue = LexicalScopeImpl(declaringScope, declaringScope.ownerDescriptor, false, null, LexicalScopeKind.DEFAULT_VALUE)
val contextForDefaultValue = ExpressionTypingContext.newContext(trace, scopeForDefaultValue, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, callChecker) val contextForDefaultValue = ExpressionTypingContext.newContext(trace, scopeForDefaultValue, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, CallChecker.DoNothing)
for ((descriptor, parameter) in valueParameterDescriptors.zip(valueParameters)) { for ((descriptor, parameter) in valueParameterDescriptors.zip(valueParameters)) {
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations()) ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations())
@@ -0,0 +1,15 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun A.foobar() = 3
class A {
fun foo() = 1
constructor(x: () -> Int)
constructor() : this(
{
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foo<!>() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this@A<!>.foo() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foobar<!>()
})
}
@@ -0,0 +1,12 @@
package
public fun A.foobar(): kotlin.Int
public final class A {
public constructor A()
public constructor A(/*0*/ x: () -> kotlin.Int)
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun A.foobar() = 3
class A {
fun foo() = 1
constructor(x: Any?)
constructor() : this(object {
fun bar() = <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this@A<!>.foo() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foobar<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super@A<!>.hashCode()
})
}
@@ -0,0 +1,12 @@
package
public fun A.foobar(): kotlin.Int
public final class A {
public constructor A()
public constructor A(/*0*/ x: kotlin.Any?)
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,11 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun A.foobar() = 3
class A {
fun foo() = 1
constructor( x: Any = object {
fun bar() = <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this@A<!>.foo() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foobar<!>()
})
}
@@ -0,0 +1,11 @@
package
public fun A.foobar(): kotlin.Int
public final class A {
public constructor A(/*0*/ x: kotlin.Any = ...)
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,15 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun A.foobar() = 1
val A.prop: Int get() = 2
class A {
constructor(x: Int)
constructor() : this(
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>foobar<!>() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foobar() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>prop<!> +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this@A<!>.prop
)
}
@@ -0,0 +1,12 @@
package
public val A.prop: kotlin.Int
public fun A.foobar(): kotlin.Int
public final class A {
public constructor A()
public constructor A(/*0*/ x: kotlin.Int)
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -14831,12 +14831,30 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("lambdaAsArgument.kt")
public void testLambdaAsArgument() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/lambdaAsArgument.kt");
doTest(fileName);
}
@TestMetadata("memberFunAccess.kt") @TestMetadata("memberFunAccess.kt")
public void testMemberFunAccess() throws Exception { public void testMemberFunAccess() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("objectLiteralAsArgument.kt")
public void testObjectLiteralAsArgument() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsArgument.kt");
doTest(fileName);
}
@TestMetadata("objectLiteralAsDefaultValueParameter.kt")
public void testObjectLiteralAsDefaultValueParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsDefaultValueParameter.kt");
doTest(fileName);
}
@TestMetadata("passingInstance.kt") @TestMetadata("passingInstance.kt")
public void testPassingInstance() throws Exception { public void testPassingInstance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt");
@@ -14873,6 +14891,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("thisAsExtensionReceiver.kt")
public void testThisAsExtensionReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/thisAsExtensionReceiver.kt");
doTest(fileName);
}
@TestMetadata("usingOuterInstance.kt") @TestMetadata("usingOuterInstance.kt")
public void testUsingOuterInstance() throws Exception { public void testUsingOuterInstance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.kt");
@@ -1 +1 @@
<error>a</error> + b + c + a1 <error>a</error> + b + <error>c</error> + <error>a1</error>
@@ -1 +1 @@
<error>a</error> + b + c + a1 <error>a</error> + b + <error>c</error> + <error>a1</error>