Debugger: Run control flow on code fragments (KT-30120)

This commit is contained in:
Yan Zhulanow
2019-04-26 02:02:39 +03:00
parent 35c63db9bc
commit bfb1d53ddf
7 changed files with 69 additions and 22 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.util.analyzeControlFlow
import org.jetbrains.kotlin.idea.project.ResolveElementCache
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -27,21 +29,16 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes3
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScopes
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
import javax.inject.Inject
class CodeFragmentAnalyzer(
private val resolveSession: ResolveSession,
private val qualifierResolver: QualifiedExpressionResolver,
private val expressionTypingServices: ExpressionTypingServices,
private val typeResolver: TypeResolver
) {
@set:Inject // component dependency cycle
@@ -58,15 +55,8 @@ class CodeFragmentAnalyzer(
when (val contentElement = codeFragment.getContentElement()) {
is KtExpression -> {
PreliminaryDeclarationVisitor.createForExpression(
contentElement, bindingTrace,
expressionTypingServices.languageVersionSettings
)
expressionTypingServices.getTypeInfo(
scope, contentElement, TypeUtils.NO_EXPECTED_TYPE,
dataFlowInfo, InferenceSession.default, bindingTrace, false
)
contentElement.analyzeInContext(scope, trace = bindingTrace, dataFlowInfo = dataFlowInfo)
analyzeControlFlow(resolveSession, contentElement, bindingTrace)
}
is KtTypeReference -> {
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2019 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.idea.caches.resolve.util
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
fun analyzeControlFlow(resolveSession: ResolveSession, resolveElement: KtElement, trace: BindingTrace) {
val controlFlowTrace = DelegatingBindingTrace(
trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true
)
ControlFlowInformationProvider(
resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor
).checkDeclaration()
controlFlowTrace.addOwnDataTo(trace, null, false)
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.frontend.di.createContainerForBodyResolve
import org.jetbrains.kotlin.idea.caches.resolve.CodeFragmentAnalyzer
import org.jetbrains.kotlin.idea.caches.resolve.util.analyzeControlFlow
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
@@ -413,13 +414,7 @@ class ResolveElementCache(
}
if (bodyResolveMode.doControlFlowAnalysis) {
val controlFlowTrace = DelegatingBindingTrace(
trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true
)
ControlFlowInformationProvider(
resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor
).checkDeclaration()
controlFlowTrace.addOwnDataTo(trace, null, false)
analyzeControlFlow(resolveSession, resolveElement, trace)
}
return Pair(trace.bindingContext, statementFilterUsed)
+16
View File
@@ -0,0 +1,16 @@
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.UnusedEqualsInspection
fun main() {
val list = java.util.ArrayList<Int>()
<caret>val x = 0
}
fun <T> Collection<T>.isAny(predicate: (T) -> Boolean): Boolean {
for (item in this) {
if (predicate(item)) {
return true
}
}
return false
}
@@ -0,0 +1 @@
list.isAny { it == 2 }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.debugger.evaluate
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
@@ -33,7 +34,7 @@ import kotlin.test.assertTrue
abstract class AbstractCodeFragmentHighlightingTest : AbstractPsiCheckerTest() {
override fun doTest(filePath: String) {
myFixture.configureByCodeFragment(filePath)
myFixture.checkHighlighting(true, false, false)
checkHighlighting(filePath)
}
fun doTestWithImport(filePath: String) {
@@ -49,6 +50,22 @@ abstract class AbstractCodeFragmentHighlightingTest : AbstractPsiCheckerTest() {
}
}
checkHighlighting(filePath)
}
private fun checkHighlighting(filePath: String) {
val inspectionName = InTextDirectivesUtils.findStringWithPrefixes(File(filePath).readText(), "// INSPECTION_CLASS: ")
if (inspectionName != null) {
val inspection = Class.forName(inspectionName).newInstance() as InspectionProfileEntry
myFixture.enableInspections(inspection)
try {
myFixture.checkHighlighting(true, false, false)
} finally {
myFixture.disableInspections(inspection)
}
return
}
myFixture.checkHighlighting(true, false, false)
}
}
@@ -141,6 +141,11 @@ public class CodeFragmentHighlightingTestGenerated extends AbstractCodeFragmentH
runTest("idea/testData/checker/codeFragments/startingFromReturn.kt");
}
@TestMetadata("unusedEquals.kt")
public void testUnusedEquals() throws Exception {
runTest("idea/testData/checker/codeFragments/unusedEquals.kt");
}
@TestMetadata("withoutBodyFunction.kt")
public void testWithoutBodyFunction() throws Exception {
runTest("idea/testData/checker/codeFragments/withoutBodyFunction.kt");