Public members should have bigger priority in debugContext

#KT-10634 Fixed
This commit is contained in:
Natalia Ukhorskaya
2016-01-28 15:11:15 +03:00
parent d60a5e65c1
commit b19d32e4f2
5 changed files with 102 additions and 14 deletions
@@ -19,15 +19,13 @@ package org.jetbrains.kotlin.resolve.calls.results
import gnu.trove.THashSet
import gnu.trove.TObjectHashingStrategy
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -42,7 +40,8 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
fun <D : CallableDescriptor> findMaximallySpecific(
candidates: Set<MutableResolvedCall<D>>,
checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean
discriminateGenerics: Boolean,
isDebuggerContext: Boolean
): MutableResolvedCall<D>? =
if (candidates.size <= 1)
candidates.firstOrNull()
@@ -56,7 +55,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
}.singleOrNull()
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
findMaximallySpecificCall(candidates, discriminateGenerics)
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
}
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(candidates: Set<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> {
@@ -67,7 +66,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
throw AssertionError("Regular call among variable-as-function calls: $it")
}
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false) ?: return emptySet()
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, false, false) ?: return emptySet()
return candidates.filterTo(newResolvedCallSet<MutableResolvedCall<D>>(2)) {
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor
@@ -76,7 +75,8 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
private fun <D : CallableDescriptor> findMaximallySpecificCall(
candidates: Set<MutableResolvedCall<D>>,
discriminateGenerics: Boolean
discriminateGenerics: Boolean,
isDebuggerContext: Boolean
): MutableResolvedCall<D>? {
val filteredCandidates = uniquifyCandidatesSet(candidates)
@@ -97,7 +97,10 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
}
}
return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 -> isOfNotLessSpecificShape(call1, call2) }?.resolvedCall
return bestCandidatesByParameterTypes.exactMaxWith {
call1, call2 ->
isOfNotLessSpecificShape(call1, call2) && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
}?.resolvedCall
}
private inline fun <C : Any> Collection<C>.exactMaxWith(isNotWorse: (C, C) -> Boolean): C? {
@@ -231,6 +234,22 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
return true
}
private fun <D: CallableDescriptor, K> isOfNotLessSpecificVisibilityForDebugger(
call1: CandidateCallWithArgumentMapping<D, K>,
call2: CandidateCallWithArgumentMapping<D, K>,
isDebuggerContext: Boolean
): Boolean {
if (isDebuggerContext) {
val isMoreVisible1 = Visibilities.compare(
call1.resolvedCall.resultingDescriptor.visibility,
call2.resolvedCall.resultingDescriptor.visibility
)
if (isMoreVisible1 != null && isMoreVisible1 < 0) return false
}
return true
}
/**
* Returns `true` if `d1` is definitely not less specific than `d2`,
* `false` if `d1` is definitely less specific than `d2`,
@@ -96,7 +96,8 @@ public class ResolutionResultsHandler {
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
successfulAndIncomplete.addAll(successfulCandidates);
successfulAndIncomplete.addAll(incompleteCandidates);
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true, checkArgumentsMode);
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(
successfulAndIncomplete, true, context.isDebuggerContext, checkArgumentsMode);
if (results.isSingleResult()) {
MutableResolvedCall<D> resultingCall = results.getResultingCall();
resultingCall.getTrace().moveAllMyDataTo(context.trace);
@@ -147,7 +148,7 @@ public class ResolutionResultsHandler {
if (severityLevel.contains(ARGUMENTS_MAPPING_ERROR)) {
return recordFailedInfo(tracing, trace, thisLevel);
}
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false, checkArgumentsMode);
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false, false, checkArgumentsMode);
return recordFailedInfo(tracing, trace, results.getResultingCalls());
}
}
@@ -188,6 +189,7 @@ public class ResolutionResultsHandler {
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
@NotNull Set<MutableResolvedCall<D>> candidates,
boolean discriminateGenerics,
boolean isDebuggerContext,
@NotNull CheckArgumentTypesMode checkArgumentsMode
) {
if (candidates.size() == 1) {
@@ -203,14 +205,14 @@ public class ResolutionResultsHandler {
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
}
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false);
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, checkArgumentsMode, false, isDebuggerContext);
if (maximallySpecific != null) {
return OverloadResolutionResultsImpl.success(maximallySpecific);
}
if (discriminateGenerics) {
MutableResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(
noOverrides, checkArgumentsMode, true);
noOverrides, checkArgumentsMode, true, isDebuggerContext);
if (maximallySpecificGenericsDiscriminated != null) {
return OverloadResolutionResultsImpl.success(maximallySpecificGenericsDiscriminated);
}
@@ -0,0 +1,14 @@
LineBreakpoint created at privateMembersPriority.kt:22
LineBreakpoint created at privateMembersPriority.kt:34
LineBreakpoint created at privateMembersPriority.kt:41
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! privateMembersPriority.PrivateMembersPriorityKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
privateMembersPriority.kt:22
Compile bytecode for privateFun()
privateMembersPriority.kt:34
Compile bytecode for javaClass.size
privateMembersPriority.kt:41
Compile bytecode for TwoPrivateFun().foo(1)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,47 @@
package privateMembersPriority
fun main(args: Array<String>) {
Receiver2().test1()
test2()
test3()
}
class Receiver1 {
private fun privateFun() = 1
}
class Receiver2 {
fun privateFun() = 2
// In IDE -> privateFun() will return 2, because privateFun from Receiver is invisible in current scope
fun test1() {
with(Receiver1()) {
// EXPRESSION: privateFun()
// RESULT: 1: I
//Breakpoint!
privateFun()
}
}
}
// In debuggerContext there are two properties size in ArrayList (java field + kotlin property)
fun test2() {
val javaClass = arrayListOf(1)
// EXPRESSION: javaClass.size
// RESULT: 1: I
//Breakpoint!
javaClass.size
}
fun test3() {
// EXPRESSION: TwoPrivateFun().foo(1)
// RESULT: 1: I
//Breakpoint!
val a = 1
}
class TwoPrivateFun {
private fun foo(i: Int) = 1
private fun foo(i: Double) = 2
}
@@ -778,6 +778,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
doMultipleBreakpointsTest(fileName);
}
@TestMetadata("privateMembersPriority.kt")
public void testPrivateMembersPriority() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/privateMembersPriority.kt");
doMultipleBreakpointsTest(fileName);
}
@TestMetadata("whenEntry.kt")
public void testWhenEntry() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/whenEntry.kt");