From e4ae15b3f04e2516fd9ca9b628d85a03293fec4c Mon Sep 17 00:00:00 2001 From: Alexey Merkulov Date: Mon, 31 Jul 2023 20:28:59 +0200 Subject: [PATCH] [FIR] Allow resolve to private members from debugger evaluator KT-60714 --- ...ourceModuleCompilerFacilityTestGenerated.java | 12 ++++++++++++ .../capturing/preferCorrectResolve.capturing.txt | 3 +++ .../capturing/preferCorrectResolve.fragment.kt | 2 ++ .../capturing/preferCorrectResolve.ir.txt | 14 ++++++++++++++ .../capturing/preferCorrectResolve.kt | 8 ++++++++ .../capturing/preferCorrectResolve.txt | 5 +++++ .../capturing/privateMemberCall.capturing.txt | 3 +++ .../capturing/privateMemberCall.fragment.kt | 1 + .../capturing/privateMemberCall.ir.txt | 13 +++++++++++++ .../codeFragments/capturing/privateMemberCall.kt | 7 +++++++ .../capturing/privateMemberCall.txt | 5 +++++ .../fir/CodeFragmentCapturingTestGenerated.java | 12 ++++++++++++ .../org/jetbrains/kotlin/fir/FirCallResolver.kt | 16 +++++++++++++++- .../kotlin/fir/resolve/calls/Candidate.kt | 13 ++++++++++--- .../kotlin/fir/resolve/calls/VisibilityUtils.kt | 5 +++++ .../kotlin/util/CodeFragmentAdjustment.kt | 9 +++++++++ 16 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.capturing.txt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.fragment.kt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.ir.txt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.txt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.capturing.txt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.fragment.kt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.ir.txt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt create mode 100644 analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.txt create mode 100644 compiler/frontend.common/src/org/jetbrains/kotlin/util/CodeFragmentAdjustment.kt diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java index cfbba221e6e..d2df7310b22 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java @@ -250,6 +250,18 @@ public class FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated exten runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/outerClassMutatedPrivate.kt"); } + @Test + @TestMetadata("preferCorrectResolve.kt") + public void testPreferCorrectResolve() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt"); + } + + @Test + @TestMetadata("privateMemberCall.kt") + public void testPrivateMemberCall() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt"); + } + @Test @TestMetadata("valueParameter.kt") public void testValueParameter() throws Exception { diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.capturing.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.capturing.txt new file mode 100644 index 00000000000..bd01dd95625 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.capturing.txt @@ -0,0 +1,3 @@ +Local[name: a; isMutated: false; displayText: a] + a: R|A| + R|A| diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.fragment.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.fragment.kt new file mode 100644 index 00000000000..c2a351fdf2d --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.fragment.kt @@ -0,0 +1,2 @@ +// Need to choose public foo(Any) call instead of more specific but private call foo(Int) +a.foo(5) \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.ir.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.ir.txt new file mode 100644 index 00000000000..f6a4ee95c48 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.ir.txt @@ -0,0 +1,14 @@ +MODULE_FRAGMENT name: + FILE fqName: fileName:/fragment.kt + CLASS CLASS name:CodeFragment modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.CodeFragment + CONSTRUCTOR visibility:public <> () returnType:.CodeFragment [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + FUN name:run visibility:public modality:FINAL <> (p0:.A) returnType:kotlin.Int + VALUE_PARAMETER name:p0 index:0 type:.A + EXPRESSION_BODY + BLOCK type=kotlin.Int origin=null + CALL 'public final fun foo (x: kotlin.Any): kotlin.Int declared in .A' type=kotlin.Int origin=null + $this: GET_VAR 'p0: .A declared in .CodeFragment.run' type=.A origin=null + x: CONST Int type=kotlin.Int value=5 diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt new file mode 100644 index 00000000000..cc9f27baf29 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt @@ -0,0 +1,8 @@ +class A { + private fun foo(x: Int) = 1 + x + fun foo(x: Any) = 2 +} + +fun test(a: A) { + val x = 0 +} diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.txt new file mode 100644 index 00000000000..83b3eb654d1 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.txt @@ -0,0 +1,5 @@ +public final class CodeFragment { + // source: 'fragment.kt' + public method (): void + public final static method run(p0: A): int +} diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.capturing.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.capturing.txt new file mode 100644 index 00000000000..bd01dd95625 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.capturing.txt @@ -0,0 +1,3 @@ +Local[name: a; isMutated: false; displayText: a] + a: R|A| + R|A| diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.fragment.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.fragment.kt new file mode 100644 index 00000000000..8831d5ec208 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.fragment.kt @@ -0,0 +1 @@ +a.foo() \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.ir.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.ir.txt new file mode 100644 index 00000000000..bba79677f0d --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.ir.txt @@ -0,0 +1,13 @@ +MODULE_FRAGMENT name: + FILE fqName: fileName:/fragment.kt + CLASS CLASS name:CodeFragment modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.CodeFragment + CONSTRUCTOR visibility:public <> () returnType:.CodeFragment [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + FUN name:run visibility:public modality:FINAL <> (p0:.A) returnType:kotlin.Int + VALUE_PARAMETER name:p0 index:0 type:.A + EXPRESSION_BODY + BLOCK type=kotlin.Int origin=null + CALL 'private final fun foo (): kotlin.Int declared in .A' type=kotlin.Int origin=null + $this: GET_VAR 'p0: .A declared in .CodeFragment.run' type=.A origin=null diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt new file mode 100644 index 00000000000..d1afb5af890 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt @@ -0,0 +1,7 @@ +class A { + private fun foo() = 2 +} + +fun test(a: A) { + val x = 0 +} diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.txt new file mode 100644 index 00000000000..83b3eb654d1 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.txt @@ -0,0 +1,5 @@ +public final class CodeFragment { + // source: 'fragment.kt' + public method (): void + public final static method run(p0: A): int +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/CodeFragmentCapturingTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/CodeFragmentCapturingTestGenerated.java index c406d9d5325..7120e147ae5 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/CodeFragmentCapturingTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/CodeFragmentCapturingTestGenerated.java @@ -150,6 +150,18 @@ public class CodeFragmentCapturingTestGenerated extends AbstractCodeFragmentCapt runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/outerClassMutatedPrivate.kt"); } + @Test + @TestMetadata("preferCorrectResolve.kt") + public void testPreferCorrectResolve() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/preferCorrectResolve.kt"); + } + + @Test + @TestMetadata("privateMemberCall.kt") + public void testPrivateMemberCall() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing/privateMemberCall.kt"); + } + @Test @TestMetadata("valueParameter.kt") public void testValueParameter() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index e5678cf26c7..ee0d418a010 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -55,6 +55,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.util.CodeFragmentAdjustment class FirCallResolver( private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, @@ -765,7 +766,13 @@ class FirCallResolver( !applicability.isSuccess -> { val candidate = candidates.single() - createConeDiagnosticForCandidateWithError(applicability, candidate) + if (needTreatErrorCandidateAsResolved(candidate)) { + @OptIn(CodeFragmentAdjustment::class) + candidate.resetToResolved() + null + } else { + createConeDiagnosticForCandidateWithError(applicability, candidate) + } } else -> null @@ -820,6 +827,13 @@ class FirCallResolver( return FirNamedReferenceWithCandidate(source, name, candidate) } + private fun needTreatErrorCandidateAsResolved(candidate: Candidate): Boolean { + return if (candidate.isCodeFragmentVisibilityError) { + components.resolutionStageRunner.fullyProcessCandidate(candidate, transformer.resolutionContext) + candidate.diagnostics.all { it.applicability.isSuccess || it.applicability == CandidateApplicability.K2_VISIBILITY_ERROR } + } else false + } + private fun createErrorReferenceForSingleCandidate( candidate: Candidate?, diagnostic: ConeDiagnostic, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index 011ad3ed6b2..6b613644b7d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -7,9 +7,10 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.fakeElement -import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirValueParameter -import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression +import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.builder.buildThisReceiverExpressionCopy import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression @@ -20,7 +21,6 @@ import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeVariable -import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImp import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess +import org.jetbrains.kotlin.util.CodeFragmentAdjustment class Candidate( override val symbol: FirBasedSymbol<*>, @@ -103,6 +104,12 @@ class Candidate( } } + @CodeFragmentAdjustment + internal fun resetToResolved() { + currentApplicability = CandidateApplicability.RESOLVED + _diagnostics.clear() + } + val isSuccessful: Boolean get() = currentApplicability.isSuccess && (!systemInitialized || !system.hasContradiction) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/VisibilityUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/VisibilityUtils.kt index bd506bc277e..bee8498c0fe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/VisibilityUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/VisibilityUtils.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isNullableNothing import org.jetbrains.kotlin.fir.types.makeConeTypeDefinitelyNotNullOrNotNull import org.jetbrains.kotlin.fir.types.typeContext +import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.utils.addToStdlib.runIf fun FirVisibilityChecker.isVisible( @@ -136,3 +137,7 @@ private fun isExplicitReceiverExpression(receiverExpression: FirExpression?): Bo val thisReference = receiverExpression.toReference() as? FirThisReference ?: return true return !thisReference.isImplicit } + +internal val Candidate.isCodeFragmentVisibilityError + get() = applicability == CandidateApplicability.K2_VISIBILITY_ERROR && + callInfo.containingFile.declarations.singleOrNull() is FirCodeFragment diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/util/CodeFragmentAdjustment.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/util/CodeFragmentAdjustment.kt new file mode 100644 index 00000000000..b9097e10c74 --- /dev/null +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/util/CodeFragmentAdjustment.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.util + +@RequiresOptIn(message = "Should be used only for code fragment resolve/generation adjustments") +annotation class CodeFragmentAdjustment \ No newline at end of file