Unbind general FirDiagnostic from PsiFile & PsiElement

This commit is contained in:
Mikhail Glukhikh
2020-11-19 11:45:34 +03:00
parent 68b748e164
commit 037c505069
24 changed files with 287 additions and 282 deletions
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
@@ -154,16 +153,16 @@ class AnalyzerWithCompilerReport(
return diagnostic.severity == Severity.ERROR return diagnostic.severity == Severity.ERROR
} }
fun reportDiagnostics(unsortedDiagnostics: Diagnostics, reporter: DiagnosticMessageReporter): Boolean { fun reportDiagnostics(unsortedDiagnostics: GenericDiagnostics<*>, reporter: DiagnosticMessageReporter): Boolean {
var hasErrors = false var hasErrors = false
val diagnostics = sortedDiagnostics(unsortedDiagnostics.all()) val diagnostics = sortedDiagnostics(unsortedDiagnostics.all().filterIsInstance<Diagnostic>())
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
hasErrors = hasErrors or reportDiagnostic(diagnostic, reporter) hasErrors = hasErrors or reportDiagnostic(diagnostic, reporter)
} }
return hasErrors return hasErrors
} }
fun reportDiagnostics(diagnostics: Diagnostics, messageCollector: MessageCollector): Boolean { fun reportDiagnostics(diagnostics: GenericDiagnostics<*>, messageCollector: MessageCollector): Boolean {
val hasErrors = reportDiagnostics(diagnostics, DefaultDiagnosticReporter(messageCollector)) val hasErrors = reportDiagnostics(diagnostics, DefaultDiagnosticReporter(messageCollector))
if (diagnostics.any { it.factory == Errors.INCOMPATIBLE_CLASS }) { if (diagnostics.any { it.factory == Errors.INCOMPATIBLE_CLASS }) {
@@ -28,9 +28,9 @@ class DefaultDiagnosticReporter(override val messageCollector: MessageCollector)
interface MessageCollectorBasedReporter : DiagnosticMessageReporter { interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) = messageCollector.report( override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity), AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render, render,
MessageUtil.psiFileToMessageLocation(file!!, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic)) MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
) )
} }
@@ -28,9 +28,9 @@ class DefaultDiagnosticReporter(override val messageCollector: MessageCollector)
interface MessageCollectorBasedReporter : DiagnosticMessageReporter { interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) = messageCollector.report( override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity), AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render, render,
MessageUtil.psiFileToMessageLocation(file!!, file.name, DiagnosticUtils.getLineAndColumn(diagnostic)) MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
) )
} }
@@ -20,5 +20,5 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
interface DiagnosticMessageReporter { interface DiagnosticMessageReporter {
fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) fun report(diagnostic: Diagnostic, file: PsiFile, render: String)
} }
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.* import com.intellij.openapi.vfs.*
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementFinder import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.DelegatingGlobalSearchScope
@@ -54,9 +53,7 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.* import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirMetadataSerializer import org.jetbrains.kotlin.fir.backend.jvm.FirMetadataSerializer
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
@@ -72,7 +69,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CompilerEnvironment import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.resolve.diagnostics.SimpleDiagnostics import org.jetbrains.kotlin.resolve.diagnostics.SimpleGenericDiagnostics
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
@@ -343,7 +340,7 @@ object KotlinToJVMBytecodeCompiler {
firAnalyzerFacade.runResolution() firAnalyzerFacade.runResolution()
val firDiagnostics = firAnalyzerFacade.runCheckers().values.flatten() val firDiagnostics = firAnalyzerFacade.runCheckers().values.flatten()
AnalyzerWithCompilerReport.reportDiagnostics( AnalyzerWithCompilerReport.reportDiagnostics(
SimpleDiagnostics(firDiagnostics), SimpleGenericDiagnostics(firDiagnostics),
environment.messageCollector environment.messageCollector
) )
performanceManager?.notifyAnalysisFinished() performanceManager?.notifyAnalysisFinished()
@@ -10,13 +10,14 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic
import org.jetbrains.kotlin.fir.FirLightSourceElement import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
// ------------------------------ diagnostics ------------------------------ // ------------------------------ diagnostics ------------------------------
sealed class FirDiagnostic<out E : FirSourceElement> : Diagnostic { sealed class FirDiagnostic<out E : FirSourceElement> : UnboundDiagnostic {
abstract val element: E abstract val element: E
abstract override val severity: Severity abstract override val severity: Severity
abstract override val factory: AbstractFirDiagnosticFactory<*, *> abstract override val factory: AbstractFirDiagnosticFactory<*, *>
@@ -94,16 +95,8 @@ data class FirPsiDiagnosticWithParameters3<P : PsiElement, A : Any, B : Any, C :
// ------------------------------ light tree diagnostics ------------------------------ // ------------------------------ light tree diagnostics ------------------------------
interface FirLightDiagnostic : Diagnostic { interface FirLightDiagnostic : UnboundDiagnostic {
val element: FirLightSourceElement val element: FirLightSourceElement
override val psiElement: PsiElement
get() {
throw UnsupportedOperationException("Light diagnostic does not hold PSI element")
}
override val psiFile: PsiFile?
get() = null
} }
data class FirLightSimpleDiagnostic( data class FirLightSimpleDiagnostic(
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.diagnostics
interface GenericDiagnostics<T : UnboundDiagnostic> : Iterable<T> {
fun all(): Collection<T>
fun isEmpty(): Boolean = all().isEmpty()
override fun iterator(): Iterator<T> = all().iterator()
}
@@ -20,7 +20,7 @@ class ActualDiagnostic constructor(val diagnostic: Diagnostic, override val plat
get() = diagnostic.factory.name!! get() = diagnostic.factory.name!!
val file: PsiFile val file: PsiFile
get() = diagnostic.psiFile!! get() = diagnostic.psiFile
override fun compareTo(other: AbstractTestDiagnostic): Int { override fun compareTo(other: AbstractTestDiagnostic): Int {
return if (this.diagnostic is DiagnosticWithParameters1<*, *> && other is ActualDiagnostic && other.diagnostic is DiagnosticWithParameters1<*, *>) { return if (this.diagnostic is DiagnosticWithParameters1<*, *> && other is ActualDiagnostic && other.diagnostic is DiagnosticWithParameters1<*, *>) {
@@ -2,222 +2,216 @@
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2018 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. * 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.checkers.utils
package org.jetbrains.kotlin.checkers.utils; import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import java.util.HashMap
import com.intellij.psi.PsiElement; object DebugInfoUtil {
import com.intellij.psi.tree.IElementType; private val MAY_BE_UNRESOLVED = TokenSet.create(KtTokens.IN_KEYWORD, KtTokens.NOT_IN)
import com.intellij.psi.tree.TokenSet; private val EXCLUDED = TokenSet.create(
import com.intellij.psi.util.PsiTreeUtil; KtTokens.COLON,
import org.jetbrains.annotations.NotNull; KtTokens.AS_KEYWORD,
import org.jetbrains.kotlin.KtNodeTypes; KtTokens.`AS_SAFE`,
import org.jetbrains.kotlin.descriptors.CallableDescriptor; KtTokens.IS_KEYWORD,
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; KtTokens.NOT_IS,
import org.jetbrains.kotlin.descriptors.PropertyDescriptor; KtTokens.OROR,
import org.jetbrains.kotlin.descriptors.VariableDescriptor; KtTokens.ANDAND,
import org.jetbrains.kotlin.diagnostics.Diagnostic; KtTokens.EQ,
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; KtTokens.EQEQEQ,
import org.jetbrains.kotlin.diagnostics.Errors; KtTokens.EXCLEQEQEQ,
import org.jetbrains.kotlin.lexer.KtTokens; KtTokens.ELVIS,
import org.jetbrains.kotlin.psi.*; KtTokens.EXCLEXCL
import org.jetbrains.kotlin.resolve.BindingContext; )
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collection; fun markDebugAnnotations(
import java.util.HashMap; root: PsiElement,
import java.util.Map; bindingContext: BindingContext,
debugInfoReporter: DebugInfoReporter
import static org.jetbrains.kotlin.lexer.KtTokens.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
public class DebugInfoUtil {
private static final TokenSet MAY_BE_UNRESOLVED = TokenSet.create(IN_KEYWORD, NOT_IN);
private static final TokenSet EXCLUDED = TokenSet.create(
COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL);
public abstract static class DebugInfoReporter {
public void preProcessReference(@NotNull KtReferenceExpression expression) {
// do nothing
}
public abstract void reportElementWithErrorType(@NotNull KtReferenceExpression expression);
public abstract void reportMissingUnresolved(@NotNull KtReferenceExpression expression);
public abstract void reportUnresolvedWithTarget(@NotNull KtReferenceExpression expression, @NotNull String target);
public void reportDynamicCall(@NotNull KtElement element, DeclarationDescriptor declarationDescriptor) { }
}
public static void markDebugAnnotations(
@NotNull PsiElement root,
@NotNull BindingContext bindingContext,
@NotNull DebugInfoReporter debugInfoReporter
) { ) {
Map<KtReferenceExpression, DiagnosticFactory<?>> markedWithErrorElements = new HashMap<>(); val markedWithErrorElements: MutableMap<KtReferenceExpression, DiagnosticFactory<*>?> = HashMap()
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { for (diagnostic in bindingContext.diagnostics) {
DiagnosticFactory<?> factory = diagnostic.getFactory(); val factory = diagnostic.factory
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) { if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.factory)) {
markedWithErrorElements.put((KtReferenceExpression) diagnostic.getPsiElement(), factory); markedWithErrorElements[diagnostic.psiElement as KtReferenceExpression] = factory
} } else if (factory === Errors.SUPER_IS_NOT_AN_EXPRESSION
else if (factory == Errors.SUPER_IS_NOT_AN_EXPRESSION || factory === Errors.SUPER_NOT_AVAILABLE
|| factory == Errors.SUPER_NOT_AVAILABLE) { ) {
KtSuperExpression superExpression = (KtSuperExpression) diagnostic.getPsiElement(); val superExpression = diagnostic.psiElement as KtSuperExpression
markedWithErrorElements.put(superExpression.getInstanceReference(), factory); markedWithErrorElements[superExpression.instanceReference] = factory
} } else if (factory === Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
else if (factory == Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) { markedWithErrorElements[diagnostic.psiElement as KtSimpleNameExpression] = factory
markedWithErrorElements.put((KtSimpleNameExpression) diagnostic.getPsiElement(), factory); } else if (factory === Errors.UNSUPPORTED) {
} for (reference in PsiTreeUtil.findChildrenOfType(
else if (factory == Errors.UNSUPPORTED) { diagnostic.psiElement,
for (KtReferenceExpression reference : PsiTreeUtil.findChildrenOfType(diagnostic.getPsiElement(), KtReferenceExpression::class.java
KtReferenceExpression.class)) { )) {
markedWithErrorElements.put(reference, factory); markedWithErrorElements[reference] = factory
} }
} }
} }
root.acceptChildren(object : KtTreeVisitorVoid() {
root.acceptChildren(new KtTreeVisitorVoid() { override fun visitForExpression(expression: KtForExpression) {
val range = expression.loopRange
@Override if (range != null) {
public void visitForExpression(@NotNull KtForExpression expression) { reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL)
KtExpression range = expression.getLoopRange(); reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL)
reportIfDynamicCall(range, range, LOOP_RANGE_ITERATOR_RESOLVED_CALL); reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL)
reportIfDynamicCall(range, range, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL);
reportIfDynamicCall(range, range, LOOP_RANGE_NEXT_RESOLVED_CALL);
super.visitForExpression(expression);
}
@Override
public void visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration destructuringDeclaration) {
for (KtDestructuringDeclarationEntry entry : destructuringDeclaration.getEntries()) {
reportIfDynamicCall(entry, entry, COMPONENT_RESOLVED_CALL);
} }
super.visitDestructuringDeclaration(destructuringDeclaration); super.visitForExpression(expression)
} }
@Override override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
public void visitProperty(@NotNull KtProperty property) { for (entry in destructuringDeclaration.entries) {
VariableDescriptor descriptor = bindingContext.get(VARIABLE, property); reportIfDynamicCall(entry, entry, BindingContext.COMPONENT_RESOLVED_CALL)
if (descriptor instanceof PropertyDescriptor && property.getDelegate() != null) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
reportIfDynamicCall(property.getDelegate(), propertyDescriptor, PROVIDE_DELEGATE_RESOLVED_CALL);
reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getGetter(), DELEGATED_PROPERTY_RESOLVED_CALL);
reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getSetter(), DELEGATED_PROPERTY_RESOLVED_CALL);
} }
super.visitProperty(property); super.visitDestructuringDeclaration(destructuringDeclaration)
} }
@Override override fun visitProperty(property: KtProperty) {
public void visitThisExpression(@NotNull KtThisExpression expression) { val descriptor = bindingContext.get(BindingContext.VARIABLE, property)
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext); val delegate = property.delegate
if (descriptor is PropertyDescriptor && delegate != null) {
reportIfDynamicCall(delegate, descriptor, BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL)
reportIfDynamicCall(delegate, descriptor.getter, BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL)
reportIfDynamicCall(delegate, descriptor.setter, BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL)
}
super.visitProperty(property)
}
override fun visitThisExpression(expression: KtThisExpression) {
val resolvedCall = expression.getResolvedCall(bindingContext)
if (resolvedCall != null) { if (resolvedCall != null) {
reportIfDynamic(expression, resolvedCall.getResultingDescriptor(), debugInfoReporter); reportIfDynamic(expression, resolvedCall.resultingDescriptor, debugInfoReporter)
} }
super.visitThisExpression(expression); super.visitThisExpression(expression)
} }
@Override override fun visitReferenceExpression(expression: KtReferenceExpression) {
public void visitReferenceExpression(@NotNull KtReferenceExpression expression) { super.visitReferenceExpression(expression)
super.visitReferenceExpression(expression); if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)) {
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){ return
return;
} }
IElementType referencedNameElementType = null; var referencedNameElementType: IElementType? = null
if (expression instanceof KtSimpleNameExpression) { if (expression is KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) expression; val elementType = expression.getNode().elementType
IElementType elementType = expression.getNode().getElementType(); if (elementType === KtNodeTypes.OPERATION_REFERENCE) {
if (elementType == KtNodeTypes.OPERATION_REFERENCE) { referencedNameElementType = expression.getReferencedNameElementType()
referencedNameElementType = nameExpression.getReferencedNameElementType();
if (EXCLUDED.contains(referencedNameElementType)) { if (EXCLUDED.contains(referencedNameElementType)) {
return; return
} }
} }
if (elementType == KtNodeTypes.LABEL || if (elementType === KtNodeTypes.LABEL ||
nameExpression.getReferencedNameElementType() == KtTokens.THIS_KEYWORD) { expression.getReferencedNameElementType() === KtTokens.THIS_KEYWORD
return; ) {
return
} }
} }
debugInfoReporter.preProcessReference(expression)
debugInfoReporter.preProcessReference(expression); var target: String? = null
val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression)
String target = null;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, expression);
if (declarationDescriptor != null) { if (declarationDescriptor != null) {
target = declarationDescriptor.toString(); target = declarationDescriptor.toString()
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter)
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter);
} }
if (target == null) { if (target == null) {
PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression); val labelTarget = bindingContext.get(BindingContext.LABEL_TARGET, expression)
if (labelTarget != null) { if (labelTarget != null) {
target = labelTarget.getText(); target = labelTarget.text
} }
} }
if (target == null) { if (target == null) {
Collection<? extends DeclarationDescriptor> declarationDescriptors = val declarationDescriptors = bindingContext.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression)
bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression);
if (declarationDescriptors != null) { if (declarationDescriptors != null) {
target = "[" + declarationDescriptors.size() + " descriptors]"; target = "[" + declarationDescriptors.size + " descriptors]"
} }
} }
if (target == null) { if (target == null) {
Collection<? extends PsiElement> labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, expression); val labelTargets = bindingContext.get(BindingContext.AMBIGUOUS_LABEL_TARGET, expression)
if (labelTargets != null) { if (labelTargets != null) {
target = "[" + labelTargets.size() + " elements]"; target = "[" + labelTargets.size + " elements]"
} }
} }
if (MAY_BE_UNRESOLVED.contains(referencedNameElementType)) { if (MAY_BE_UNRESOLVED.contains(referencedNameElementType)) {
return; return
} }
val resolved = target != null
boolean resolved = target != null; var markedWithError = markedWithErrorElements.containsKey(expression)
boolean markedWithError = markedWithErrorElements.containsKey(expression); if (expression is KtArrayAccessExpression &&
if (expression instanceof KtArrayAccessExpression && markedWithErrorElements.containsKey(expression.arrayExpression)
markedWithErrorElements.containsKey(((KtArrayAccessExpression) expression).getArrayExpression())) { ) {
// if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved') // if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved')
markedWithError = true; markedWithError = true
} }
KotlinType expressionType = bindingContext.getType(expression); val expressionType = bindingContext.getType(expression)
DiagnosticFactory<?> factory = markedWithErrorElements.get(expression); val factory = markedWithErrorElements[expression]
if (declarationDescriptor != null && if (declarationDescriptor != null &&
(ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) { (ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))
if (factory != Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) { ) {
debugInfoReporter.reportElementWithErrorType(expression); if (factory !== Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
debugInfoReporter.reportElementWithErrorType(expression)
} }
} }
if (resolved && markedWithError) { if (resolved && markedWithError) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) { if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) {
debugInfoReporter.reportUnresolvedWithTarget(expression, target); debugInfoReporter.reportUnresolvedWithTarget(expression, target!!)
} }
} } else if (!resolved && !markedWithError) {
else if (!resolved && !markedWithError) { debugInfoReporter.reportMissingUnresolved(expression)
debugInfoReporter.reportMissingUnresolved(expression);
} }
} }
private <E extends KtElement, K, D extends CallableDescriptor> boolean reportIfDynamicCall(E element, K key, WritableSlice<K, ResolvedCall<D>> slice) { private fun <E : KtElement, K, D : CallableDescriptor?> reportIfDynamicCall(
ResolvedCall<D> resolvedCall = bindingContext.get(slice, key); element: E,
if (resolvedCall != null) { key: K,
return reportIfDynamic(element, resolvedCall.getResultingDescriptor(), debugInfoReporter); slice: WritableSlice<K, ResolvedCall<D>>
} ): Boolean {
return false; val resolvedCall = bindingContext[slice, key]
return if (resolvedCall != null) {
reportIfDynamic(element, resolvedCall.resultingDescriptor, debugInfoReporter)
} else false
} }
}); })
} }
private static boolean reportIfDynamic(KtElement element, DeclarationDescriptor declarationDescriptor, DebugInfoReporter debugInfoReporter) { private fun reportIfDynamic(
if (declarationDescriptor != null && DynamicCallsKt.isDynamic(declarationDescriptor)) { element: KtElement,
debugInfoReporter.reportDynamicCall(element, declarationDescriptor); declarationDescriptor: DeclarationDescriptor?,
return true; debugInfoReporter: DebugInfoReporter
): Boolean {
if (declarationDescriptor != null && declarationDescriptor.isDynamic()) {
debugInfoReporter.reportDynamicCall(element, declarationDescriptor)
return true
} }
return false; return false
} }
}
abstract class DebugInfoReporter {
fun preProcessReference(expression: KtReferenceExpression) {
// do nothing
}
abstract fun reportElementWithErrorType(expression: KtReferenceExpression)
abstract fun reportMissingUnresolved(expression: KtReferenceExpression)
abstract fun reportUnresolvedWithTarget(expression: KtReferenceExpression, target: String)
open fun reportDynamicCall(element: KtElement, declarationDescriptor: DeclarationDescriptor) {}
}
}
@@ -20,5 +20,5 @@ import com.intellij.psi.PsiFile
interface Diagnostic : UnboundDiagnostic { interface Diagnostic : UnboundDiagnostic {
val psiElement: PsiElement val psiElement: PsiElement
val psiFile: PsiFile? val psiFile: PsiFile
} }
@@ -74,9 +74,6 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges(); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumn.NONE; if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumn.NONE;
TextRange firstRange = firstRange(textRanges); TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumn.NONE;
}
return getLineAndColumnInPsiFile(file, firstRange); return getLineAndColumnInPsiFile(file, firstRange);
} }
@@ -92,9 +89,6 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges(); List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumnRange.NONE; if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumnRange.NONE;
TextRange firstRange = firstRange(textRanges); TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumnRange.NONE;
}
return getLineAndColumnRangeInPsiFile(file, firstRange); return getLineAndColumnRangeInPsiFile(file, firstRange);
} }
@@ -131,11 +125,9 @@ public class DiagnosticUtils {
result.sort((d1, d2) -> { result.sort((d1, d2) -> {
PsiFile file1 = d1.getPsiFile(); PsiFile file1 = d1.getPsiFile();
PsiFile file2 = d2.getPsiFile(); PsiFile file2 = d2.getPsiFile();
if (file1 != null && file2 != null) { String path1 = file1.getViewProvider().getVirtualFile().getPath();
String path1 = file1.getViewProvider().getVirtualFile().getPath(); String path2 = file2.getViewProvider().getVirtualFile().getPath();
String path2 = file2.getViewProvider().getVirtualFile().getPath(); if (!path1.equals(path2)) return path1.compareTo(path2);
if (!path1.equals(path2)) return path1.compareTo(path2);
}
TextRange range1 = firstRange(d1.getTextRanges()); TextRange range1 = firstRange(d1.getTextRanges());
TextRange range2 = firstRange(d2.getTextRanges()); TextRange range2 = firstRange(d2.getTextRanges());
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.config.LanguageVersion;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic;
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement; import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement;
import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData; import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
import org.jetbrains.kotlin.types.KotlinTypeKt; import org.jetbrains.kotlin.types.KotlinTypeKt;
@@ -46,7 +47,7 @@ public class DefaultErrorMessages {
@NotNull @NotNull
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static String render(@NotNull Diagnostic diagnostic) { public static String render(@NotNull UnboundDiagnostic diagnostic) {
DiagnosticRenderer renderer = getRendererForDiagnostic(diagnostic); DiagnosticRenderer renderer = getRendererForDiagnostic(diagnostic);
if (renderer != null) { if (renderer != null) {
return renderer.render(diagnostic); return renderer.render(diagnostic);
@@ -55,7 +56,7 @@ public class DefaultErrorMessages {
} }
@Nullable @Nullable
public static DiagnosticRenderer getRendererForDiagnostic(@NotNull Diagnostic diagnostic) { public static DiagnosticRenderer getRendererForDiagnostic(@NotNull UnboundDiagnostic diagnostic) {
DiagnosticRenderer<?> renderer = AddToStdlibKt.firstNotNullResult(RENDERER_MAPS, map -> map.get(diagnostic.getFactory())); DiagnosticRenderer<?> renderer = AddToStdlibKt.firstNotNullResult(RENDERER_MAPS, map -> map.get(diagnostic.getFactory()));
if (renderer != null) if (renderer != null)
return renderer; return renderer;
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.diagnostics.*
import java.text.MessageFormat import java.text.MessageFormat
abstract class AbstractDiagnosticWithParametersRenderer<in D : Diagnostic> protected constructor(message: String) : DiagnosticRenderer<D> { abstract class AbstractDiagnosticWithParametersRenderer<in D : UnboundDiagnostic> protected constructor(message: String) : DiagnosticRenderer<D> {
private val messageFormat = MessageFormat(message) private val messageFormat = MessageFormat(message)
override fun render(diagnostic: D): String { override fun render(diagnostic: D): String {
@@ -13,81 +13,77 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.resolve
package org.jetbrains.kotlin.resolve; import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.psi.debugText.getDebugText
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import java.lang.IllegalArgumentException
import java.lang.StringBuilder
import java.util.ArrayList
import com.intellij.psi.PsiElement; object AnalyzingUtils {
import com.intellij.psi.PsiErrorElement; private const val WRITE_DEBUG_TRACE_NAMES = false
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid;
import org.jetbrains.kotlin.psi.debugText.DebugTextUtilKt;
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import java.util.ArrayList; @JvmStatic
import java.util.List; fun checkForSyntacticErrors(root: PsiElement) {
root.acceptChildren(object : PsiErrorElementVisitor() {
public class AnalyzingUtils { override fun visitErrorElement(element: PsiErrorElement) {
private static final boolean WRITE_DEBUG_TRACE_NAMES = false; throw IllegalArgumentException(
element.errorDescription + "; looking at " +
public abstract static class PsiErrorElementVisitor extends KtTreeVisitorVoid { element.node.elementType + " '" +
@Override element.text + PsiDiagnosticUtils.atLocation(element)
public abstract void visitErrorElement(@NotNull PsiErrorElement element); )
}
public static void checkForSyntacticErrors(@NotNull PsiElement root) {
root.acceptChildren(new PsiErrorElementVisitor() {
@Override
public void visitErrorElement(@NotNull PsiErrorElement element) {
throw new IllegalArgumentException(element.getErrorDescription() + "; looking at " +
element.getNode().getElementType() + " '" +
element.getText() + PsiDiagnosticUtils.atLocation(element));
} }
}); })
} }
public static List<PsiErrorElement> getSyntaxErrorRanges(@NotNull PsiElement root) { @JvmStatic
List<PsiErrorElement> r = new ArrayList<>(); fun getSyntaxErrorRanges(root: PsiElement): List<PsiErrorElement> {
root.acceptChildren(new PsiErrorElementVisitor() { val r: MutableList<PsiErrorElement> = ArrayList()
@Override root.acceptChildren(object : PsiErrorElementVisitor() {
public void visitErrorElement(@NotNull PsiErrorElement element) { override fun visitErrorElement(element: PsiErrorElement) {
r.add(element); r.add(element)
} }
}); })
return r; return r
} }
public static void throwExceptionOnErrors(BindingContext bindingContext) { fun throwExceptionOnErrors(bindingContext: BindingContext) {
throwExceptionOnErrors(bindingContext.getDiagnostics()); throwExceptionOnErrors(bindingContext.diagnostics)
} }
public static void throwExceptionOnErrors(Diagnostics diagnostics) { fun throwExceptionOnErrors(diagnostics: Diagnostics) {
for (Diagnostic diagnostic : diagnostics) { for (diagnostic in diagnostics) {
DiagnosticSink.THROW_EXCEPTION.report(diagnostic); DiagnosticSink.THROW_EXCEPTION.report(diagnostic)
} }
} }
// -------------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------------
public static String formDebugNameForBindingTrace(@NotNull String debugName, @Nullable Object resolutionSubjectForMessage) { @JvmStatic
fun formDebugNameForBindingTrace(debugName: String, resolutionSubjectForMessage: Any?): String {
if (WRITE_DEBUG_TRACE_NAMES) { if (WRITE_DEBUG_TRACE_NAMES) {
StringBuilder debugInfo = new StringBuilder(debugName); val debugInfo = StringBuilder(debugName)
if (resolutionSubjectForMessage instanceof KtElement) { if (resolutionSubjectForMessage is KtElement) {
KtElement element = (KtElement) resolutionSubjectForMessage; debugInfo.append(" ").append(resolutionSubjectForMessage.getDebugText())
debugInfo.append(" ").append(DebugTextUtilKt.getDebugText(element));
//debugInfo.append(" in ").append(element.getContainingFile().getName()); //debugInfo.append(" in ").append(element.getContainingFile().getName());
debugInfo.append(" in ").append(element.getContainingKtFile().getName()).append(" ").append(element.getTextOffset()); debugInfo.append(" in ").append(resolutionSubjectForMessage.containingKtFile.name).append(" ").append(
resolutionSubjectForMessage.textOffset
)
} else if (resolutionSubjectForMessage != null) {
debugInfo.append(" ").append(resolutionSubjectForMessage)
} }
else if (resolutionSubjectForMessage != null) { return debugInfo.toString()
debugInfo.append(" ").append(resolutionSubjectForMessage);
}
return debugInfo.toString();
} }
return ""
return "";
} }
}
abstract class PsiErrorElementVisitor : KtTreeVisitorVoid() {
abstract override fun visitErrorElement(element: PsiErrorElement)
}
}
@@ -17,25 +17,26 @@
package org.jetbrains.kotlin.resolve.diagnostics package org.jetbrains.kotlin.resolve.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.GenericDiagnostics
interface Diagnostics : Iterable<Diagnostic> { interface Diagnostics : GenericDiagnostics<Diagnostic> {
//should not be called on readonly views //should not be called on readonly views
//any Diagnostics object returned by BindingContext#getDiagnostics() should implement this property //any Diagnostics object returned by BindingContext#getDiagnostics() should implement this property
val modificationTracker: ModificationTracker val modificationTracker: ModificationTracker
get() = throw IllegalStateException("Trying to obtain modification tracker for Diagnostics object of class ${this::class.java}") get() = throw IllegalStateException("Trying to obtain modification tracker for Diagnostics object of class ${this::class.java}")
fun all(): Collection<Diagnostic> override fun all(): Collection<Diagnostic>
override fun isEmpty(): Boolean = all().isEmpty()
override fun iterator(): Iterator<Diagnostic> = all().iterator()
fun forElement(psiElement: PsiElement): Collection<Diagnostic> fun forElement(psiElement: PsiElement): Collection<Diagnostic>
fun isEmpty(): Boolean = all().isEmpty()
fun noSuppression(): Diagnostics fun noSuppression(): Diagnostics
override fun iterator() = all().iterator()
companion object { companion object {
val EMPTY: Diagnostics = object : Diagnostics { val EMPTY: Diagnostics = object : Diagnostics {
override fun noSuppression(): Diagnostics = this override fun noSuppression(): Diagnostics = this
@@ -16,21 +16,20 @@
package org.jetbrains.kotlin.resolve.diagnostics package org.jetbrains.kotlin.resolve.diagnostics
import com.intellij.openapi.util.Condition
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import java.util.ArrayList import java.util.ArrayList
class SimpleDiagnostics(diagnostics: Collection<Diagnostic>) : Diagnostics { class SimpleDiagnostics(diagnostics: Collection<Diagnostic>) : SimpleGenericDiagnostics<Diagnostic>(diagnostics), Diagnostics {
//copy to prevent external change //copy to prevent external change
private val diagnostics = ArrayList(diagnostics) private val diagnostics = ArrayList(diagnostics)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private val elementsCache = DiagnosticsElementsCache(this, { true }) private val elementsCache = DiagnosticsElementsCache(this) { true }
override fun all() = diagnostics override fun all() = diagnostics
override fun forElement(psiElement: PsiElement) = elementsCache.getDiagnostics(psiElement) override fun forElement(psiElement: PsiElement): MutableCollection<Diagnostic> = elementsCache.getDiagnostics(psiElement)
override fun noSuppression() = this override fun noSuppression() = this
} }
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.diagnostics
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic
import org.jetbrains.kotlin.diagnostics.GenericDiagnostics
import java.util.ArrayList
open class SimpleGenericDiagnostics<T : UnboundDiagnostic>(diagnostics: Collection<T>) : GenericDiagnostics<T> {
//copy to prevent external change
private val diagnostics = ArrayList(diagnostics)
override fun all() = diagnostics
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.checkers.diagnostics.TextDiagnostic
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.builder.RawFirBuilder
@@ -324,7 +325,7 @@ abstract class AbstractFirBaseDiagnosticsTest : BaseDiagnosticsTest() {
private fun Iterable<FirDiagnostic<*>>.toActualDiagnostic(root: PsiElement): List<ActualDiagnostic> { private fun Iterable<FirDiagnostic<*>>.toActualDiagnostic(root: PsiElement): List<ActualDiagnostic> {
val result = mutableListOf<ActualDiagnostic>() val result = mutableListOf<ActualDiagnostic>()
mapTo(result) { filterIsInstance<Diagnostic>().mapTo(result) {
ActualDiagnostic(it, null, true) ActualDiagnostic(it, null, true)
} }
for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) { for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) {
@@ -28,7 +28,7 @@ class DiagnosticTestTypeValidator(
private fun findTestCases(diagnostic: Diagnostic): TestCasesByNumbers { private fun findTestCases(diagnostic: Diagnostic): TestCasesByNumbers {
val ranges = diagnostic.textRanges val ranges = diagnostic.textRanges
val filename = diagnostic.psiFile!!.name val filename = diagnostic.psiFile.name
val foundTestCases = testInfo.cases.byRanges[filename]!!.floorEntry(ranges[0].startOffset) val foundTestCases = testInfo.cases.byRanges[filename]!!.floorEntry(ranges[0].startOffset)
if (foundTestCases != null) if (foundTestCases != null)
@@ -20,6 +20,7 @@ import com.intellij.icons.AllIcons;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic;
import org.jetbrains.kotlin.diagnostics.rendering.*; import org.jetbrains.kotlin.diagnostics.rendering.*;
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle; import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs; import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
@@ -42,7 +43,7 @@ public class IdeErrorMessages {
private static final DiagnosticFactoryToRendererMap MAP = new DiagnosticFactoryToRendererMap("IDE"); private static final DiagnosticFactoryToRendererMap MAP = new DiagnosticFactoryToRendererMap("IDE");
@NotNull @NotNull
public static String render(@NotNull Diagnostic diagnostic) { public static String render(@NotNull UnboundDiagnostic diagnostic) {
DiagnosticRenderer renderer = MAP.get(diagnostic.getFactory()); DiagnosticRenderer renderer = MAP.get(diagnostic.getFactory());
if (renderer != null) { if (renderer != null) {
@@ -54,7 +55,7 @@ public class IdeErrorMessages {
} }
@TestOnly @TestOnly
public static boolean hasIdeSpecificMessage(@NotNull Diagnostic diagnostic) { public static boolean hasIdeSpecificMessage(@NotNull UnboundDiagnostic diagnostic) {
return MAP.get(diagnostic.getFactory()) != null; return MAP.get(diagnostic.getFactory()) != null;
} }
@@ -261,7 +261,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
answer.append("// ================\n") answer.append("// ================\n")
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
answer.append("// Error at ") answer.append("// Error at ")
.append(diagnostic.psiFile?.name) .append(diagnostic.psiFile.name)
.append(join(diagnostic.textRanges, ",")) .append(join(diagnostic.textRanges, ","))
.append(": ") .append(": ")
.append(DefaultErrorMessages.render(diagnostic)) .append(DefaultErrorMessages.render(diagnostic))
@@ -128,7 +128,7 @@ class AddFunctionToSupertypeFix private constructor(
val descriptors = generateFunctionsToAdd(function) val descriptors = generateFunctionsToAdd(function)
if (descriptors.isEmpty()) return null if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile!!.project val project = diagnostic.psiFile.project
val functionData = descriptors.mapNotNull { createFunctionData(it, project) } val functionData = descriptors.mapNotNull { createFunctionData(it, project) }
if (functionData.isEmpty()) return null if (functionData.isEmpty()) return null
@@ -102,7 +102,7 @@ class AddPropertyToSupertypeFix private constructor(
val descriptors = generatePropertiesToAdd(property) val descriptors = generatePropertiesToAdd(property)
if (descriptors.isEmpty()) return null if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile!!.project val project = diagnostic.psiFile.project
val propertyData = descriptors.mapNotNull { createPropertyData(it, property.initializer, project) } val propertyData = descriptors.mapNotNull { createPropertyData(it, property.initializer, project) }
if (propertyData.isEmpty()) return null if (propertyData.isEmpty()) return null
@@ -15,7 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory
class IdeDiagnosticMessageHolder : DiagnosticMessageHolder { class IdeDiagnosticMessageHolder : DiagnosticMessageHolder {
private val diagnostics = arrayListOf<Pair<Diagnostic, String>>() private val diagnostics = arrayListOf<Pair<Diagnostic, String>>()
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) { override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) {
diagnostics.add(Pair(diagnostic, render)) diagnostics.add(Pair(diagnostic, render))
} }