diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index a2e92eb3b75..2cfbf41962c 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -312,7 +312,7 @@ fun main(args: Array) { model("resolve/resolveModeComparison") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") @@ -1092,7 +1092,7 @@ fun main(args: Array) { model("resolve/references", pattern = KT_WITHOUT_DOTS_IN_NAME) } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 index ddae3330f6c..51ef15e2838 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 @@ -239,7 +239,7 @@ fun main(args: Array) { model("resolve/partialBodyResolve") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 index c74929eb79b..7e525475af3 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 @@ -235,7 +235,7 @@ fun main(args: Array) { model("resolve/partialBodyResolve") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties b/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties index f2e8aaddbe2..455b56a9cfe 100644 --- a/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties +++ b/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties @@ -40,6 +40,8 @@ html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr. intention.suppress.family=Suppress Warnings intention.suppress.text=Suppress ''{0}'' for {1} {2} +intention.calculating.text=Quick fix is being calculated ... + special.module.for.files.not.under.source.root= sdk.0= sources.for.library.0= diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt new file mode 100644 index 00000000000..919daceea10 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt @@ -0,0 +1,47 @@ +/* + * 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.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.Document +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext + +@Suppress("UnstableApiUsage") +abstract class AbstractBindingContextAwareHighlightingPassBase( + file: KtFile, + document: Document +) : AbstractHighlightingPassBase(file, document) { + + private val cachedAnnotator by lazy { annotator } + + protected abstract val annotator: Annotator + + private var bindingContext: BindingContext? = null + + protected fun bindingContext(): BindingContext = bindingContext ?: error("bindingContext has to be acquired") + + protected open fun buildBindingContext(holder: AnnotationHolder): BindingContext = + file.analyzeWithAllCompilerChecks().also { it.throwIfError() }.bindingContext + + override fun runAnnotatorWithContext(element: PsiElement, holder: AnnotationHolder) { + bindingContext = buildBindingContext(holder) + try { + element.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + cachedAnnotator.annotate(element, holder) + super.visitElement(element) + } + }) + } finally { + bindingContext = null + } + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt new file mode 100644 index 00000000000..3e9ae6bd035 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt @@ -0,0 +1,293 @@ +/* + * 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.codeInsight.daemon.impl.Divider +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.Document +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.util.CommonProcessors +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks +import org.jetbrains.kotlin.idea.quickfix.QuickFixes +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNameReferenceExpression +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.KotlinType +import java.lang.reflect.* +import java.util.* + +abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document) : + AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = KotlinAfterAnalysisAnnotator() + + private inner class KotlinAfterAnalysisAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + val bindingContext = bindingContext() + getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) } + } + } + + override fun buildBindingContext(holder: AnnotationHolder): BindingContext { + val dividedElements: List = ArrayList() + Divider.divideInsideAndOutsideAllRoots( + file, file.textRange, file.textRange, { true }, + CommonProcessors.CollectProcessor(dividedElements) + ) + // TODO: for the sake of check that element belongs to the file + // for some reason analyzeWithAllCompilerChecks could return psiElements those do not belong to the file + // see [ScriptConfigurationHighlightingTestGenerated$Highlighting.testCustomExtension] + val elements = dividedElements.flatMap(Divider.DividedElements::inside).toSet() + + // annotate diagnostics on fly: show diagnostics as soon as front-end reports them + // don't create quick fixes as it could require some resolve + val annotationByDiagnostic = mutableMapOf() + val annotationByTextRange = mutableMapOf() + + // render of on-fly diagnostics with descriptors could lead to recursion + fun checkIfDescriptor(candidate: Any?): Boolean = + candidate is DeclarationDescriptor || candidate is Collection<*> && candidate.any(::checkIfDescriptor) + + val analysisResult = + file.analyzeWithAllCompilerChecks({ + val element = it.psiElement + if (element in elements && + it !in annotationByDiagnostic && + !RenderingContext.parameters(it).any(::checkIfDescriptor) + ) { + annotateDiagnostic(element, holder, it, annotationByDiagnostic, annotationByTextRange) + } + }).also { it.throwIfError() } + // resolve is done! + + val bindingContext = analysisResult.bindingContext + + cleanUpCalculatingAnnotations(annotationByTextRange) + // TODO: for some reasons it could be duplicated diagnostics for the same factory + // see [PsiCheckerTestGenerated$Checker.testRedeclaration] + val diagnostics = bindingContext.diagnostics.asSequence().filter { it.psiElement in elements }.toSet() + + if (diagnostics.isNotEmpty()) { + // annotate diagnostics those were not possible to render on fly + diagnostics.asSequence().filterNot { it in annotationByDiagnostic }.forEach { + annotateDiagnostic(it.psiElement, holder, it, annotationByDiagnostic, calculatingInProgress = false) + } + // apply quick fixes for all diagnostics grouping by element + diagnostics.groupBy(Diagnostic::psiElement).forEach { + annotateQuickFixes(it.key, it.value, annotationByDiagnostic) + } + } + return bindingContext + } + + private fun annotateDiagnostic( + element: PsiElement, + holder: AnnotationHolder, + diagnostic: Diagnostic, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + calculatingInProgress: Boolean = true + ) = annotateDiagnostics(element, holder, listOf(diagnostic), annotationByDiagnostic, annotationByTextRange, true, calculatingInProgress) + + private fun cleanUpCalculatingAnnotations(annotationByTextRange: Map) { + annotationByTextRange.values.forEach { annotation -> + annotation.quickFixes?.removeIf { + it.quickFix is CalculatingIntentionAction + } + } + } + + private fun annotateDiagnostics( + element: PsiElement, + holder: AnnotationHolder, + diagnostics: List, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + noFixes: Boolean = false, + calculatingInProgress: Boolean = false + ) = annotateDiagnostics( + file, element, holder, diagnostics, annotationByDiagnostic, annotationByTextRange, + ::shouldSuppressUnusedParameter, + noFixes = noFixes, calculatingInProgress = calculatingInProgress + ) + + /** + * [diagnostics] has to belong to the same element + */ + private fun annotateQuickFixes( + element: PsiElement, + diagnostics: List, + annotationByDiagnostic: MutableMap + ) { + if (diagnostics.isEmpty()) return + + assertBelongsToTheSameElement(element, diagnostics) + + val shouldHighlightErrors = + KotlinHighlightingUtil.shouldHighlightErrors( + if (element.isPhysical) file else element + ) + + if (shouldHighlightErrors) { + ElementAnnotator(element) { param -> + shouldSuppressUnusedParameter(param) + }.registerDiagnosticsQuickFixes(diagnostics, annotationByDiagnostic) + } + } + + protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false + + companion object { + fun createQuickFixes(diagnostic: Diagnostic): Collection = + createQuickFixes(listOfNotNull(diagnostic))[diagnostic] + + private val UNRESOLVED_KEY = Key("KotlinHighlightingPass.UNRESOLVED_KEY") + + fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null + + fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( + PropertiesHighlightingVisitor(holder, bindingContext), + FunctionsHighlightingVisitor(holder, bindingContext), + VariablesHighlightingVisitor(holder, bindingContext), + TypeKindHighlightingVisitor(holder, bindingContext) + ) + + private fun assertBelongsToTheSameElement(element: PsiElement, diagnostics: Collection) { + assert(diagnostics.all { it.psiElement == element }) + } + + fun annotateDiagnostics( + file: KtFile, + element: PsiElement, + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + shouldSuppressUnusedParameter: (KtParameter) -> Boolean = { false }, + noFixes: Boolean = false, + calculatingInProgress: Boolean = false + ) { + if (diagnostics.isEmpty()) return + + assertBelongsToTheSameElement(element, diagnostics) + + if (element is KtNameReferenceExpression) { + val unresolved = diagnostics.any { it.factory == Errors.UNRESOLVED_REFERENCE } + element.putUserData(UNRESOLVED_KEY, if (unresolved) Unit else null) + } + + val shouldHighlightErrors = + KotlinHighlightingUtil.shouldHighlightErrors( + if (element.isPhysical) file else element + ) + + if (shouldHighlightErrors) { + val elementAnnotator = ElementAnnotator(element) { param -> + shouldSuppressUnusedParameter(param) + } + elementAnnotator.registerDiagnosticsAnnotations( + holder, diagnostics, annotationByDiagnostic, + annotationByTextRange, + noFixes = noFixes, calculatingInProgress = calculatingInProgress + ) + } + } + } +} + + +internal fun createQuickFixes(similarDiagnostics: Collection): MultiMap { + val first = similarDiagnostics.minByOrNull { it.toString() } + val factory = similarDiagnostics.first().getRealDiagnosticFactory() + + val actions = MultiMap() + + val intentionActionsFactories = QuickFixes.getInstance().getActionFactories(factory) + for (intentionActionsFactory in intentionActionsFactories) { + val allProblemsActions = intentionActionsFactory.createActionsForAllProblems(similarDiagnostics) + if (allProblemsActions.isNotEmpty()) { + actions.putValues(first, allProblemsActions) + } else { + for (diagnostic in similarDiagnostics) { + actions.putValues(diagnostic, intentionActionsFactory.createActions(diagnostic)) + } + } + } + + for (diagnostic in similarDiagnostics) { + actions.putValues(diagnostic, QuickFixes.getInstance().getActions(diagnostic.factory)) + } + + actions.values().forEach { NoDeclarationDescriptorsChecker.check(it::class.java) } + + return actions +} + +private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> = + when (factory) { + Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory + Errors.PLUGIN_WARNING -> Errors.PLUGIN_WARNING.cast(this).a.factory + Errors.PLUGIN_INFO -> Errors.PLUGIN_INFO.cast(this).a.factory + else -> factory + } + +private object NoDeclarationDescriptorsChecker { + private val LOG = Logger.getInstance(NoDeclarationDescriptorsChecker::class.java) + + private val checkedQuickFixClasses = Collections.synchronizedSet(HashSet>()) + + fun check(quickFixClass: Class<*>) { + if (!checkedQuickFixClasses.add(quickFixClass)) return + + for (field in quickFixClass.declaredFields) { + checkType(field.genericType, field) + } + + quickFixClass.superclass?.let { check(it) } + } + + private fun checkType(type: Type, field: Field) { + when (type) { + is Class<*> -> { + if (DeclarationDescriptor::class.java.isAssignableFrom(type) || KotlinType::class.java.isAssignableFrom(type)) { + LOG.error( + "QuickFix class ${field.declaringClass.name} contains field ${field.name} that holds ${type.simpleName}. " + + "This leads to holding too much memory through this quick-fix instance. " + + "Possible solution can be wrapping it using KotlinIntentionActionFactoryWithDelegate." + ) + } + + if (IntentionAction::class.java.isAssignableFrom(type)) { + check(type) + } + + } + + is GenericArrayType -> checkType(type.genericComponentType, field) + + is ParameterizedType -> { + if (Collection::class.java.isAssignableFrom(type.rawType as Class<*>)) { + type.actualTypeArguments.forEach { checkType(it, field) } + } + } + + is WildcardType -> type.upperBounds.forEach { checkType(it, field) } + } + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt index cd8bd2cb27a..0c15bd0e46e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt @@ -8,10 +8,9 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeInsight.intention.EmptyIntentionAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.lang.annotation.AnnotationBuilder +import com.intellij.lang.annotation.Annotation import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.HighlightSeverity -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.util.TextRange import com.intellij.util.containers.MultiMap @@ -20,6 +19,8 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix +import org.jetbrains.kotlin.idea.util.application.isApplicationInternalMode +import org.jetbrains.kotlin.idea.util.application.isUnitTestMode class AnnotationPresentationInfo( val ranges: List, @@ -28,32 +29,59 @@ class AnnotationPresentationInfo( val textAttributes: TextAttributesKey? = null ) { - fun processDiagnostics(holder: AnnotationHolder, diagnostics: List, fixesMap: MultiMap) { + fun processDiagnostics( + holder: AnnotationHolder, + diagnostics: Collection, + annotationBuilderByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap?, + fixesMap: MultiMap?, + calculatingInProgress: Boolean + ) { for (range in ranges) { for (diagnostic in diagnostics) { - val fixes = fixesMap[diagnostic] create(diagnostic, range, holder) { annotation -> - fixes.forEach { - when (it) { - is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix() - is IntentionAction -> annotation.newFix(it).registerFix() - } + annotationBuilderByDiagnostic?.put(diagnostic, annotation) + if (fixesMap != null) { + applyFixes(fixesMap, diagnostic, annotation) } - - if (diagnostic.severity == Severity.WARNING) { - annotation.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) - - if (fixes.isEmpty()) { - // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions - annotation.newFix(EmptyIntentionAction(diagnostic.factory.name!!)).registerFix() - } + if (calculatingInProgress && annotationByTextRange?.containsKey(range) == false) { + annotationByTextRange[range] = annotation + annotation.registerFix(CalculatingIntentionAction(), range) } } } } } - private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (AnnotationBuilder) -> Unit) { + internal fun applyFixes( + fixesMap: MultiMap, + diagnostic: Diagnostic, + annotation: Annotation + ) { + val fixes = fixesMap[diagnostic] + val textRange = TextRange(annotation.startOffset, annotation.endOffset) + fixes.forEach { + when (it) { + is KotlinUniversalQuickFix -> { + annotation.registerBatchFix(it, textRange, null) + annotation.registerFix(it, textRange) + } + is IntentionAction -> { + annotation.registerFix(it, textRange) + } + } + } + + if (diagnostic.severity == Severity.WARNING) { + if (fixes.isEmpty()) { + // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions + //annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix() + annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name), textRange) + } + } + } + + private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (Annotation) -> Unit) { val severity = when (diagnostic.severity) { Severity.ERROR -> HighlightSeverity.ERROR Severity.WARNING -> if (highlightType == ProblemHighlightType.WEAK_WARNING) { @@ -62,18 +90,26 @@ class AnnotationPresentationInfo( Severity.INFO -> HighlightSeverity.WEAK_WARNING } - holder.newAnnotation(severity, nonDefaultMessage ?: getDefaultMessage(diagnostic)) + + val message = nonDefaultMessage ?: getDefaultMessage(diagnostic) + holder.newAnnotation(severity, message) .range(range) .tooltip(getMessage(diagnostic)) .also { builder -> highlightType?.let { builder.highlightType(it) } } .also { builder -> textAttributes?.let { builder.textAttributes(it) } } - .also { consumer(it) } + .also { + if (diagnostic.severity == Severity.WARNING) { + it.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) + } + } .create() + @Suppress("UNCHECKED_CAST") + (holder as? List)?.last()?.let(consumer::invoke) } private fun getMessage(diagnostic: Diagnostic): String { var message = IdeErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + if (isApplicationInternalMode() || isUnitTestMode()) { val factoryName = diagnostic.factory.name message = if (message.startsWith("")) { "[$factoryName] ${message.substring("".length)}" @@ -89,10 +125,11 @@ class AnnotationPresentationInfo( private fun getDefaultMessage(diagnostic: Diagnostic): String { val message = DefaultErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { - return "[${diagnostic.factory.name}] $message" + return if (isApplicationInternalMode() || isUnitTestMode()) { + "[${diagnostic.factory.name}] $message" + } else { + message } - return message } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt new file mode 100644 index 00000000000..488af96bdf8 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2021 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.codeInsight.intention.AbstractEmptyIntentionAction +import com.intellij.codeInsight.intention.LowPriorityAction +import com.intellij.icons.AllIcons +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle +import javax.swing.Icon + +class CalculatingIntentionAction : AbstractEmptyIntentionAction(), LowPriorityAction, Iconable { + override fun getText(): String = KotlinIdeaAnalysisBundle.message("intention.calculating.text") + + override fun getFamilyName(): String = KotlinIdeaAnalysisBundle.message("intention.calculating.text") + + override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean = true + + override fun equals(other: Any?): Boolean = this === other || other is CalculatingIntentionAction + + override fun hashCode(): Int = 42 + + override fun getIcon(@Iconable.IconFlags flags: Int): Icon = AllIcons.Actions.Preview +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt new file mode 100644 index 00000000000..beec88a4edb --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt @@ -0,0 +1,100 @@ +/* + * 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.codeHighlighting.* +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.checkers.utils.DebugInfoUtil +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.application.isApplicationInternalMode +import org.jetbrains.kotlin.psi.KtCodeFragment +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtReferenceExpression + +class DebugInfoHighlightingPass(file: KtFile, document: Document) : AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = DebugInfoAnnotator() + + private inner class DebugInfoAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element is KtFile && element !is KtCodeFragment) { + fun errorAnnotation( + expression: PsiElement, + message: String, + textAttributes: TextAttributesKey? = KotlinHighlightingColors.DEBUG_INFO + ) = + holder.newAnnotation(HighlightSeverity.ERROR, "[DEBUG] $message") + .range(expression.textRange) + .also { + textAttributes?.let { ta -> it.textAttributes(ta) } + } + .create() + + try { + DebugInfoUtil.markDebugAnnotations(element, bindingContext(), object : DebugInfoUtil.DebugInfoReporter() { + override fun reportElementWithErrorType(expression: KtReferenceExpression) = + errorAnnotation(expression, "Resolved to error element", KotlinHighlightingColors.RESOLVED_TO_ERROR) + + override fun reportMissingUnresolved(expression: KtReferenceExpression) = + errorAnnotation( + expression, + "Reference is not resolved to anything, but is not marked unresolved" + ) + + override fun reportUnresolvedWithTarget(expression: KtReferenceExpression, target: String) = + errorAnnotation( + expression, + "Reference marked as unresolved is actually resolved to $target" + ) + }) + } catch (e: ProcessCanceledException) { + throw e + } catch (e: Throwable) { + // TODO + errorAnnotation(element, e.javaClass.canonicalName + ": " + e.message, null) + e.printStackTrace() + } + + } + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + return if (file is KtFile && + (isApplicationInternalMode() && (KotlinPluginUtil.isSnapshotVersion() || KotlinPluginUtil.isDevVersion())) && + ProjectRootsUtil.isInProjectOrLibSource(file) + ) { + DebugInfoHighlightingPass(file, editor.document) + } else { + null + } + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runAfterStartingOf = */ null, + /* runIntentionsPassAfter = */ false, + /* forcedPassId = */ -1 + ) + } + } + +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt deleted file mode 100644 index 56818c1b443..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.highlighter - -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.Annotator -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.asJava.* -import org.jetbrains.kotlin.idea.caches.project.getModuleInfo -import org.jetbrains.kotlin.idea.caches.resolve.* -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.platform.jvm.isJvm - -class DuplicateJvmSignatureAnnotator : Annotator { - override fun annotate(element: PsiElement, holder: AnnotationHolder) { - if (element !is KtFile && element !is KtDeclaration) return - if (!ProjectRootsUtil.isInProjectSource(element)) return - - val file = element.containingFile - if (file !is KtFile || !TargetPlatformDetector.getPlatform(file).isJvm()) return - - val otherDiagnostics = when (element) { - is KtDeclaration -> element.analyzeWithContent() - is KtFile -> element.analyzeWithContent() - else -> throw AssertionError("DuplicateJvmSignatureAnnotator: should not get here! Element: ${element.text}") - }.diagnostics - - val moduleScope = element.getModuleInfo().contentScope() - val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return - - KotlinPsiChecker().annotateElement(element, holder, diagnostics) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt new file mode 100644 index 00000000000..ca1bba3a9e8 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt @@ -0,0 +1,74 @@ +/* + * 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.codeHighlighting.* +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics +import org.jetbrains.kotlin.idea.caches.project.getModuleInfo +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass.Companion.annotateDiagnostics +import org.jetbrains.kotlin.idea.project.TargetPlatformDetector +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile + +class DuplicateJvmSignatureHighlightPass(file: KtFile, document: Document) : + AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = DuplicateJvmSignatureAnnotator() + + inner class DuplicateJvmSignatureAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element !is KtFile && element !is KtDeclaration) return + + val otherDiagnostics = when (element) { + is KtDeclaration -> element.analyzeWithContent() + is KtFile -> element.analyzeWithContent() + else -> throw AssertionError("DuplicateJvmSignatureAnnotator: should not get here! Element: ${element.text}") + }.diagnostics + + val moduleScope = element.getModuleInfo().contentScope() + val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return + + val diagnosticsForElement = diagnostics.forElement(element).toSet() + + annotateDiagnostics(file, element, holder, diagnosticsForElement) + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + return if (file is KtFile && + ProjectRootsUtil.isInProjectSource(file) && + TargetPlatformDetector.getPlatform(file).isJvm() + ) { + DuplicateJvmSignatureHighlightPass(file, editor.document) + } else { + null + } + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runAfterStartingOf = */ null, + /* runIntentionsPassAfter = */ false, + /* forcedPassId = */ -1 + ) + } + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt new file mode 100644 index 00000000000..82467f68b1f --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt @@ -0,0 +1,214 @@ +/* + * 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.codeInsight.intention.IntentionAction +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.diagnostic.ControlFlowException +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.colors.CodeInsightColors +import com.intellij.openapi.util.TextRange +import com.intellij.psi.MultiRangeReference +import com.intellij.psi.PsiElement +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.KtReferenceExpression + +internal class ElementAnnotator( + private val element: PsiElement, + private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean +) { + fun registerDiagnosticsAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) = diagnostics.groupBy { it.factory } + .forEach { + registerSameFactoryDiagnosticsAnnotations( + holder, + it.value, + annotationByDiagnostic, + annotationByTextRange, + noFixes, + calculatingInProgress + ) + } + + private fun registerSameFactoryDiagnosticsAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) { + val presentationInfo = presentationInfo(diagnostics) ?: return + setUpAnnotations( + holder, + diagnostics, + presentationInfo, + annotationByDiagnostic, + annotationByTextRange, + noFixes, + calculatingInProgress + ) + } + + fun registerDiagnosticsQuickFixes( + diagnostics: List, + annotationByDiagnostic: MutableMap + ) = diagnostics.groupBy { it.factory } + .forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, annotationByDiagnostic) } + + private fun registerDiagnosticsSameFactoryQuickFixes( + diagnostics: List, + annotationByDiagnostic: MutableMap + ) { + val presentationInfo = presentationInfo(diagnostics) ?: return + val fixesMap = createFixesMap(diagnostics) ?: return + + diagnostics.forEach { + val annotation = annotationByDiagnostic[it] ?: return + + presentationInfo.applyFixes(fixesMap, it, annotation) + } + } + + private fun presentationInfo(diagnostics: Collection): AnnotationPresentationInfo? { + if (diagnostics.isEmpty() || !diagnostics.any { it.isValid }) return null + + val diagnostic = diagnostics.first() + // hack till the root cause #KT-21246 is fixed + if (isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic)) return null + + val factory = diagnostic.factory + + assert(diagnostics.all { it.psiElement == element && it.factory == factory }) + + val ranges = diagnostic.textRanges + val presentationInfo: AnnotationPresentationInfo = when (factory.severity) { + Severity.ERROR -> { + when (factory) { + in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS -> { + val referenceExpression = element as KtReferenceExpression + val reference = referenceExpression.mainReference + if (reference is MultiRangeReference) { + AnnotationPresentationInfo( + ranges = reference.ranges.map { it.shiftRight(referenceExpression.textOffset) }, + highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL + ) + } else { + AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + } + } + + Errors.ILLEGAL_ESCAPE -> AnnotationPresentationInfo( + ranges, textAttributes = KotlinHighlightingColors.INVALID_STRING_ESCAPE + ) + + Errors.REDECLARATION -> AnnotationPresentationInfo( + ranges = listOf(diagnostic.textRanges.first()), nonDefaultMessage = "" + ) + + else -> { + AnnotationPresentationInfo( + ranges, + highlightType = if (factory == Errors.INVISIBLE_REFERENCE) + ProblemHighlightType.LIKE_UNKNOWN_SYMBOL + else + null + ) + } + } + } + Severity.WARNING -> { + if (factory == Errors.UNUSED_PARAMETER && shouldSuppressUnusedParameter(element as KtParameter)) { + return null + } + + AnnotationPresentationInfo( + ranges, + textAttributes = when (factory) { + Errors.DEPRECATION -> CodeInsightColors.DEPRECATED_ATTRIBUTES + Errors.UNUSED_ANONYMOUS_PARAMETER -> CodeInsightColors.WEAK_WARNING_ATTRIBUTES + else -> null + }, + highlightType = when (factory) { + in Errors.UNUSED_ELEMENT_DIAGNOSTICS -> ProblemHighlightType.LIKE_UNUSED_SYMBOL + Errors.UNUSED_ANONYMOUS_PARAMETER -> ProblemHighlightType.WEAK_WARNING + else -> null + } + ) + } + Severity.INFO -> AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.INFORMATION) + } + return presentationInfo + } + + private fun setUpAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + data: AnnotationPresentationInfo, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) { + val fixesMap = + createFixesMap(diagnostics, noFixes) + + data.processDiagnostics(holder, diagnostics, annotationByDiagnostic, annotationByTextRange, fixesMap, calculatingInProgress) + } + + private fun createFixesMap( + diagnostics: Collection, + noFixes: Boolean = false + ): MultiMap? = if (noFixes) { + null + } else { + try { + createQuickFixes(diagnostics) + } catch (e: Exception) { + if (e is ControlFlowException) { + throw e + } + LOG.error(e) + MultiMap() + } + } + + private fun isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic: Diagnostic): Boolean { + val factory = diagnostic.factory + if (factory != Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS && factory != Errors.FIR_COMPILED_CLASS) return false + + val module = element.module ?: return false + val moduleFacetSettings = KotlinFacetSettingsProvider.getInstance(element.project)?.getSettings(module) ?: return false + return when (factory) { + Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS -> + moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useIR) && + !moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useOldBackend) + Errors.FIR_COMPILED_CLASS -> + moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useFir) + else -> error(factory) + } + } + + companion object { + val LOG = Logger.getInstance(ElementAnnotator::class.java) + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt index f2656bc597c..e53d590fe0a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt @@ -34,7 +34,10 @@ import kotlin.script.experimental.api.ScriptDiagnostic object KotlinHighlightingUtil { fun shouldHighlight(psiElement: PsiElement): Boolean { val ktFile = psiElement.containingFile as? KtFile ?: return false + return shouldHighlightFile(ktFile) + } + fun shouldHighlightFile(ktFile: KtFile): Boolean { if (ktFile is KtCodeFragment && ktFile.context != null) { return true } @@ -52,8 +55,12 @@ object KotlinHighlightingUtil { return ProjectRootsUtil.isInProjectOrLibraryContent(ktFile) && ktFile.getModuleInfo() !is NotUnderContentRootModuleInfo } - fun shouldHighlightErrors(psiElement: PsiElement): Boolean { - val ktFile = psiElement.containingFile as? KtFile ?: return false + fun shouldHighlightErrors(psiElement: PsiElement): Boolean = + (psiElement.containingFile as? KtFile)?.let { + shouldHighlightErrors(it) + } ?: false + + fun shouldHighlightErrors(ktFile: KtFile): Boolean { if (ktFile.isCompiled) { return false } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt deleted file mode 100644 index 18b0bd371fd..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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.codeInsight.intention.IntentionAction -import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.openapi.diagnostic.ControlFlowException -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.editor.colors.CodeInsightColors -import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.util.Key -import com.intellij.psi.MultiRangeReference -import com.intellij.psi.PsiElement -import com.intellij.util.containers.MultiMap -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.config.KotlinFacetSettings -import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.diagnostics.DiagnosticFactory -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks -import org.jetbrains.kotlin.idea.quickfix.QuickFixes -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.idea.util.module -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtNameReferenceExpression -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtReferenceExpression -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics -import org.jetbrains.kotlin.types.KotlinType -import java.lang.reflect.* -import java.util.* - -open class KotlinPsiChecker : AbstractKotlinPsiChecker() { - override fun shouldHighlight(file: KtFile): Boolean = KotlinHighlightingUtil.shouldHighlight(file) - - override fun annotateElement( - element: PsiElement, - containingFile: KtFile, - holder: AnnotationHolder - ) { - val analysisResult = containingFile.analyzeWithAllCompilerChecks() - if (analysisResult.isError()) { - throw ProcessCanceledException(analysisResult.error) - } - - val bindingContext = analysisResult.bindingContext - - getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) } - - annotateElement(element, holder, bindingContext.diagnostics) - } - - protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false - - fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) { - val diagnosticsForElement = diagnostics.forElement(element).toSet() - - if (element is KtNameReferenceExpression) { - val unresolved = diagnostics.any { it.factory == Errors.UNRESOLVED_REFERENCE } - element.putUserData(UNRESOLVED_KEY, if (unresolved) Unit else null) - } - - if (diagnosticsForElement.isEmpty()) return - - if (KotlinHighlightingUtil.shouldHighlightErrors(element)) { - ElementAnnotator(element, holder) { param -> - shouldSuppressUnusedParameter(param) - }.registerDiagnosticsAnnotations(diagnosticsForElement) - } - } - - companion object { - fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( - PropertiesHighlightingVisitor(holder, bindingContext), - FunctionsHighlightingVisitor(holder, bindingContext), - VariablesHighlightingVisitor(holder, bindingContext), - TypeKindHighlightingVisitor(holder, bindingContext) - ) - - fun createQuickFixes(diagnostic: Diagnostic): Collection = - createQuickFixes(listOfNotNull(diagnostic))[diagnostic] - - private val UNRESOLVED_KEY = Key("KotlinPsiChecker.UNRESOLVED_KEY") - - fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null - } -} - -private fun createQuickFixes(similarDiagnostics: Collection): MultiMap { - val first = similarDiagnostics.minByOrNull { it.toString() } - val factory = similarDiagnostics.first().getRealDiagnosticFactory() - - val actions = MultiMap() - - val intentionActionsFactories = QuickFixes.getInstance().getActionFactories(factory) - for (intentionActionsFactory in intentionActionsFactories) { - val allProblemsActions = intentionActionsFactory.createActionsForAllProblems(similarDiagnostics) - if (allProblemsActions.isNotEmpty()) { - actions.putValues(first, allProblemsActions) - } else { - for (diagnostic in similarDiagnostics) { - actions.putValues(diagnostic, intentionActionsFactory.createActions(diagnostic)) - } - } - } - - for (diagnostic in similarDiagnostics) { - actions.putValues(diagnostic, QuickFixes.getInstance().getActions(diagnostic.factory)) - } - - actions.values().forEach { NoDeclarationDescriptorsChecker.check(it::class.java) } - - return actions -} - -private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> = - when (factory) { - Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory - Errors.PLUGIN_WARNING -> Errors.PLUGIN_WARNING.cast(this).a.factory - Errors.PLUGIN_INFO -> Errors.PLUGIN_INFO.cast(this).a.factory - else -> factory - } - -private object NoDeclarationDescriptorsChecker { - private val LOG = Logger.getInstance(NoDeclarationDescriptorsChecker::class.java) - - private val checkedQuickFixClasses = Collections.synchronizedSet(HashSet>()) - - fun check(quickFixClass: Class<*>) { - if (!checkedQuickFixClasses.add(quickFixClass)) return - - for (field in quickFixClass.declaredFields) { - checkType(field.genericType, field) - } - - quickFixClass.superclass?.let { check(it) } - } - - private fun checkType(type: Type, field: Field) { - when (type) { - is Class<*> -> { - if (DeclarationDescriptor::class.java.isAssignableFrom(type) || KotlinType::class.java.isAssignableFrom(type)) { - LOG.error( - "QuickFix class ${field.declaringClass.name} contains field ${field.name} that holds ${type.simpleName}. " - + "This leads to holding too much memory through this quick-fix instance. " - + "Possible solution can be wrapping it using KotlinIntentionActionFactoryWithDelegate." - ) - } - - if (IntentionAction::class.java.isAssignableFrom(type)) { - check(type) - } - - } - - is GenericArrayType -> checkType(type.genericComponentType, field) - - is ParameterizedType -> { - if (Collection::class.java.isAssignableFrom(type.rawType as Class<*>)) { - type.actualTypeArguments.forEach { checkType(it, field) } - } - } - - is WildcardType -> type.upperBounds.forEach { checkType(it, field) } - } - } -} - -private class ElementAnnotator( - private val element: PsiElement, - private val holder: AnnotationHolder, - private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean -) { - fun registerDiagnosticsAnnotations(diagnostics: Collection) { - diagnostics.groupBy { it.factory }.forEach { group -> registerDiagnosticAnnotations(group.value) } - } - - private fun registerDiagnosticAnnotations(diagnostics: List) { - assert(diagnostics.isNotEmpty()) - - val validDiagnostics = diagnostics.filter { it.isValid } - if (validDiagnostics.isEmpty()) return - - val diagnostic = diagnostics.first() - val factory = diagnostic.factory - - // hack till the root cause #KT-21246 is fixed - if (isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic)) return - - assert(diagnostics.all { it.psiElement == element && it.factory == factory }) - - val ranges = diagnostic.textRanges - - val presentationInfo: AnnotationPresentationInfo = when (factory.severity) { - Severity.ERROR -> { - when (factory) { - in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS -> { - val referenceExpression = element as KtReferenceExpression - val reference = referenceExpression.mainReference - if (reference is MultiRangeReference) { - AnnotationPresentationInfo( - ranges = reference.ranges.map { it.shiftRight(referenceExpression.textOffset) }, - highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - ) - } else { - AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - } - } - - Errors.ILLEGAL_ESCAPE -> AnnotationPresentationInfo( - ranges, textAttributes = KotlinHighlightingColors.INVALID_STRING_ESCAPE - ) - - Errors.REDECLARATION -> AnnotationPresentationInfo( - ranges = listOf(diagnostic.textRanges.first()), nonDefaultMessage = "" - ) - - else -> { - AnnotationPresentationInfo( - ranges, - highlightType = if (factory == Errors.INVISIBLE_REFERENCE) - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - else - null - ) - } - } - } - Severity.WARNING -> { - if (factory == Errors.UNUSED_PARAMETER && shouldSuppressUnusedParameter(element as KtParameter)) { - return - } - - AnnotationPresentationInfo( - ranges, - textAttributes = when (factory) { - Errors.DEPRECATION -> CodeInsightColors.DEPRECATED_ATTRIBUTES - Errors.UNUSED_ANONYMOUS_PARAMETER -> CodeInsightColors.WEAK_WARNING_ATTRIBUTES - else -> null - }, - highlightType = when (factory) { - in Errors.UNUSED_ELEMENT_DIAGNOSTICS -> ProblemHighlightType.LIKE_UNUSED_SYMBOL - Errors.UNUSED_ANONYMOUS_PARAMETER -> ProblemHighlightType.WEAK_WARNING - else -> null - } - ) - } - Severity.INFO -> AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.INFORMATION) - } - - setUpAnnotations(diagnostics, presentationInfo) - } - - private fun setUpAnnotations(diagnostics: List, data: AnnotationPresentationInfo) { - val fixesMap = try { - createQuickFixes(diagnostics) - } catch (e: Exception) { - if (e is ControlFlowException) { - throw e - } - LOG.error(e) - MultiMap() - } - - data.processDiagnostics(holder, diagnostics, fixesMap) - } - - private fun isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic: Diagnostic): Boolean { - val factory = diagnostic.factory - if (factory != Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS && factory != Errors.FIR_COMPILED_CLASS) return false - - val module = element.module ?: return false - val moduleFacetSettings = KotlinFacetSettingsProvider.getInstance(element.project)?.getSettings(module) ?: return false - return when (factory) { - Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS -> - moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useIR) && - !moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useOldBackend) - Errors.FIR_COMPILED_CLASS -> - moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useFir) - else -> error(factory) - } - } - - companion object { - val LOG = Logger.getInstance(ElementAnnotator::class.java) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt index 0bdc9234c72..5778f16260c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt @@ -35,8 +35,8 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon if (target is ValueParameterDescriptor && bindingContext.get(AUTO_CREATED_IT, target) == true) { createInfoAnnotation( expression, - FUNCTION_LITERAL_DEFAULT_PARAMETER, - KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type") + KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type"), + FUNCTION_LITERAL_DEFAULT_PARAMETER ) } else if (expression.parent !is KtValueArgumentName) { // highlighted separately highlightVariable(expression, target) @@ -91,14 +91,15 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon "0.smart.cast.to.1", receiverName, DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type) - ) - ).textAttributes = SMART_CAST_RECEIVER + ), + SMART_CAST_RECEIVER + ) } } val nullSmartCast = bindingContext.get(SMARTCAST_NULL, expression) == true if (nullSmartCast) { - createInfoAnnotation(expression, KotlinIdeaAnalysisBundle.message("always.null")).textAttributes = SMART_CONSTANT + createInfoAnnotation(expression, KotlinIdeaAnalysisBundle.message("always.null"), SMART_CONSTANT) } val smartCast = bindingContext.get(SMARTCAST, expression) @@ -107,8 +108,9 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon if (defaultType != null) { createInfoAnnotation( getSmartCastTarget(expression), - KotlinIdeaAnalysisBundle.message("smart.cast.to.0", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(defaultType)) - ).textAttributes = SMART_CAST_VALUE + KotlinIdeaAnalysisBundle.message("smart.cast.to.0", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(defaultType)), + SMART_CAST_VALUE + ) } else if (smartCast is MultipleSmartCasts) { for ((call, type) in smartCast.map) { createInfoAnnotation( @@ -117,8 +119,9 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon "smart.cast.to.0.for.1.call", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type), call.toString() - ) - ).textAttributes = SMART_CAST_VALUE + ), + SMART_CAST_VALUE + ) } } } @@ -154,7 +157,7 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon val parent = elementToHighlight.parent if (!(parent is PsiNameIdentifierOwner && parent.nameIdentifier == elementToHighlight)) { - createInfoAnnotation(elementToHighlight, WRAPPED_INTO_REF, msg) + createInfoAnnotation(elementToHighlight, msg, WRAPPED_INTO_REF) return } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt index 955430e86d4..e9e3c7d3dd6 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt @@ -9,7 +9,8 @@ import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.progress.ProgressManager import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.psi.KtCallExpression @@ -28,7 +29,7 @@ class FromUnresolvedNamesCompletion( scope.forEachDescendantOfType { refExpr -> ProgressManager.checkCanceled() - if (KotlinPsiChecker.wasUnresolved(refExpr)) { + if (AbstractKotlinHighlightingPass.wasUnresolved(refExpr)) { val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr) if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType if (sampleDescriptor != null) { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt index add37568aa3..eb8c0166d41 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors import org.jetbrains.kotlin.psi.* internal class ExpressionsSmartcastHighlightingVisitor( @@ -30,8 +31,9 @@ internal class ExpressionsSmartcastHighlightingVisitor( "0.smart.cast.to.1", receiverName, type.asStringForDebugging() - ) - ).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_RECEIVER + ), + KotlinHighlightingColors.SMART_CAST_RECEIVER + ) } } expression.getSmartCasts()?.forEach { type -> @@ -40,8 +42,9 @@ internal class ExpressionsSmartcastHighlightingVisitor( KotlinIdeaAnalysisBundle.message( "smart.cast.to.0", type.asStringForDebugging() - ) - ).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_VALUE + ), + KotlinHighlightingColors.SMART_CAST_VALUE + ) } //todo smartcast to null diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt index 0348a0cf832..4a378ce9e37 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.idea.fir.highlighter.visitors import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.highlighter.HighlightingVisitor @@ -14,6 +16,12 @@ abstract class FirAfterResolveHighlightingVisitor( protected val holder: AnnotationHolder ) : HighlightingVisitor(holder) { + override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) { + // TODO: Temporary use deprecated for FIR plugin as it is supposes to be rewritten fully + holder.createInfoAnnotation(textRange, message) + .also { annotation -> textAttributes?.let { annotation.textAttributes = textAttributes } } + } + companion object { fun createListOfVisitors( analysisSession: KtAnalysisSession, diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt index 316079c6e2f..b22dad28b3b 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt @@ -34,8 +34,8 @@ internal class VariableReferenceHighlightingVisitor( if (expression.isAutoCreatedItParameter()) { createInfoAnnotation( expression, - Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER, - KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type") + KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type"), + Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER ) return } diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt similarity index 95% rename from idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt rename to idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt index 2630a8431f0..c58d50a881c 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.uitls.IgnoreTests import java.io.File -abstract class AbstractFirPsiCheckerTest : AbstractPsiCheckerTest() { +abstract class AbstractFirKotlinHighlightingPassTest : AbstractKotlinHighlightingPassTest() { override val captureExceptions: Boolean = false override fun isFirPlugin(): Boolean = true diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java similarity index 97% rename from idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java rename to idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java index dde41ce45cf..6b27c7511c8 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java @@ -18,11 +18,11 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @RunWith(JUnit3RunnerWithInners.class) -public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { +public class FirKotlinHighlightingPassTestGenerated extends AbstractFirKotlinHighlightingPassTest { @TestMetadata("idea/testData/checker") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Checker extends AbstractFirPsiCheckerTest { + public static class Checker extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -41,6 +41,11 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { runTest("idea/testData/checker/AnnotationOnFile.kt"); } + @TestMetadata("AnnotationSupressing.kt") + public void testAnnotationSupressing() throws Exception { + runTest("idea/testData/checker/AnnotationSupressing.kt"); + } + @TestMetadata("AnonymousInitializers.kt") public void testAnonymousInitializers() throws Exception { runTest("idea/testData/checker/AnonymousInitializers.kt"); @@ -365,7 +370,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/regression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Regression extends AbstractFirPsiCheckerTest { + public static class Regression extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -608,7 +613,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/recovery") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Recovery extends AbstractFirPsiCheckerTest { + public static class Recovery extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -636,7 +641,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/rendering") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Rendering extends AbstractFirPsiCheckerTest { + public static class Rendering extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -654,7 +659,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/infos") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Infos extends AbstractFirPsiCheckerTest { + public static class Infos extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -747,7 +752,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/diagnosticsMessage") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DiagnosticsMessage extends AbstractFirPsiCheckerTest { + public static class DiagnosticsMessage extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt new file mode 100644 index 00000000000..07f21d2ad9b --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt @@ -0,0 +1,84 @@ +/* + * 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.codeHighlighting.TextEditorHighlightingPass +import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl +import com.intellij.codeInsight.daemon.impl.HighlightInfo +import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.AnnotationSession +import com.intellij.openapi.editor.Document +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAware +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import org.jetbrains.kotlin.psi.KtFile + +/** + * Single thread model only (as any other [TextEditorHighlightingPass]) + */ +@Suppress("UnstableApiUsage") +abstract class AbstractHighlightingPassBase( + protected val file: KtFile, + document: Document +) : TextEditorHighlightingPass(file.project, document), DumbAware { + + private val highlightInfos: MutableList = mutableListOf() + protected var annotationCallback: ((Annotation) -> Unit)? = null + protected var annotationHolder: AnnotationHolderImpl? = null + + fun annotationCallback(callback: (Annotation) -> Unit) { + annotationCallback = callback + } + + fun resetAnnotationCallback() { + annotationCallback = null + } + + override fun doCollectInformation(progress: ProgressIndicator) { + highlightInfos.clear() + + // TODO: YES, IT USES `@ApiStatus.Internal` AnnotationHolderImpl intentionally: + // there is no other way to highlight: + // - HighlightInfo could not be highlighted immediately as myHighlightInfoProcessor.infoIsAvailable is not accessible + // (HighlightingSessionImpl impl is closed) and/or UpdateHighlightersUtil.addHighlighterToEditorIncrementally is closed as well. + // therefore direct usage of AnnotationHolderImpl is the smallest evil + + val annotationHolder = object : AnnotationHolderImpl(AnnotationSession(file)) { + override fun add(element: Annotation?): Boolean { + element?.let { annotationCallback?.invoke(it) } + return super.add(element) + } + } + annotationHolder.runAnnotatorWithContext(file) { element, holder -> + runAnnotatorWithContext(element, holder) + } + this.annotationHolder = annotationHolder + } + + protected open fun runAnnotatorWithContext( + element: PsiElement, + holder: AnnotationHolder + ) { + element.accept(object : PsiRecursiveElementVisitor() {}) + } + + override fun getInfos(): MutableList = highlightInfos + + override fun doApplyInformationToEditor() { + try { + val infos = annotationHolder?.map { HighlightInfo.fromAnnotation(it) } ?: return + highlightInfos.addAll(infos) + // NOTE: keep !! for 201 version + UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) + } finally { + annotationHolder = null + } + } + +} \ No newline at end of file diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt index b6fd735475c..e59e13c300d 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt @@ -38,7 +38,7 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High else -> return } - createInfoAnnotation(element, null).textAttributes = attributes + createInfoAnnotation(element, textAttributes = attributes) } private fun willApplyRainbowHighlight(element: KDocLink): Boolean { @@ -53,27 +53,29 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High if (ApplicationManager.getApplication().isUnitTestMode) return val functionLiteral = lambdaExpression.functionLiteral - createInfoAnnotation(functionLiteral.lBrace, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(functionLiteral.lBrace, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) val closingBrace = functionLiteral.rBrace if (closingBrace != null) { - createInfoAnnotation(closingBrace, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(closingBrace, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) } val arrow = functionLiteral.arrow if (arrow != null) { - createInfoAnnotation(arrow, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(arrow, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) } } override fun visitArgument(argument: KtValueArgument) { val argumentName = argument.getArgumentName() ?: return val eq = argument.equalsToken ?: return - createInfoAnnotation(TextRange(argumentName.startOffset, eq.endOffset), null).textAttributes = - if (argument.parent.parent is KtAnnotationEntry) + createInfoAnnotation( + TextRange(argumentName.startOffset, eq.endOffset), + textAttributes = if (argument.parent.parent is KtAnnotationEntry) KotlinHighlightingColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES else KotlinHighlightingColors.NAMED_ARGUMENT + ) } override fun visitExpressionWithLabel(expression: KtExpressionWithLabel) { diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt index 500140cae50..df4edf914ab 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.lang.annotation.Annotation import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement @@ -17,29 +18,34 @@ abstract class HighlightingVisitor protected constructor( private val holder: AnnotationHolder ) : KtVisitorVoid() { - protected fun createInfoAnnotation(element: PsiElement, textAttributes: TextAttributesKey, message: String? = null) { - createInfoAnnotation(element.textRange, textAttributes, message) + protected fun createInfoAnnotation(element: PsiElement, message: String? = null, textAttributes: TextAttributesKey) { + createInfoAnnotation(element.textRange, message, textAttributes) } - protected fun createInfoAnnotation(range: TextRange, textAttributes: TextAttributesKey, message: String? = null) { - createInfoAnnotation(range, message).textAttributes = textAttributes - } - - protected fun createInfoAnnotation(element: PsiElement, message: String? = null): Annotation = + protected fun createInfoAnnotation(element: PsiElement, message: String? = null) = createInfoAnnotation(element.textRange, message) - protected fun createInfoAnnotation(textRange: TextRange, message: String? = null): Annotation = - holder.createInfoAnnotation(textRange, message) + protected open fun createInfoAnnotation(textRange: TextRange, message: String? = null, textAttributes: TextAttributesKey? = null) { + (message?.let { holder.newAnnotation(HighlightSeverity.INFORMATION, it) } + ?: holder.newSilentAnnotation(HighlightSeverity.INFORMATION)) + .range(textRange) + .also { builder -> + textAttributes?.let { + builder.textAttributes(it) + } + } + .create() + } protected fun highlightName(element: PsiElement, attributesKey: TextAttributesKey, message: String? = null) { if (NameHighlighter.namesHighlightingEnabled && !element.textRange.isEmpty) { - createInfoAnnotation(element, attributesKey, message) + createInfoAnnotation(element, message, attributesKey) } } protected fun highlightName(textRange: TextRange, attributesKey: TextAttributesKey, message: String? = null) { if (NameHighlighter.namesHighlightingEnabled) { - createInfoAnnotation(textRange, attributesKey, message) + createInfoAnnotation(textRange, message, attributesKey) } } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt index 597c8ea58ea..4d3e3c34af5 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt @@ -6,51 +6,29 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeHighlighting.* -import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl -import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.AnnotationSession import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiRecursiveElementVisitor import org.jetbrains.kotlin.psi.KtFile -class KotlinBeforeResolveHighlightingPass( - private val file: KtFile, - document: Document -) : TextEditorHighlightingPass(file.project, document), DumbAware { +class KotlinBeforeResolveHighlightingPass(file: KtFile, document: Document) : AbstractHighlightingPassBase(file, document) { - @Volatile - private var annotationHolder: AnnotationHolderImpl? = null + override fun runAnnotatorWithContext(element: PsiElement, holder: AnnotationHolder) { + val visitor = BeforeResolveHighlightingVisitor(holder) + val extensions = EP_NAME.extensionList.map { it.createVisitor(holder) } - override fun doCollectInformation(progress: ProgressIndicator) { - val annotationHolder = AnnotationHolderImpl(AnnotationSession(file)) - val visitor = BeforeResolveHighlightingVisitor(annotationHolder) - val extensions = EP_NAME.extensionList.map { it.createVisitor(annotationHolder) } - file.accept(object : PsiRecursiveElementVisitor() { + element.accept(object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { - super.visitElement(element) element.accept(visitor) extensions.forEach(element::accept) + super.visitElement(element) } }) - this.annotationHolder = annotationHolder - } - - override fun doApplyInformationToEditor() { - if (annotationHolder == null) return - - val infos = annotationHolder!!.map { HighlightInfo.fromAnnotation(it) } - - UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) - annotationHolder = null } class Factory : TextEditorHighlightingPassFactory { @@ -64,10 +42,10 @@ class KotlinBeforeResolveHighlightingPass( override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { registrar.registerTextEditorHighlightingPass( Factory(), - TextEditorHighlightingPassRegistrar.Anchor.BEFORE, - Pass.UPDATE_FOLDING, - false, - false + /* anchor = */ TextEditorHighlightingPassRegistrar.Anchor.BEFORE, + /* anchorPassId = */ Pass.UPDATE_FOLDING, + /* needAdditionalIntentionsPass = */ false, + /* inPostHighlightingPass = */ false ) } } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt index 4d23a1b3a87..7c859256a10 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt @@ -58,6 +58,8 @@ inline fun invokeLater(expired: Condition<*>, crossinline action: () -> Unit) = inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUnitTestMode +inline fun isApplicationInternalMode(): Boolean = ApplicationManager.getApplication().isInternal + inline fun ComponentManager.getServiceSafe(): T = this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}") diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt index e89114cbcb2..6faae1309a9 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -5,15 +5,17 @@ package org.jetbrains.kotlin.idea.perf +import com.intellij.codeHighlighting.* import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.testFramework.RunAll import com.intellij.util.ThrowableRunnable import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure import org.jetbrains.kotlin.idea.perf.util.Metric @@ -22,6 +24,7 @@ import org.jetbrains.kotlin.idea.testFramework.Fixture import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT +import org.jetbrains.kotlin.psi.KtFile import java.util.concurrent.atomic.AtomicLong import kotlin.test.assertNotEquals @@ -38,6 +41,9 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { @JvmStatic val timer: AtomicLong = AtomicLong() + @JvmStatic + val diagnosticTimer: AtomicLong = AtomicLong() + fun resetTimestamp() { timer.set(0) } @@ -326,6 +332,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { val testName = "fileAnalysis ${notePrefix(note)}${simpleFilename(fileName)}" val extraStats = Stats("${stats.name} $testName") val extraTimingsNs = mutableListOf?>() + val diagnosticTimingsNs = mutableListOf?>() val warmUpIterations = 30 val iterations = 50 @@ -337,7 +344,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { iterations(iterations) setUp(perfKtsFileAnalysisSetUp(project, fileName)) test(perfKtsFileAnalysisTest()) - tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, project)) + tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, diagnosticTimingsNs, project)) profilerConfig.enabled = true } @@ -349,19 +356,31 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { metricChildren ) + extraStats.printWarmUpTimings( + "diagnostic", + diagnosticTimingsNs.take(warmUpIterations).toTypedArray(), + metricChildren + ) + extraStats.processTimings( "annotator", extraTimingsNs.drop(warmUpIterations).toTypedArray(), metricChildren ) + + extraStats.processTimings( + "diagnostic", + diagnosticTimingsNs.drop(warmUpIterations).toTypedArray(), + metricChildren + ) } } private fun replaceWithCustomHighlighter() { org.jetbrains.kotlin.idea.testFramework.replaceWithCustomHighlighter( testRootDisposable, - KotlinPsiCheckerAndHighlightingUpdater::class.java.name, - TestKotlinPsiChecker::class.java.name + KotlinHighlightingPass.Registrar::class.java.name, + TestKotlinHighlightingPass.Registrar::class.java.name ) } @@ -385,18 +404,22 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { fun perfKtsFileAnalysisTest(): (TestData>>) -> Unit { return { it.value = it.setUpValue?.let { fixture -> - Pair(System.nanoTime(), fixture.doHighlighting()) + val nowNs = System.nanoTime() + diagnosticTimer.set(-nowNs) + Pair(nowNs, fixture.doHighlighting()) } } } fun perfKtsFileAnalysisTearDown( extraTimingsNs: MutableList?>, + diagnosticTimingsMs: MutableList?>, project: Project ): (TestData>>) -> Unit { return { it.setUpValue?.let { fixture -> it.value?.let { v -> + diagnosticTimingsMs.add(mapOf(TEST_KEY to diagnosticTimer.getAndSet(0))) assertTrue(v.second.isNotEmpty()) assertNotEquals(0, timer.get()) @@ -411,12 +434,38 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { } - class TestKotlinPsiChecker : KotlinPsiChecker() { - override fun annotate( - element: PsiElement, holder: AnnotationHolder - ) { - super.annotate(element, holder) - markTimestamp() + class TestKotlinHighlightingPass(file: KtFile, document: Document) : KotlinHighlightingPass(file, document) { + override fun doCollectInformation(progress: ProgressIndicator) { + annotationCallback { + val nowNs = System.nanoTime() + diagnosticTimer.addAndGet(nowNs) + resetAnnotationCallback() + } + try { + super.doCollectInformation(progress) + } finally { + resetAnnotationCallback() + markTimestamp() + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return TestKotlinHighlightingPass(file, editor.document) + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + null, + intArrayOf(Pass.UPDATE_ALL), + false, + -1 + ) + } } } } \ No newline at end of file diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml index 981f882d453..8f7e0dbe79c 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml +++ b/idea/resources-descriptors/META-INF/plugin.xml @@ -123,6 +123,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.201 b/idea/resources-descriptors/META-INF/plugin.xml.201 index 8f5c88df3b5..47bfa2fd0ef 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.201 +++ b/idea/resources-descriptors/META-INF/plugin.xml.201 @@ -123,6 +123,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as41 b/idea/resources-descriptors/META-INF/plugin.xml.as41 index a70a1c3b054..285aa3ca3f6 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as41 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as41 @@ -122,6 +122,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as42 b/idea/resources-descriptors/META-INF/plugin.xml.as42 index 1a2237b7f41..a7cce72296f 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as42 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as42 @@ -103,6 +103,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index e802ce65eb8..89ffc2af605 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -491,13 +491,8 @@ - - - - - diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt new file mode 100644 index 00000000000..30920e08a2e --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt @@ -0,0 +1,45 @@ +/* + * 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.codeHighlighting.* +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection +import org.jetbrains.kotlin.idea.isMainFunction +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter + +open class KotlinHighlightingPass(file: KtFile, document: Document) : AbstractKotlinHighlightingPass(file, document) { + + override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean { + val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false + if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false + return !grandParent.isMainFunction() + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return KotlinHighlightingPass(file, editor.document) + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ null, + /* runAfterStartingOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runIntentionsPassAfter = */false, + /* forcedPassId = */-1 + ) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt deleted file mode 100644 index 9a01b9dec6d..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.highlighter - -import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection -import org.jetbrains.kotlin.idea.isMainFunction -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtParameter - -class KotlinPsiCheckerAndHighlightingUpdater : KotlinPsiChecker() { - override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean { - val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false - if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false - return !grandParent.isMainFunction() - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt index 60cb787374c..31388e0274b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass import org.jetbrains.kotlin.idea.quickfix.CleanupFix import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix @@ -99,7 +99,7 @@ class KotlinCleanupInspection : LocalInspectionTool(), CleanupLocalInspectionToo } private fun Diagnostic.toCleanupFixes(): Collection { - return KotlinPsiChecker.createQuickFixes(this).filterIsInstance() + return AbstractKotlinHighlightingPass.createQuickFixes(this).filterIsInstance() } private class Wrapper(val intention: IntentionAction, file: KtFile) : IntentionWrapper(intention, file) { diff --git a/idea/testData/checker/AnnotationSupressing.kt b/idea/testData/checker/AnnotationSupressing.kt new file mode 100644 index 00000000000..7fe305fc5b1 --- /dev/null +++ b/idea/testData/checker/AnnotationSupressing.kt @@ -0,0 +1,32 @@ +annotation class A(val i: Int) +annotation class Z(val i: Int) + +@Z("BAD") @Suppress("TYPE_MISMATCH") +fun some0() {} + +@Z("BAD") @Z("BAD") @Suppress("TYPE_MISMATCH") +fun some01() {} + +@Suppress("TYPE_MISMATCH") @Z("BAD") +fun some1() { +} + +@Suppress("TYPE_MISMATCH") @Z("BAD") @Z("BAD") +fun some11() { +} + +@A("BAD") @Suppress("TYPE_MISMATCH") +fun some2() { +} + +@Suppress("TYPE_MISMATCH") @A("BAD") +fun some3() { +} + +@A("BAD") @A("BAD") +fun some4() { +} + +@Z("BAD") +fun someN() { +} diff --git a/idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java similarity index 97% rename from idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java rename to idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java index 98a416691c4..db8320d1f16 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java @@ -25,7 +25,7 @@ import java.io.File; import static org.jetbrains.kotlin.resolve.lazy.ResolveSession.areDescriptorsCreatedForDeclaration; -public abstract class AbstractPsiCheckerTest extends KotlinLightCodeInsightFixtureTestCase { +public abstract class AbstractKotlinHighlightingPassTest extends KotlinLightCodeInsightFixtureTestCase { public void doTest(@NotNull VirtualFile file) throws Exception { myFixture.configureFromExistingVirtualFile(file); checkHighlighting(true, false, false); diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt similarity index 94% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt index 457a1a7e436..406d3eef8a2 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt @@ -13,7 +13,7 @@ import org.junit.runner.RunWith @TestMetadata("idea/testData/checker/custom") @RunWith(JUnit3WithIdeaConfigurationRunner::class) -class PsiCheckerCustomTest : AbstractPsiCheckerTest() { +class KotlinHighlightingPassCustomTest : AbstractKotlinHighlightingPassTest() { @TestMetadata("noUnusedParameterWhenCustom.kt") fun testNoUnusedParameterWhenCustom() { diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt similarity index 92% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt index 594fda3e8a1..e4e1c1474ba 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt @@ -12,7 +12,7 @@ import org.junit.runner.RunWith @TestMetadata("idea/testData/checker/sealed") @RunWith(JUnit3WithIdeaConfigurationRunner::class) -class PsiCheckerSealedTest : AbstractPsiCheckerTest() { +class KotlinHighlightingPassSealedTest : AbstractKotlinHighlightingPassTest() { fun testOutsideOfPackageInheritors() { doTest( diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java similarity index 97% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java index e8a89d8269f..94c1d65a404 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java @@ -18,11 +18,11 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @RunWith(JUnit3RunnerWithInners.class) -public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { +public class KotlinHighlightingPassTestGenerated extends AbstractKotlinHighlightingPassTest { @TestMetadata("idea/testData/checker") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Checker extends AbstractPsiCheckerTest { + public static class Checker extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -41,6 +41,11 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { runTest("idea/testData/checker/AnnotationOnFile.kt"); } + @TestMetadata("AnnotationSupressing.kt") + public void testAnnotationSupressing() throws Exception { + runTest("idea/testData/checker/AnnotationSupressing.kt"); + } + @TestMetadata("AnonymousInitializers.kt") public void testAnonymousInitializers() throws Exception { runTest("idea/testData/checker/AnonymousInitializers.kt"); @@ -365,7 +370,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/regression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Regression extends AbstractPsiCheckerTest { + public static class Regression extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -608,7 +613,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/recovery") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Recovery extends AbstractPsiCheckerTest { + public static class Recovery extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -636,7 +641,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/rendering") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Rendering extends AbstractPsiCheckerTest { + public static class Rendering extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -654,7 +659,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/scripts") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Scripts extends AbstractPsiCheckerTest { + public static class Scripts extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -687,7 +692,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DuplicateJvmSignature extends AbstractPsiCheckerTest { + public static class DuplicateJvmSignature extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -699,7 +704,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/fields") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Fields extends AbstractPsiCheckerTest { + public static class Fields extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -717,7 +722,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class FunctionAndProperty extends AbstractPsiCheckerTest { + public static class FunctionAndProperty extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -780,7 +785,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/traitImpl") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class TraitImpl extends AbstractPsiCheckerTest { + public static class TraitImpl extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -799,7 +804,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/infos") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Infos extends AbstractPsiCheckerTest { + public static class Infos extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTestWithInfos, this, testDataFilePath); } @@ -892,7 +897,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/diagnosticsMessage") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DiagnosticsMessage extends AbstractPsiCheckerTest { + public static class DiagnosticsMessage extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt index 7721f7cbd9f..a45c2615e46 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt @@ -5,12 +5,12 @@ package org.jetbrains.kotlin.idea.debugger.evaluate -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.psi.KtCodeFragment import kotlin.test.assertNull -abstract class AbstractCodeFragmentAutoImportTest : AbstractPsiCheckerTest() { +abstract class AbstractCodeFragmentAutoImportTest : AbstractKotlinHighlightingPassTest() { override fun doTest(filePath: String) { myFixture.configureByCodeFragment(filePath) myFixture.doHighlighting() diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt index ba2ab37af90..415632d0415 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.debugger.evaluate import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.openapi.util.io.FileUtil -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.application.executeWriteCommand @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.InTextDirectivesUtils import java.io.File -abstract class AbstractCodeFragmentHighlightingTest : AbstractPsiCheckerTest() { +abstract class AbstractCodeFragmentHighlightingTest : AbstractKotlinHighlightingPassTest() { override fun doTest(filePath: String) { myFixture.configureByCodeFragment(filePath) checkHighlighting(filePath) diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt index 1b3af009ab6..0487de53f2d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt @@ -34,10 +34,12 @@ abstract class AbstractDslHighlighterTest : KotlinLightCodeInsightFixtureTestCas val styleIdByCall = extension.highlightCall(element, call)?.externalName if (styleIdByCall != null && styleIdByCall == styleIdByComment) { val annotationHolder = AnnotationHolderImpl(AnnotationSession(psiFile)) - val checkers = KotlinPsiChecker.getAfterAnalysisVisitor(annotationHolder, bindingContext) - checkers.forEach { call.call.callElement.accept(it) } + annotationHolder.runAnnotatorWithContext(file) { _, _ -> + val checkers = AbstractKotlinHighlightingPass.getAfterAnalysisVisitor(annotationHolder, bindingContext) + checkers.forEach { call.call.callElement.accept(it) } + } assertTrue( - "KotlinPsiChecker did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", + "KotlinHighlightingPass did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", annotationHolder.any { it.textAttributes.externalName == styleIdByComment } diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt index ab1d14fd2c7..72eab58ba76 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.idea.inspections import com.google.common.collect.Lists import com.intellij.codeHighlighting.HighlightDisplayLevel import com.intellij.codeHighlighting.Pass +import com.intellij.codeHighlighting.TextEditorHighlightingPass import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.codeInsight.daemon.impl.TextEditorHighlightingPassRegistrarEx import com.intellij.codeInsight.intention.EmptyIntentionAction import com.intellij.codeInspection.ProblemHighlightType import com.intellij.openapi.util.SystemInfo @@ -19,6 +21,7 @@ import junit.framework.ComparisonFailure import junit.framework.TestCase import org.jdom.Element import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.highlighter.AbstractHighlightingPassBase import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.withCustomCompilerOptions @@ -29,6 +32,7 @@ import org.jetbrains.kotlin.test.KotlinTestUtils import org.junit.Assert import java.io.File + abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCase() { private val inspectionFileName: String get() = ".inspection" @@ -145,16 +149,23 @@ abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCa state.tool.tool.readSettings(inspectionSettings) } + val passIdsToIgnore = mutableListOf( + Pass.LINE_MARKERS, + Pass.EXTERNAL_TOOLS, + Pass.POPUP_HINTS, + Pass.UPDATE_ALL, + Pass.UPDATE_FOLDING, + Pass.WOLF + ) + val passRegistrar = TextEditorHighlightingPassRegistrarEx.getInstanceEx(myFixture.project) + // to exclude AbstractHighlightingPassBase instances based on their ids + passRegistrar.instantiatePasses( + file, editor, passIdsToIgnore.toIntArray() + ).filterIsInstance().map(TextEditorHighlightingPass::getId).forEach(passIdsToIgnore::add) + val caretOffset = myFixture.caretOffset val highlightInfos = CodeInsightTestFixtureImpl.instantiateAndRun( - file, editor, intArrayOf( - Pass.LINE_MARKERS, - Pass.EXTERNAL_TOOLS, - Pass.POPUP_HINTS, - Pass.UPDATE_ALL, - Pass.UPDATE_FOLDING, - Pass.WOLF - ), (file as? KtFile)?.isScript() == true + file, editor, passIdsToIgnore.toIntArray(), (file as? KtFile)?.isScript() == true ).filter { it.description != null && caretOffset in it.startOffset..it.endOffset } Assert.assertTrue( diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt index d88f705b2ed..cc5cca8bcf3 100644 --- a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt @@ -5,11 +5,9 @@ package org.jetbrains.kotlin.pacelize.ide.test -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest -import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil -import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest -abstract class AbstractParcelizeCheckerTest : AbstractPsiCheckerTest() { +abstract class AbstractParcelizeCheckerTest : AbstractKotlinHighlightingPassTest() { override fun setUp() { super.setUp() addParcelizeLibraries(module) diff --git a/tests/mute-common.csv b/tests/mute-common.csv index fa22ea62e40..edb53357168 100644 --- a/tests/mute-common.csv +++ b/tests/mute-common.csv @@ -79,7 +79,7 @@ org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.Facades.test org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testActualTypeAliasCustomJvmPackageName, Invalid behavior of old lightclasses in common tests,, org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testJvmPackageName, Invalid behavior of old lightclasses in common tests,, org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testReceiverFun, Analysing of facade annotation with receiver site is broken (connected with KT-40403),, -org.jetbrains.kotlin.checkers.FirPsiCheckerTestGenerated.Regression.testJet53,,, FLAKY +org.jetbrains.kotlin.checkers.FirKotlinHighlightingPassTestGenerated.Regression.testJet53,,, FLAKY org.jetbrains.kotlin.idea.caches.resolve.MultiModuleHighlightingTest.testLanguageVersionsViaFacets,,, FLAKY org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.Jvm.testCircular, Temporary muted due to problems with IC and JVM IR backend,, org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.Jvm.testCircularDependencyClasses, Temporary muted due to problems with IC and JVM IR backend,,