From 26c153639a9e9bc88285776e71176ea853a611a2 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Mon, 14 Mar 2016 16:01:10 +0300 Subject: [PATCH] Skip visibility check when resolving class in debug mode #KT-11326 Fixed --- .../resolve/QualifiedExpressionResolver.kt | 24 +++++++++------- .../kotlin/resolve/TypeResolutionContext.java | 11 +++++--- .../jetbrains/kotlin/resolve/TypeResolver.kt | 13 +++++---- .../BasicExpressionTypingVisitor.java | 7 ++--- .../PatternMatchingTypingVisitor.kt | 2 +- .../caches/resolve/CodeFragmentAnalyzer.kt | 3 +- .../ReplaceWithAnnotationAnalyzer.kt | 2 +- .../debugger/tinyApp/outs/privateClass.out | 11 ++++++++ .../evaluate/singleBreakpoint/privateClass.kt | 28 +++++++++++++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 6 ++++ 10 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/privateClass.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateClass.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index 603959e8d42..f02072a82ee 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.resolve.calls.CallExpressionElement import org.jetbrains.kotlin.resolve.calls.unrollToLeftMostQualifiedExpression import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -64,12 +65,14 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator fun resolveDescriptorForType( userType: KtUserType, scope: LexicalScope, - trace: BindingTrace + trace: BindingTrace, + isDebuggerContext: Boolean ): TypeQualifierResolutionResult { + val ownerDescriptor = if (!isDebuggerContext) scope.ownerDescriptor else null if (userType.qualifier == null && !userType.startWithPackage) { // optimization for non-qualified types val descriptor = userType.referenceExpression?.let { val classifier = scope.findClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it)) - storeResult(trace, it, classifier, scope.ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) + storeResult(trace, it, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) classifier } @@ -80,7 +83,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator val (qualifierPartList, hasError) = userType.asQualifierPartList() if (hasError) { val descriptor = resolveToPackageOrClass( - qualifierPartList, module, trace, scope.ownerDescriptor, scope, position = QualifierPosition.TYPE + qualifierPartList, module, trace, ownerDescriptor, scope, position = QualifierPosition.TYPE ) as? ClassifierDescriptor return TypeQualifierResolutionResult(qualifierPartList, descriptor) } @@ -90,7 +93,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator val qualifier = resolveToPackageOrClass( qualifierPartList.subList(0, qualifierPartList.size - 1), module, - trace, scope.ownerDescriptor, scope.check { !userType.startWithPackage }, position = QualifierPosition.TYPE + trace, ownerDescriptor, scope.check { !userType.startWithPackage }, position = QualifierPosition.TYPE ) ?: return TypeQualifierResolutionResult(qualifierPartList, null) val lastPart = qualifierPartList.last() @@ -99,7 +102,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location) else -> null } - storeResult(trace, lastPart.expression, classifier, scope.ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) + storeResult(trace, lastPart.expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) return TypeQualifierResolutionResult(qualifierPartList, classifier) } @@ -141,11 +144,12 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator val path = importedReference.asQualifierPartList(trace) val lastPart = path.lastOrNull() ?: return null val packageFragmentForCheck = - if (packageFragmentForVisibilityCheck is DeclarationDescriptorWithSource && packageFragmentForVisibilityCheck.source == SourceElement.NO_SOURCE) { - PackageFragmentWithCustomSource(packageFragmentForVisibilityCheck, KotlinSourceElement(importDirective.getContainingKtFile())) - } - else { - packageFragmentForVisibilityCheck + when { + importDirective.suppressDiagnosticsInDebugMode() -> null + packageFragmentForVisibilityCheck is DeclarationDescriptorWithSource && packageFragmentForVisibilityCheck.source == SourceElement.NO_SOURCE -> { + PackageFragmentWithCustomSource(packageFragmentForVisibilityCheck, KotlinSourceElement(importDirective.getContainingKtFile())) + } + else -> packageFragmentForVisibilityCheck } if (importDirective.isAllUnder) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java index 847ac8a83b1..7b4c5d2db21 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java @@ -25,9 +25,10 @@ public class TypeResolutionContext { public final boolean checkBounds; public final boolean allowBareTypes; public final boolean forceResolveLazyTypes; + public final boolean isDebuggerContext; - public TypeResolutionContext(@NotNull LexicalScope scope, @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes) { - this(scope, trace, checkBounds, allowBareTypes, allowBareTypes); + public TypeResolutionContext(@NotNull LexicalScope scope, @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes, boolean isDebuggerContext) { + this(scope, trace, checkBounds, allowBareTypes, allowBareTypes, isDebuggerContext); } private TypeResolutionContext( @@ -35,16 +36,18 @@ public class TypeResolutionContext { @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes, - boolean forceResolveLazyTypes + boolean forceResolveLazyTypes, + boolean isDebuggerContext ) { this.scope = scope; this.trace = trace; this.checkBounds = checkBounds; this.allowBareTypes = allowBareTypes; this.forceResolveLazyTypes = forceResolveLazyTypes; + this.isDebuggerContext = isDebuggerContext; } public TypeResolutionContext noBareTypes() { - return new TypeResolutionContext(scope, trace, checkBounds, false, forceResolveLazyTypes); + return new TypeResolutionContext(scope, trace, checkBounds, false, forceResolveLazyTypes, isDebuggerContext); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index b3b38f35fc3..023f90369d6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.codeFragmentUtil.debugTypeInfo +import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.debugText.getDebugText import org.jetbrains.kotlin.resolve.PossiblyBareType.type import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope @@ -65,7 +66,7 @@ class TypeResolver( fun resolveType(scope: LexicalScope, typeReference: KtTypeReference, trace: BindingTrace, checkBounds: Boolean): KotlinType { // bare types are not allowed - return resolveType(TypeResolutionContext(scope, trace, checkBounds, false), typeReference) + return resolveType(TypeResolutionContext(scope, trace, checkBounds, false, typeReference.suppressDiagnosticsInDebugMode()), typeReference) } private fun resolveType(c: TypeResolutionContext, typeReference: KtTypeReference): KotlinType { @@ -157,7 +158,7 @@ class TypeResolver( var result: PossiblyBareType? = null typeElement?.accept(object : KtVisitorVoid() { override fun visitUserType(type: KtUserType) { - val qualifierResolutionResults = resolveDescriptorForType(c.scope, type, c.trace) + val qualifierResolutionResults = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext) val (qualifierParts, classifierDescriptor) = qualifierResolutionResults if (classifierDescriptor == null) { @@ -564,11 +565,11 @@ class TypeResolver( } fun resolveClass( - scope: LexicalScope, userType: KtUserType, trace: BindingTrace - ): ClassifierDescriptor? = resolveDescriptorForType(scope, userType, trace).classifierDescriptor + scope: LexicalScope, userType: KtUserType, trace: BindingTrace, isDebuggerContext: Boolean + ): ClassifierDescriptor? = resolveDescriptorForType(scope, userType, trace, isDebuggerContext).classifierDescriptor fun resolveDescriptorForType( - scope: LexicalScope, userType: KtUserType, trace: BindingTrace + scope: LexicalScope, userType: KtUserType, trace: BindingTrace, isDebuggerContext: Boolean ): QualifiedExpressionResolver.TypeQualifierResolutionResult { if (userType.qualifier != null) { // we must resolve all type references in arguments of qualifier type for (typeArgument in userType.qualifier!!.typeArguments) { @@ -578,7 +579,7 @@ class TypeResolver( } } - val result = qualifiedExpressionResolver.resolveDescriptorForType(userType, scope, trace) + val result = qualifiedExpressionResolver.resolveDescriptorForType(userType, scope, trace, isDebuggerContext) if (result.classifierDescriptor != null) { PlatformTypesMappedToKotlinChecker.reportPlatformClassMappedToKotlin( moduleDescriptor, trace, userType, result.classifierDescriptor) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index e39a377d7b7..7ef488e7602 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.types.expressions; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; @@ -251,7 +250,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); boolean allowBareTypes = BARE_TYPES_ALLOWED.contains(operationType); - TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, allowBareTypes); + TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, allowBareTypes, context.isDebuggerContext); PossiblyBareType possiblyBareTarget = components.typeResolver.resolvePossiblyBareType(typeResolutionContext, right); KotlinTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); @@ -432,7 +431,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { KtUserType userType = (KtUserType) typeElement; // This may be just a superclass name even if the superclass is generic if (userType.getTypeArguments().isEmpty()) { - classifierCandidate = components.typeResolver.resolveClass(context.scope, userType, context.trace); + classifierCandidate = components.typeResolver.resolveClass(context.scope, userType, context.trace, context.isDebuggerContext); } else { supertype = components.typeResolver.resolveType(context.scope, superTypeQualifier, context.trace, true); @@ -612,7 +611,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } TypeResolutionContext context = - new TypeResolutionContext(c.scope, c.trace, /* checkBounds = */ false, /* allowBareTypes = */ true); + new TypeResolutionContext(c.scope, c.trace, /* checkBounds = */ false, /* allowBareTypes = */ true, /* isDebuggerContext */ false); PossiblyBareType possiblyBareType = components.typeResolver.resolvePossiblyBareType(context, typeReference); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index a90ea1fbec9..c49b8771484 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -346,7 +346,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping typeReferenceAfterIs: KtTypeReference, subjectDataFlowValue: DataFlowValue ): ConditionalDataFlowInfo { - val typeResolutionContext = TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true) + val typeResolutionContext = TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true, context.isDebuggerContext) val possiblyBareTarget = components.typeResolver.resolvePossiblyBareType(typeResolutionContext, typeReferenceAfterIs) val targetType = TypeReconstructionUtil.reconstructBareType(typeReferenceAfterIs, possiblyBareTarget, subjectType, context.trace, components.builtIns) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt index 430b5a599c0..de443b87faa 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes import org.jetbrains.kotlin.idea.project.ResolveElementCache import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.resolve.* @@ -67,7 +68,7 @@ class CodeFragmentAnalyzer( } is KtTypeReference -> { - val context = TypeResolutionContext(scopeForContextElement, trace, true, true).noBareTypes() + val context = TypeResolutionContext(scopeForContextElement, trace, true, true, codeFragment.suppressDiagnosticsInDebugMode()).noBareTypes() typeResolver.resolvePossiblyBareType(context, codeFragmentElement) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt index f54c7ebbe93..dd546ec85eb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/ReplaceWithAnnotationAnalyzer.kt @@ -183,7 +183,7 @@ object ReplaceWithAnnotationAnalyzer { val typeResolver = resolutionFacade.getFrontendService(TypeResolver::class.java) val bindingTrace = BindingTraceContext() - typeResolver.resolvePossiblyBareType(TypeResolutionContext(scope, bindingTrace, false, true), typeReference) + typeResolver.resolvePossiblyBareType(TypeResolutionContext(scope, bindingTrace, false, true, false), typeReference) val typesToQualify = ArrayList>() diff --git a/idea/testData/debugger/tinyApp/outs/privateClass.out b/idea/testData/debugger/tinyApp/outs/privateClass.out new file mode 100644 index 00000000000..94bc0449f36 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/privateClass.out @@ -0,0 +1,11 @@ +LineBreakpoint created at privateClass.kt:5 +!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! privateClass.PrivateClassKt +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +privateClass.kt:5 +Compile bytecode for A.PrivateClass() +Compile bytecode for A.PrivateClass().prop +Compile bytecode for A().PrivateInnerClass() +Compile bytecode for A().PrivateInnerClass().prop +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateClass.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateClass.kt new file mode 100644 index 00000000000..c67e0698e4b --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateClass.kt @@ -0,0 +1,28 @@ +package privateClass + +fun main(args: Array) { + //Breakpoint! + args.size +} + +class A { + private class PrivateClass { + private val prop = 1 + } + + private inner class PrivateInnerClass { + private val prop = 1 + } +} + +// EXPRESSION: A.PrivateClass() +// RESULT: instance of privateClass.A$PrivateClass(id=ID): LprivateClass/A$PrivateClass; + +// EXPRESSION: A.PrivateClass().prop +// RESULT: 1: I + +// EXPRESSION: A().PrivateInnerClass() +// RESULT: instance of privateClass.A$PrivateInnerClass(id=ID): LprivateClass/A$PrivateInnerClass; + +// EXPRESSION: A().PrivateInnerClass().prop +// RESULT: 1: I diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index c1d6a95786a..73e01175b82 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -271,6 +271,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doSingleBreakpointTest(fileName); } + @TestMetadata("privateClass.kt") + public void testPrivateClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateClass.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("privateMember.kt") public void testPrivateMember() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt");