FIR IDE: Begin implementing semantic highlighting via FIR

* Introduce frontend api module & implement api for FIR
* Implement some basic declaration highlighting for FIR
This commit is contained in:
Ilya Kirillov
2020-05-18 11:37:09 +03:00
parent 507fc34c22
commit f37e313705
23 changed files with 1055 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -923,9 +923,13 @@ fun main(args: Array<String>) {
model("fir/multiModule", recursive = false, extension = null)
}
testClass<AbstractFirLazyResolveTest> {
model("fir/lazyResolve", extension = "test", singleClass = true, filenameStartsLowerCase = true)
}
testClass<AbstractFirHighlightingTest> {
model("highlighter")
}
testClass<AbstractFirLazyResolveTest> {
model("fir/lazyResolve", extension = "test", singleClass = true, filenameStartsLowerCase = true)
}
testClass<AbstractFirReferenceResolveTest> {
model("resolve/references", pattern = KT_WITHOUT_DOTS_IN_NAME)

View File

@@ -25,6 +25,7 @@ dependencies {
testRuntime(intellijPluginDep("java"))
}
testCompile(projectTests(":idea:idea-test-framework"))
testRuntime(intellijRuntimeAnnotations())
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
@@ -48,7 +49,6 @@ dependencies {
testRuntime(project(":idea:idea-android")) { isTransitive = false }
testRuntime(project(":plugins:lint")) { isTransitive = false }
testRuntime(project(":plugins:uast-kotlin"))
testRuntime(project(":nj2k:nj2k-services")) { isTransitive = false }
}
sourceSets {

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2010-2020 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.highlighter
import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources
import org.jetbrains.kotlin.test.InTextDirectivesUtils
abstract class AbstractFirHighlightingTest : AbstractHighlightingTest() {
override fun getDefaultProjectDescriptor() = ProjectDescriptorWithStdlibSources.INSTANCE
override fun checkHighlighting(fileText: String) {
val checkInfos = !InTextDirectivesUtils.isDirectiveDefined(fileText, NO_CHECK_INFOS_PREFIX);
// warnings are not supported yet
myFixture.checkHighlighting(/* checkWarnings= */ false, checkInfos, /* checkWeakWarnings= */ false)
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright 2010-2020 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.highlighter;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/testData/highlighter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FirHighlightingTestGenerated extends AbstractFirHighlightingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInHighlighter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/highlighter"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("Annotations.kt")
public void testAnnotations() throws Exception {
runTest("idea/testData/highlighter/Annotations.kt");
}
@TestMetadata("AutoCreatedItParameter.kt")
public void testAutoCreatedItParameter() throws Exception {
runTest("idea/testData/highlighter/AutoCreatedItParameter.kt");
}
@TestMetadata("Destructuring.kt")
public void testDestructuring() throws Exception {
runTest("idea/testData/highlighter/Destructuring.kt");
}
@TestMetadata("Dynamic.kt")
public void testDynamic() throws Exception {
runTest("idea/testData/highlighter/Dynamic.kt");
}
@TestMetadata("Enums.kt")
public void testEnums() throws Exception {
runTest("idea/testData/highlighter/Enums.kt");
}
@TestMetadata("Field.kt")
public void testField() throws Exception {
runTest("idea/testData/highlighter/Field.kt");
}
@TestMetadata("Functions.kt")
public void testFunctions() throws Exception {
runTest("idea/testData/highlighter/Functions.kt");
}
@TestMetadata("InvokeCall.kt")
public void testInvokeCall() throws Exception {
runTest("idea/testData/highlighter/InvokeCall.kt");
}
@TestMetadata("JavaTypes.kt")
public void testJavaTypes() throws Exception {
runTest("idea/testData/highlighter/JavaTypes.kt");
}
@TestMetadata("KDoc.kt")
public void testKDoc() throws Exception {
runTest("idea/testData/highlighter/KDoc.kt");
}
@TestMetadata("KotlinInjection.kt")
public void testKotlinInjection() throws Exception {
runTest("idea/testData/highlighter/KotlinInjection.kt");
}
@TestMetadata("Labels.kt")
public void testLabels() throws Exception {
runTest("idea/testData/highlighter/Labels.kt");
}
@TestMetadata("NamedArguments.kt")
public void testNamedArguments() throws Exception {
runTest("idea/testData/highlighter/NamedArguments.kt");
}
@TestMetadata("NonNullAssertion.kt")
public void testNonNullAssertion() throws Exception {
runTest("idea/testData/highlighter/NonNullAssertion.kt");
}
@TestMetadata("Object.kt")
public void testObject() throws Exception {
runTest("idea/testData/highlighter/Object.kt");
}
@TestMetadata("PropertiesWithPropertyDeclarations.kt")
public void testPropertiesWithPropertyDeclarations() throws Exception {
runTest("idea/testData/highlighter/PropertiesWithPropertyDeclarations.kt");
}
@TestMetadata("SmartCast.kt")
public void testSmartCast() throws Exception {
runTest("idea/testData/highlighter/SmartCast.kt");
}
@TestMetadata("Suspend.kt")
public void testSuspend() throws Exception {
runTest("idea/testData/highlighter/Suspend.kt");
}
@TestMetadata("SyntheticExtensionProperty.kt")
public void testSyntheticExtensionProperty() throws Exception {
runTest("idea/testData/highlighter/SyntheticExtensionProperty.kt");
}
@TestMetadata("Todo.kt")
public void testTodo() throws Exception {
runTest("idea/testData/highlighter/Todo.kt");
}
@TestMetadata("TopLevelDestructuring.kt")
public void testTopLevelDestructuring() throws Exception {
runTest("idea/testData/highlighter/TopLevelDestructuring.kt");
}
@TestMetadata("TopLevelOpenSuspendFun.kt")
public void testTopLevelOpenSuspendFun() throws Exception {
runTest("idea/testData/highlighter/TopLevelOpenSuspendFun.kt");
}
@TestMetadata("TypeAlias.kt")
public void testTypeAlias() throws Exception {
runTest("idea/testData/highlighter/TypeAlias.kt");
}
@TestMetadata("TypesAndAnnotations.kt")
public void testTypesAndAnnotations() throws Exception {
runTest("idea/testData/highlighter/TypesAndAnnotations.kt");
}
@TestMetadata("Variables.kt")
public void testVariables() throws Exception {
runTest("idea/testData/highlighter/Variables.kt");
}
@TestMetadata("VariablesAsFunctions.kt")
public void testVariablesAsFunctions() throws Exception {
runTest("idea/testData/highlighter/VariablesAsFunctions.kt");
}
@TestMetadata("idea/testData/highlighter/deprecated")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Deprecated extends AbstractFirHighlightingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInDeprecated() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/highlighter/deprecated"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("Class.kt")
public void testClass() throws Exception {
runTest("idea/testData/highlighter/deprecated/Class.kt");
}
@TestMetadata("ClassObject.kt")
public void testClassObject() throws Exception {
runTest("idea/testData/highlighter/deprecated/ClassObject.kt");
}
@TestMetadata("Constructor.kt")
public void testConstructor() throws Exception {
runTest("idea/testData/highlighter/deprecated/Constructor.kt");
}
@TestMetadata("ExtensionFunction.kt")
public void testExtensionFunction() throws Exception {
runTest("idea/testData/highlighter/deprecated/ExtensionFunction.kt");
}
@TestMetadata("Function.kt")
public void testFunction() throws Exception {
runTest("idea/testData/highlighter/deprecated/Function.kt");
}
@TestMetadata("Get.kt")
public void testGet() throws Exception {
runTest("idea/testData/highlighter/deprecated/Get.kt");
}
@TestMetadata("Getter.kt")
public void testGetter() throws Exception {
runTest("idea/testData/highlighter/deprecated/Getter.kt");
}
@TestMetadata("Inc.kt")
public void testInc() throws Exception {
runTest("idea/testData/highlighter/deprecated/Inc.kt");
}
@TestMetadata("Invalid.kt")
public void testInvalid() throws Exception {
runTest("idea/testData/highlighter/deprecated/Invalid.kt");
}
@TestMetadata("Invoke.kt")
public void testInvoke() throws Exception {
runTest("idea/testData/highlighter/deprecated/Invoke.kt");
}
@TestMetadata("Operation.kt")
public void testOperation() throws Exception {
runTest("idea/testData/highlighter/deprecated/Operation.kt");
}
@TestMetadata("Property.kt")
public void testProperty() throws Exception {
runTest("idea/testData/highlighter/deprecated/Property.kt");
}
@TestMetadata("RangeTo.kt")
public void testRangeTo() throws Exception {
runTest("idea/testData/highlighter/deprecated/RangeTo.kt");
}
@TestMetadata("Setter.kt")
public void testSetter() throws Exception {
runTest("idea/testData/highlighter/deprecated/Setter.kt");
}
@TestMetadata("SuperCall.kt")
public void testSuperCall() throws Exception {
runTest("idea/testData/highlighter/deprecated/SuperCall.kt");
}
@TestMetadata("Trait.kt")
public void testTrait() throws Exception {
runTest("idea/testData/highlighter/deprecated/Trait.kt");
}
}
}

View File

@@ -0,0 +1,34 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":compiler:psi"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":core:type-system"))
compileOnly(project(":idea:idea-frontend-independent"))
compileOnly(project(":compiler:psi"))
compileOnly(intellijCoreDep())
compileOnly(intellijDep())
Platform[191].orLower {
compileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
}
Platform[192].orHigher {
compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
}
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
testsJar()
projectTest {
dependsOn(":dist")
workingDir = rootDir
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2010-2020 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.frontend.api
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedFunction
sealed class CallInfo {
abstract val isSuspendCall: Boolean
abstract val targetFunction: PsiElement?
}
data class VariableAsFunctionCallInfo(val target: PsiElement, override val isSuspendCall: Boolean) : CallInfo() {
override val targetFunction: PsiElement? = null
}
data class VariableAsFunctionLikeCallInfo(val target: PsiElement, val invokeFunction: KtNamedFunction) : CallInfo() {
override val isSuspendCall: Boolean get() = invokeFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val targetFunction: PsiElement? get() = invokeFunction
}
// SimpleFunctionCallInfo
sealed class SimpleFunctionCallInfo : CallInfo() {
abstract override val targetFunction: PsiElement
}
data class SimpleKtFunctionCallInfo(override val targetFunction: KtNamedFunction) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean get() = targetFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
}
data class SimpleJavaFunctionCallInfo(override val targetFunction: PsiMethod) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean = false
}
// ConstructorCallInfo
//TODO
object ConstructorCallInfo : CallInfo() {
// abstract val targetConstructor: PsiElement?
final override val isSuspendCall: Boolean = false
override val targetFunction: PsiElement? = null
}
//data class SimpleKtConstructorCallInfo(override val targetConstructor: KtConstructor<*>) : ConstructorCallInfo()
//data class SimpleJavaConstructorCallInfo(override val targetConstructor: PsiMethod) : ConstructorCallInfo()

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2010-2020 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.frontend.api
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
abstract class FrontendAnalysisSession {
abstract fun getSmartCastedToTypes(expression: KtExpression): Collection<KotlinTypeMarker>?
abstract fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast>
abstract fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KotlinTypeMarker?
abstract fun renderType(type: KotlinTypeMarker): String
abstract fun getKtExpressionType(expression: KtExpression): KotlinTypeMarker?
abstract fun isSubclassOf(klass: KtClassOrObject, superClassId: ClassId): Boolean
abstract fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic>
abstract fun resolveCall(call: KtCallExpression): CallInfo?
abstract fun resolveCall(call: KtBinaryExpression): CallInfo?
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright 2010-2020 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.frontend.api
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
data class ImplicitReceiverSmartCast(val types: Collection<KotlinTypeMarker>, val kind: ImplicitReceiverSmartcastKind)
enum class ImplicitReceiverSmartcastKind {
DISPATCH, EXTENSION
}

View File

@@ -6,6 +6,7 @@ plugins {
dependencies {
compileOnly(project(":compiler:psi"))
compileOnly(project(":idea:idea-frontend-independent"))
implementation(project(":idea:idea-frontend-api"))
compileOnly(project(":idea:idea-core"))
compileOnly(project(":compiler:fir:fir2ir"))
compileOnly(project(":compiler:fir:resolve"))

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2010-2020 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.fir
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
fun FirFunctionCall.isImplicitFunctionCall(): Boolean {
if (dispatchReceiver !is FirQualifiedAccessExpression) return false
val resolvedCalleeSymbol = (calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return (resolvedCalleeSymbol as? FirNamedFunctionSymbol)?.fir?.name?.asString() == "invoke"
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright 2010-2020 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.frontend.api.fir
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper.toTargetPsi
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
class AnalysisSessionFirImpl internal constructor(
private val state: FirModuleResolveState
) : FrontendAnalysisSession() {
override fun getSmartCastedToTypes(expression: KtExpression): Collection<KotlinTypeMarker>? {
// TODO filter out not used smartcasts
return (expression.toFir() as? FirExpressionWithSmartcast)?.typesFromSmartCast
}
@OptIn(ExperimentalStdlibApi::class)
override fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast> {
// TODO filter out not used smartcasts
val qualifiedExpression = expression.getOrBuildFir(state) as? FirQualifiedAccessExpression ?: return emptyList()
if (qualifiedExpression.dispatchReceiver !is FirExpressionWithSmartcast
&& qualifiedExpression.extensionReceiver !is FirExpressionWithSmartcast
) return emptyList()
return buildList {
(qualifiedExpression.dispatchReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast(smartCasted.typesFromSmartCast, ImplicitReceiverSmartcastKind.DISPATCH)
}?.let(::add)
(qualifiedExpression.extensionReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast(smartCasted.typesFromSmartCast, ImplicitReceiverSmartcastKind.EXTENSION)
}?.let(::add)
}
}
override fun renderType(type: KotlinTypeMarker): String =
type.asConeType().render()
override fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KotlinTypeMarker? =
declaration.toFir<FirCallableDeclaration<*>>()?.returnTypeRef?.coneTypeSafe()
override fun getKtExpressionType(expression: KtExpression): ConeKotlinType? =
expression.toFir<FirExpression>()?.typeRef?.coneTypeSafe()
override fun isSubclassOf(klass: KtClassOrObject, superClassId: ClassId): Boolean {
var result = false
forEachSubClass(klass.toFir() ?: return false) { type ->
result = result || type.firClassLike(state.getSession(klass))?.symbol?.classId == superClassId
}
return result
}
override fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic> {
element.containingKtFile.getOrBuildFirWithDiagnostics(state)
return state.getDiagnostics(element)
}
override fun resolveCall(call: KtBinaryExpression): CallInfo? {
val firCall = call.toFir<FirFunctionCall>() ?: return null
return resolveCall(firCall, call)
}
override fun resolveCall(call: KtCallExpression): CallInfo? {
val firCall = call.toFir<FirFunctionCall>() ?: return null
return resolveCall(firCall, call)
}
private fun resolveCall(firCall: FirFunctionCall, callExpression: KtExpression): CallInfo? {
val session = callExpression.getSession()
val resolvedFunctionPsi = firCall.calleeReference.toTargetPsi(session)
val resolvedCalleeSymbol = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return when {
resolvedCalleeSymbol is FirConstructorSymbol -> {
ConstructorCallInfo//todo use proper constructor info
}
firCall.dispatchReceiver is FirQualifiedAccessExpression && firCall.isImplicitFunctionCall() -> {
val target = with(FirReferenceResolveHelper) {
val calleeReference = (firCall.dispatchReceiver as FirQualifiedAccessExpression).calleeReference
calleeReference.toTargetPsi(session)
}
when (target) {
null -> null
is KtValVarKeywordOwner, is PsiField -> {
val functionSymbol =
(firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol
when (functionSymbol?.callableId) {
null -> null
in kotlinFunctionInvokeCallableIds -> VariableAsFunctionCallInfo(target, functionSymbol.fir.isSuspend)
else -> (resolvedFunctionPsi as? KtNamedFunction)?.let { VariableAsFunctionLikeCallInfo(target, it) }
}
}
else -> resolvedFunctionPsi?.asSimpleFunctionCall()
}
}
else -> resolvedFunctionPsi?.asSimpleFunctionCall()
}
}
private fun PsiElement.asSimpleFunctionCall() = when (this) {
is KtNamedFunction -> SimpleKtFunctionCallInfo(this)
is PsiMethod -> SimpleJavaFunctionCallInfo(this)
else -> null
}
private fun KtElement.getSession() = state.getSession(this)
private inline fun <reified F : FirElement> KtElement.toFir(phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE): F? =
getOrBuildFir(state, phase) as? F
private fun forEachSubClass(firClass: FirClass<*>, action: (FirResolvedTypeRef) -> Unit) {
firClass.superTypeRefs.forEach { superType ->
(superType as? FirResolvedTypeRef)?.let(action)
(superType.firClassLike(firClass.session) as? FirClass<*>?)?.let { forEachSubClass(it, action) }
}
}
companion object {
fun forElement(element: KtElement): FrontendAnalysisSession =
AnalysisSessionFirImpl(element.firResolveState())
private fun KotlinTypeMarker.asConeType(): ConeKotlinType =
this as? ConeKotlinType ?: error("$this should be ConeKotlinType")
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
listOf(
CallableId(KotlinBuiltIns.getFunctionClassId(arity), Name.identifier("invoke")),
CallableId(KotlinBuiltIns.getSuspendFunctionClassId(arity), Name.identifier("invoke"))
)
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2010-2020 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.highlighter
import com.intellij.lang.jvm.JvmModifier
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.psi.*
import com.intellij.psi.impl.source.PsiFieldImpl
import com.intellij.psi.util.elementType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal fun textAttributesKeyForPropertyDeclaration(declaration: PsiElement): TextAttributesKey? = when {
declaration is KtProperty && declaration.isExtensionDeclaration() -> Colors.EXTENSION_PROPERTY
declaration is KtProperty && declaration.isLocal || declaration is PsiLocalVariable ->
Colors.LOCAL_VARIABLE
declaration is KtParameter -> {
if (declaration.valOrVarKeyword != null) Colors.INSTANCE_PROPERTY
else Colors.PARAMETER
}
declaration is PsiParameter -> Colors.PARAMETER
declaration is KtProperty && declaration.isTopLevel -> {
if (declaration.isCustomPropertyDeclaration()) Colors.PACKAGE_PROPERTY_CUSTOM_PROPERTY_DECLARATION
else Colors.PACKAGE_PROPERTY
}
declaration is KtProperty -> {
if (declaration.isCustomPropertyDeclaration()) Colors.INSTANCE_PROPERTY_CUSTOM_PROPERTY_DECLARATION
else Colors.INSTANCE_PROPERTY
}
declaration is PsiField -> Colors.INSTANCE_PROPERTY
else -> null
}
private fun KtProperty.isCustomPropertyDeclaration() =
getter?.bodyExpression != null || setter?.bodyExpression != null
@Suppress("UnstableApiUsage")
internal fun textAttributesKeyForTypeDeclaration(declaration: PsiElement): TextAttributesKey? = when {
declaration is KtTypeParameter || declaration is PsiTypeParameter -> Colors.TYPE_PARAMETER
declaration is KtTypeAlias -> Colors.TYPE_ALIAS
declaration is KtClass && declaration.isInterface()
|| declaration is PsiClass && declaration.isInterface && !declaration.isAnnotationType -> Colors.TRAIT
declaration.isAnnotationClass() -> Colors.ANNOTATION
declaration is KtObjectDeclaration -> Colors.OBJECT
declaration is KtEnumEntry || declaration is PsiEnumConstant -> Colors.ENUM_ENTRY
declaration is KtClass && declaration.isAbstract()
|| declaration is PsiClass && declaration.hasModifier(JvmModifier.ABSTRACT) -> Colors.ABSTRACT_CLASS
declaration is KtClass || declaration is PsiClass -> Colors.CLASS
else -> null
}
internal fun PsiElement.isAnnotationClass() =
this is KtClass && isAnnotation() || this is PsiClass && isAnnotationType

View File

@@ -8,8 +8,9 @@ package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.fir.firResolveState
import org.jetbrains.kotlin.idea.fir.getOrBuildFirWithDiagnostics
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.idea.highlighter.visitors.FirAfterResolveHighlightingVisitor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -20,12 +21,21 @@ class KotlinFirPsiChecker : AbstractKotlinPsiChecker() {
override fun annotateElement(element: PsiElement, containingFile: KtFile, holder: AnnotationHolder) {
if (element !is KtElement) return
val state = containingFile.firResolveState()
containingFile.getOrBuildFirWithDiagnostics(state)
val analysisSession = AnalysisSessionFirImpl.forElement(element)
val diagnostics = state.getDiagnostics(element)
highlightDiagnostics(element, analysisSession, holder)
FirAfterResolveHighlightingVisitor
.createListOfVisitors(analysisSession, holder)
.forEach(element::accept)
}
private fun highlightDiagnostics(element: KtElement, analysisSession: FrontendAnalysisSession, holder: AnnotationHolder) {
val diagnostics = analysisSession.getDiagnosticsForElement(element)
if (diagnostics.isEmpty()) return
if (diagnostics.none(Diagnostic::isValid)) return
if (shouldHighlightErrors(element)) {
highlightDiagnostics(diagnostics, holder)
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.util.elementType
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForPropertyDeclaration
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForTypeDeclaration
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class DeclarationHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitNamedFunction(function: KtNamedFunction) {
highlightNamedDeclaration(function, Colors.FUNCTION_DECLARATION)
super.visitNamedFunction(function)
}
override fun visitTypeAlias(typeAlias: KtTypeAlias) {
highlightNamedDeclaration(typeAlias, Colors.TYPE_ALIAS)
super.visitTypeAlias(typeAlias)
}
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
textAttributesKeyForTypeDeclaration(classOrObject)?.let { attributes -> highlightNamedDeclaration(classOrObject, attributes) }
super.visitClassOrObject(classOrObject)
}
override fun visitTypeParameter(parameter: KtTypeParameter) {
highlightNamedDeclaration(parameter, Colors.TYPE_PARAMETER)
super.visitTypeParameter(parameter)
}
override fun visitNamedDeclaration(declaration: KtNamedDeclaration) {
if (declaration is KtValVarKeywordOwner) {
textAttributesKeyForPropertyDeclaration(declaration)?.let { attributes ->
highlightNamedDeclaration(declaration, attributes)
}
if (declaration.valOrVarKeyword?.elementType == KtTokens.VAR_KEYWORD) {
highlightNamedDeclaration(declaration, Colors.MUTABLE_VARIABLE)
}
}
super.visitNamedDeclaration(declaration)
}
override fun visitSuperTypeCallEntry(call: KtSuperTypeCallEntry) {
val calleeExpression = call.calleeExpression
val typeElement = calleeExpression.typeReference?.typeElement
if (typeElement is KtUserType) {
typeElement.referenceExpression?.let { highlightName(it, Colors.CONSTRUCTOR_CALL) }
}
super.visitSuperTypeCallEntry(call)
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind
import org.jetbrains.kotlin.psi.*
internal class ExpressionsSmartcastHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitExpression(expression: KtExpression) {
analysisSession.getImplicitReceiverSmartCasts(expression).forEach { (types, kind) ->
val receiverName = when (kind) {
ImplicitReceiverSmartcastKind.EXTENSION -> KotlinIdeaAnalysisBundle.message("extension.implicit.receiver")
ImplicitReceiverSmartcastKind.DISPATCH -> KotlinIdeaAnalysisBundle.message("implicit.receiver")
}
types.forEach { type ->
createInfoAnnotation(
expression,
KotlinIdeaAnalysisBundle.message(
"0.smart.cast.to.1",
receiverName,
analysisSession.renderType(type)
)
).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_RECEIVER
}
}
analysisSession.getSmartCastedToTypes(expression)?.forEach { type ->
createInfoAnnotation(
getSmartCastTarget(expression),
KotlinIdeaAnalysisBundle.message(
"smart.cast.to.0",
analysisSession.renderType(type)
)
).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_VALUE
}
//todo smartcast to null
super.visitExpression(expression)
}
}
private fun getSmartCastTarget(expression: KtExpression): PsiElement {
var target: PsiElement = expression
if (target is KtParenthesizedExpression) {
target = KtPsiUtil.deparenthesize(target) ?: expression
}
return when (target) {
is KtIfExpression -> target.ifKeyword
is KtWhenExpression -> target.whenKeyword
is KtBinaryExpression -> target.operationReference
else -> target
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.HighlightingVisitor
abstract class FirAfterResolveHighlightingVisitor(
protected val analysisSession: FrontendAnalysisSession,
protected val holder: AnnotationHolder
) : HighlightingVisitor(holder) {
protected fun highlightNamedDeclaration(declaration: KtNamedDeclaration, key: TextAttributesKey) {
declaration.nameIdentifier?.let { highlightName(it, key) }
}
companion object {
fun createListOfVisitors(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
): List<FirAfterResolveHighlightingVisitor> = listOf(
TypeHighlightingVisitor(analysisSession, holder),
DeclarationHighlightingVisitor(analysisSession, holder),
FunctionCallHighlightingVisitor(analysisSession, holder),
ExpressionsSmartcastHighlightingVisitor(analysisSession, holder),
VariableReferenceHighlightingVisitor(analysisSession, holder),
)
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.editor.colors.TextAttributesKey
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.serialization.deserialization.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class FunctionCallHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitBinaryExpression(expression: KtBinaryExpression) {
(expression.operationReference as? KtReferenceExpression)
?.takeIf {
// do not highlight assignment statement
(it as? KtOperationReferenceExpression)?.operationSignTokenType != KtTokens.EQ
}?.let { callee ->
analysisSession.resolveCall(expression)
?.takeIf { callInfo ->
// ignore arithmetic-like operator calls
(callInfo.targetFunction as? KtNamedFunction)?.hasModifier(KtTokens.OPERATOR_KEYWORD) != true
}
?.let { callInfo ->
getTextAttributesForCal(callInfo)?.let { attributes ->
highlightName(callee, attributes)
}
}
}
super.visitBinaryExpression(expression)
}
override fun visitCallExpression(expression: KtCallExpression) {
expression.calleeExpression
?.takeUnless { it is KtLambdaExpression }
?.takeUnless { it is KtCallExpression /* KT-16159 */}
?.let { callee ->
analysisSession.resolveCall(expression)?.let { callInfo ->
getTextAttributesForCal(callInfo)?.let { attributes ->
highlightName(callee, attributes)
}
}
}
super.visitCallExpression(expression)
}
private fun getTextAttributesForCal(callInfo: CallInfo): TextAttributesKey? = when {
callInfo.isSuspendCall -> Colors.SUSPEND_FUNCTION_CALL
callInfo is ConstructorCallInfo ->
Colors.CONSTRUCTOR_CALL
callInfo is SimpleKtFunctionCallInfo -> when {
callInfo.targetFunction.getKotlinFqName() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME ->Colors.KEYWORD
callInfo.targetFunction.isExtensionDeclaration() -> Colors.EXTENSION_FUNCTION_CALL
callInfo.targetFunction.parent is KtFile -> Colors.PACKAGE_FUNCTION_CALL
else -> Colors.FUNCTION_CALL
}
callInfo is SimpleJavaFunctionCallInfo -> Colors.FUNCTION_CALL
callInfo is VariableAsFunctionCallInfo -> Colors.VARIABLE_AS_FUNCTION_CALL
callInfo is VariableAsFunctionLikeCallInfo -> Colors.VARIABLE_AS_FUNCTION_LIKE_CALL
else -> null
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter
import org.jetbrains.kotlin.idea.highlighter.isAnnotationClass
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForTypeDeclaration
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class TypeHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
if (!NameHighlighter.namesHighlightingEnabled) return
if (expression.isCalleeExpression()) return
val parent = expression.parent
if (parent is KtInstanceExpressionWithLabel) {
// Do nothing: 'super' and 'this' are highlighted as a keyword
return
}
val target = expression.mainReference.resolve() ?: return
textAttributesKeyForTypeDeclaration(target)?.let { key ->
if (expression.isConstructorCallReference() && key != Colors.ANNOTATION) {
// Do not highlight constructor call as class reference
return@let
}
highlightName(computeHighlightingRangeForUsage(expression, target), key)
}
}
private fun computeHighlightingRangeForUsage(expression: KtSimpleNameExpression, target: PsiElement): TextRange {
val expressionRange = expression.textRange
if (!target.isAnnotationClass()) return expressionRange
// include '@' symbol if the reference is the first segment of KtAnnotationEntry
// if "Deprecated" is highlighted then '@' should be highlighted too in "@Deprecated"
val annotationEntry = PsiTreeUtil.getParentOfType(
expression, KtAnnotationEntry::class.java, /* strict = */false, KtValueArgumentList::class.java
)
val atSymbol = annotationEntry?.atSymbol ?: return expressionRange
return TextRange(atSymbol.textRange.startOffset, expression.textRange.endOffset)
}
}
private fun KtSimpleNameExpression.isCalleeExpression() =
(parent as? KtCallExpression)?.calleeExpression == this
private fun KtSimpleNameExpression.isConstructorCallReference(): Boolean {
val type = parent as? KtUserType ?: return false
val typeReference = type.parent as? KtTypeReference ?: return false
val constructorCallee = typeReference.parent as? KtConstructorCalleeExpression ?: return false
return constructorCallee.constructorReferenceExpression == this
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2010-2020 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.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiVariable
import com.intellij.psi.util.PsiUtilCore
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForPropertyDeclaration
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class VariableReferenceHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
if (!NameHighlighter.namesHighlightingEnabled) return
if (expression.isAssignmentReference()) return
if (expression.parent is KtInstanceExpressionWithLabel) return
if (expression.isAutoCreatedItParameter()) {
createInfoAnnotation(
expression,
Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER,
KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type")
)
return
}
val target = expression.mainReference.resolve()
when {
target != null && expression.isBackingField(target) -> Colors.BACKING_FIELD_VARIABLE
target is PsiMethod -> Colors.SYNTHETIC_EXTENSION_PROPERTY
target != null -> textAttributesKeyForPropertyDeclaration(target)
else -> null
}?.let { attribute ->
highlightName(expression, attribute)
if (target?.isMutableVariable() == true) {
highlightName(expression, Colors.MUTABLE_VARIABLE)
}
}
}
private fun KtSimpleNameExpression.isAutoCreatedItParameter(): Boolean {
return getReferencedName() == "it" // todo
}
}
private fun PsiElement.isMutableVariable() = when {
this is KtValVarKeywordOwner && PsiUtilCore.getElementType(valOrVarKeyword) == KtTokens.VAR_KEYWORD -> true
this is PsiVariable && !hasModifierProperty(PsiModifier.FINAL) -> true
else -> false
}
private fun KtSimpleNameExpression.isAssignmentReference(): Boolean {
if (this !is KtOperationReferenceExpression) return false
return operationSignTokenType == KtTokens.EQ
}
private fun KtSimpleNameExpression.isBackingField(target: PsiElement): Boolean {
if (getReferencedName() != "field") return false
if (target !is KtProperty) return false
val accessor = parentOfType<KtPropertyAccessor>() ?: return false
return accessor.parent == target
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -200,13 +200,15 @@ abstract class KotlinLightCodeInsightFixtureTestCase : KotlinLightCodeInsightFix
InTextDirectivesUtils.isDirectiveDefined(fileText, "ENABLE_MULTIPLATFORM") ->
KotlinProjectDescriptorWithFacet.KOTLIN_STABLE_WITH_MULTIPLATFORM
else -> KotlinLightProjectDescriptor.INSTANCE
else -> getDefaultProjectDescriptor()
}
} catch (e: IOException) {
throw rethrow(e)
}
}
protected open fun getDefaultProjectDescriptor(): KotlinLightProjectDescriptor = KotlinLightProjectDescriptor.INSTANCE
protected fun isAllFilesPresentInTest(): Boolean = KotlinTestUtils.isAllFilesPresentTest(getTestName(false))
protected fun performNotWriteEditorAction(actionId: String): Boolean {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -10,6 +10,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.ExpectedHighlightingData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.TagsTestDataUtil;
@@ -24,18 +25,23 @@ public abstract class AbstractHighlightingTest extends KotlinLightCodeInsightFix
public static final String NO_CHECK_WARNINGS_PREFIX = "// NO_CHECK_WARNINGS";
public static final String EXPECTED_DUPLICATED_HIGHLIGHTING_PREFIX = "// EXPECTED_DUPLICATED_HIGHLIGHTING";
protected void doTest(String unused) throws Exception {
String fileText = FileUtil.loadFile(new File(testPath()), true);
protected void checkHighlighting(@NotNull String fileText) {
boolean checkInfos = !InTextDirectivesUtils.isDirectiveDefined(fileText, NO_CHECK_INFOS_PREFIX);
boolean checkWeakWarnings = !InTextDirectivesUtils.isDirectiveDefined(fileText, NO_CHECK_WEAK_WARNINGS_PREFIX);
boolean checkWarnings = !InTextDirectivesUtils.isDirectiveDefined(fileText, NO_CHECK_WARNINGS_PREFIX);
myFixture.checkHighlighting(checkWarnings, checkInfos, checkWeakWarnings);
}
protected void doTest(String unused) throws Exception {
String fileText = FileUtil.loadFile(new File(testPath()), true);
boolean expectedDuplicatedHighlighting = InTextDirectivesUtils.isDirectiveDefined(fileText, EXPECTED_DUPLICATED_HIGHLIGHTING_PREFIX);
myFixture.configureByFile(fileName());
withExpectedDuplicatedHighlighting(expectedDuplicatedHighlighting, () -> {
try {
myFixture.checkHighlighting(checkWarnings, checkInfos, checkWeakWarnings);
checkHighlighting(fileText);
}
catch (FileComparisonFailure e) {
List<HighlightInfo> highlights =

View File

@@ -95,6 +95,7 @@ val projectsToShadow by extra(listOf(
":idea:idea-jps-common",
":idea:idea-frontend-independent",
":idea:idea-frontend-fir",
":idea:idea-frontend-api",
*if (Ide.IJ())
arrayOf(
":idea:idea-maven",

View File

@@ -185,6 +185,7 @@ include ":kotlin-build-common",
":idea:scripting-support",
":idea:idea-frontend-independent",
":idea:idea-frontend-fir",
":idea:idea-frontend-api",
":libraries:tools:new-project-wizard",
":idea:idea-new-project-wizard",
":libraries:tools:new-project-wizard:new-project-wizard-cli",