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.DescriptorUtils
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.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
@@ -154,16 +153,16 @@ class AnalyzerWithCompilerReport(
return diagnostic.severity == Severity.ERROR
}
fun reportDiagnostics(unsortedDiagnostics: Diagnostics, reporter: DiagnosticMessageReporter): Boolean {
fun reportDiagnostics(unsortedDiagnostics: GenericDiagnostics<*>, reporter: DiagnosticMessageReporter): Boolean {
var hasErrors = false
val diagnostics = sortedDiagnostics(unsortedDiagnostics.all())
val diagnostics = sortedDiagnostics(unsortedDiagnostics.all().filterIsInstance<Diagnostic>())
for (diagnostic in diagnostics) {
hasErrors = hasErrors or reportDiagnostic(diagnostic, reporter)
}
return hasErrors
}
fun reportDiagnostics(diagnostics: Diagnostics, messageCollector: MessageCollector): Boolean {
fun reportDiagnostics(diagnostics: GenericDiagnostics<*>, messageCollector: MessageCollector): Boolean {
val hasErrors = reportDiagnostics(diagnostics, DefaultDiagnosticReporter(messageCollector))
if (diagnostics.any { it.factory == Errors.INCOMPATIBLE_CLASS }) {
@@ -28,9 +28,9 @@ class DefaultDiagnosticReporter(override val messageCollector: MessageCollector)
interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
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),
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 {
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),
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
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.vfs.*
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiJavaModule
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.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirPsiSourceElement
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.FirMetadataSerializer
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.psi.KtFile
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.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
@@ -343,7 +340,7 @@ object KotlinToJVMBytecodeCompiler {
firAnalyzerFacade.runResolution()
val firDiagnostics = firAnalyzerFacade.runCheckers().values.flatten()
AnalyzerWithCompilerReport.reportDiagnostics(
SimpleDiagnostics(firDiagnostics),
SimpleGenericDiagnostics(firDiagnostics),
environment.messageCollector
)
performanceManager?.notifyAnalysisFinished()
@@ -10,13 +10,14 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
// ------------------------------ diagnostics ------------------------------
sealed class FirDiagnostic<out E : FirSourceElement> : Diagnostic {
sealed class FirDiagnostic<out E : FirSourceElement> : UnboundDiagnostic {
abstract val element: E
abstract override val severity: Severity
abstract override val factory: AbstractFirDiagnosticFactory<*, *>
@@ -94,16 +95,8 @@ data class FirPsiDiagnosticWithParameters3<P : PsiElement, A : Any, B : Any, C :
// ------------------------------ light tree diagnostics ------------------------------
interface FirLightDiagnostic : Diagnostic {
interface FirLightDiagnostic : UnboundDiagnostic {
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(
@@ -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!!
val file: PsiFile
get() = diagnostic.psiFile!!
get() = diagnostic.psiFile
override fun compareTo(other: AbstractTestDiagnostic): Int {
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.
* 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;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
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.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
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.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;
object DebugInfoUtil {
private val MAY_BE_UNRESOLVED = TokenSet.create(KtTokens.IN_KEYWORD, KtTokens.NOT_IN)
private val EXCLUDED = TokenSet.create(
KtTokens.COLON,
KtTokens.AS_KEYWORD,
KtTokens.`AS_SAFE`,
KtTokens.IS_KEYWORD,
KtTokens.NOT_IS,
KtTokens.OROR,
KtTokens.ANDAND,
KtTokens.EQ,
KtTokens.EQEQEQ,
KtTokens.EXCLEQEQEQ,
KtTokens.ELVIS,
KtTokens.EXCLEXCL
)
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
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
fun markDebugAnnotations(
root: PsiElement,
bindingContext: BindingContext,
debugInfoReporter: DebugInfoReporter
) {
Map<KtReferenceExpression, DiagnosticFactory<?>> markedWithErrorElements = new HashMap<>();
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
DiagnosticFactory<?> factory = diagnostic.getFactory();
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
markedWithErrorElements.put((KtReferenceExpression) diagnostic.getPsiElement(), factory);
}
else if (factory == Errors.SUPER_IS_NOT_AN_EXPRESSION
|| factory == Errors.SUPER_NOT_AVAILABLE) {
KtSuperExpression superExpression = (KtSuperExpression) diagnostic.getPsiElement();
markedWithErrorElements.put(superExpression.getInstanceReference(), factory);
}
else if (factory == Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
markedWithErrorElements.put((KtSimpleNameExpression) diagnostic.getPsiElement(), factory);
}
else if (factory == Errors.UNSUPPORTED) {
for (KtReferenceExpression reference : PsiTreeUtil.findChildrenOfType(diagnostic.getPsiElement(),
KtReferenceExpression.class)) {
markedWithErrorElements.put(reference, factory);
val markedWithErrorElements: MutableMap<KtReferenceExpression, DiagnosticFactory<*>?> = HashMap()
for (diagnostic in bindingContext.diagnostics) {
val factory = diagnostic.factory
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.factory)) {
markedWithErrorElements[diagnostic.psiElement as KtReferenceExpression] = factory
} else if (factory === Errors.SUPER_IS_NOT_AN_EXPRESSION
|| factory === Errors.SUPER_NOT_AVAILABLE
) {
val superExpression = diagnostic.psiElement as KtSuperExpression
markedWithErrorElements[superExpression.instanceReference] = factory
} else if (factory === Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
markedWithErrorElements[diagnostic.psiElement as KtSimpleNameExpression] = factory
} else if (factory === Errors.UNSUPPORTED) {
for (reference in PsiTreeUtil.findChildrenOfType(
diagnostic.psiElement,
KtReferenceExpression::class.java
)) {
markedWithErrorElements[reference] = factory
}
}
}
root.acceptChildren(new KtTreeVisitorVoid() {
@Override
public void visitForExpression(@NotNull KtForExpression expression) {
KtExpression range = expression.getLoopRange();
reportIfDynamicCall(range, range, LOOP_RANGE_ITERATOR_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);
root.acceptChildren(object : KtTreeVisitorVoid() {
override fun visitForExpression(expression: KtForExpression) {
val range = expression.loopRange
if (range != null) {
reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL)
reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL)
reportIfDynamicCall(range, range, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL)
}
super.visitDestructuringDeclaration(destructuringDeclaration);
super.visitForExpression(expression)
}
@Override
public void visitProperty(@NotNull KtProperty property) {
VariableDescriptor descriptor = bindingContext.get(VARIABLE, property);
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);
override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
for (entry in destructuringDeclaration.entries) {
reportIfDynamicCall(entry, entry, BindingContext.COMPONENT_RESOLVED_CALL)
}
super.visitProperty(property);
super.visitDestructuringDeclaration(destructuringDeclaration)
}
@Override
public void visitThisExpression(@NotNull KtThisExpression expression) {
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
override fun visitProperty(property: KtProperty) {
val descriptor = bindingContext.get(BindingContext.VARIABLE, property)
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) {
reportIfDynamic(expression, resolvedCall.getResultingDescriptor(), debugInfoReporter);
reportIfDynamic(expression, resolvedCall.resultingDescriptor, debugInfoReporter)
}
super.visitThisExpression(expression);
super.visitThisExpression(expression)
}
@Override
public void visitReferenceExpression(@NotNull KtReferenceExpression expression) {
super.visitReferenceExpression(expression);
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
return;
override fun visitReferenceExpression(expression: KtReferenceExpression) {
super.visitReferenceExpression(expression)
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)) {
return
}
IElementType referencedNameElementType = null;
if (expression instanceof KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) expression;
IElementType elementType = expression.getNode().getElementType();
if (elementType == KtNodeTypes.OPERATION_REFERENCE) {
referencedNameElementType = nameExpression.getReferencedNameElementType();
var referencedNameElementType: IElementType? = null
if (expression is KtSimpleNameExpression) {
val elementType = expression.getNode().elementType
if (elementType === KtNodeTypes.OPERATION_REFERENCE) {
referencedNameElementType = expression.getReferencedNameElementType()
if (EXCLUDED.contains(referencedNameElementType)) {
return;
return
}
}
if (elementType == KtNodeTypes.LABEL ||
nameExpression.getReferencedNameElementType() == KtTokens.THIS_KEYWORD) {
return;
if (elementType === KtNodeTypes.LABEL ||
expression.getReferencedNameElementType() === KtTokens.THIS_KEYWORD
) {
return
}
}
debugInfoReporter.preProcessReference(expression);
String target = null;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, expression);
debugInfoReporter.preProcessReference(expression)
var target: String? = null
val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression)
if (declarationDescriptor != null) {
target = declarationDescriptor.toString();
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter);
target = declarationDescriptor.toString()
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter)
}
if (target == null) {
PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression);
val labelTarget = bindingContext.get(BindingContext.LABEL_TARGET, expression)
if (labelTarget != null) {
target = labelTarget.getText();
target = labelTarget.text
}
}
if (target == null) {
Collection<? extends DeclarationDescriptor> declarationDescriptors =
bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression);
val declarationDescriptors = bindingContext.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression)
if (declarationDescriptors != null) {
target = "[" + declarationDescriptors.size() + " descriptors]";
target = "[" + declarationDescriptors.size + " descriptors]"
}
}
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) {
target = "[" + labelTargets.size() + " elements]";
target = "[" + labelTargets.size + " elements]"
}
}
if (MAY_BE_UNRESOLVED.contains(referencedNameElementType)) {
return;
return
}
boolean resolved = target != null;
boolean markedWithError = markedWithErrorElements.containsKey(expression);
if (expression instanceof KtArrayAccessExpression &&
markedWithErrorElements.containsKey(((KtArrayAccessExpression) expression).getArrayExpression())) {
val resolved = target != null
var markedWithError = markedWithErrorElements.containsKey(expression)
if (expression is KtArrayAccessExpression &&
markedWithErrorElements.containsKey(expression.arrayExpression)
) {
// 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);
DiagnosticFactory<?> factory = markedWithErrorElements.get(expression);
val expressionType = bindingContext.getType(expression)
val factory = markedWithErrorElements[expression]
if (declarationDescriptor != null &&
(ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) {
if (factory != Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
debugInfoReporter.reportElementWithErrorType(expression);
(ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))
) {
if (factory !== Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
debugInfoReporter.reportElementWithErrorType(expression)
}
}
if (resolved && markedWithError) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) {
debugInfoReporter.reportUnresolvedWithTarget(expression, target);
debugInfoReporter.reportUnresolvedWithTarget(expression, target!!)
}
}
else if (!resolved && !markedWithError) {
debugInfoReporter.reportMissingUnresolved(expression);
} else if (!resolved && !markedWithError) {
debugInfoReporter.reportMissingUnresolved(expression)
}
}
private <E extends KtElement, K, D extends CallableDescriptor> boolean reportIfDynamicCall(E element, K key, WritableSlice<K, ResolvedCall<D>> slice) {
ResolvedCall<D> resolvedCall = bindingContext.get(slice, key);
if (resolvedCall != null) {
return reportIfDynamic(element, resolvedCall.getResultingDescriptor(), debugInfoReporter);
}
return false;
private fun <E : KtElement, K, D : CallableDescriptor?> reportIfDynamicCall(
element: E,
key: K,
slice: WritableSlice<K, ResolvedCall<D>>
): Boolean {
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) {
if (declarationDescriptor != null && DynamicCallsKt.isDynamic(declarationDescriptor)) {
debugInfoReporter.reportDynamicCall(element, declarationDescriptor);
return true;
private fun reportIfDynamic(
element: KtElement,
declarationDescriptor: DeclarationDescriptor?,
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 {
val psiElement: PsiElement
val psiFile: PsiFile?
val psiFile: PsiFile
}
@@ -74,9 +74,6 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumn.NONE;
TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumn.NONE;
}
return getLineAndColumnInPsiFile(file, firstRange);
}
@@ -92,9 +89,6 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumnRange.NONE;
TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumnRange.NONE;
}
return getLineAndColumnRangeInPsiFile(file, firstRange);
}
@@ -131,11 +125,9 @@ public class DiagnosticUtils {
result.sort((d1, d2) -> {
PsiFile file1 = d1.getPsiFile();
PsiFile file2 = d2.getPsiFile();
if (file1 != null && file2 != null) {
String path1 = file1.getViewProvider().getVirtualFile().getPath();
String path2 = file2.getViewProvider().getVirtualFile().getPath();
if (!path1.equals(path2)) return path1.compareTo(path2);
}
String path1 = file1.getViewProvider().getVirtualFile().getPath();
String path2 = file2.getViewProvider().getVirtualFile().getPath();
if (!path1.equals(path2)) return path1.compareTo(path2);
TextRange range1 = firstRange(d1.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.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic;
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement;
import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
import org.jetbrains.kotlin.types.KotlinTypeKt;
@@ -46,7 +47,7 @@ public class DefaultErrorMessages {
@NotNull
@SuppressWarnings("unchecked")
public static String render(@NotNull Diagnostic diagnostic) {
public static String render(@NotNull UnboundDiagnostic diagnostic) {
DiagnosticRenderer renderer = getRendererForDiagnostic(diagnostic);
if (renderer != null) {
return renderer.render(diagnostic);
@@ -55,7 +56,7 @@ public class DefaultErrorMessages {
}
@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()));
if (renderer != null)
return renderer;
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.diagnostics.*
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)
override fun render(diagnostic: D): String {
@@ -13,81 +13,77 @@
* See the License for the specific language governing permissions and
* 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;
import com.intellij.psi.PsiErrorElement;
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;
object AnalyzingUtils {
private const val WRITE_DEBUG_TRACE_NAMES = false
import java.util.ArrayList;
import java.util.List;
public class AnalyzingUtils {
private static final boolean WRITE_DEBUG_TRACE_NAMES = false;
public abstract static class PsiErrorElementVisitor extends KtTreeVisitorVoid {
@Override
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));
@JvmStatic
fun checkForSyntacticErrors(root: PsiElement) {
root.acceptChildren(object : PsiErrorElementVisitor() {
override fun visitErrorElement(element: PsiErrorElement) {
throw IllegalArgumentException(
element.errorDescription + "; looking at " +
element.node.elementType + " '" +
element.text + PsiDiagnosticUtils.atLocation(element)
)
}
});
})
}
public static List<PsiErrorElement> getSyntaxErrorRanges(@NotNull PsiElement root) {
List<PsiErrorElement> r = new ArrayList<>();
root.acceptChildren(new PsiErrorElementVisitor() {
@Override
public void visitErrorElement(@NotNull PsiErrorElement element) {
r.add(element);
@JvmStatic
fun getSyntaxErrorRanges(root: PsiElement): List<PsiErrorElement> {
val r: MutableList<PsiErrorElement> = ArrayList()
root.acceptChildren(object : PsiErrorElementVisitor() {
override fun visitErrorElement(element: PsiErrorElement) {
r.add(element)
}
});
return r;
})
return r
}
public static void throwExceptionOnErrors(BindingContext bindingContext) {
throwExceptionOnErrors(bindingContext.getDiagnostics());
fun throwExceptionOnErrors(bindingContext: BindingContext) {
throwExceptionOnErrors(bindingContext.diagnostics)
}
public static void throwExceptionOnErrors(Diagnostics diagnostics) {
for (Diagnostic diagnostic : diagnostics) {
DiagnosticSink.THROW_EXCEPTION.report(diagnostic);
fun throwExceptionOnErrors(diagnostics: Diagnostics) {
for (diagnostic in diagnostics) {
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) {
StringBuilder debugInfo = new StringBuilder(debugName);
if (resolutionSubjectForMessage instanceof KtElement) {
KtElement element = (KtElement) resolutionSubjectForMessage;
debugInfo.append(" ").append(DebugTextUtilKt.getDebugText(element));
val debugInfo = StringBuilder(debugName)
if (resolutionSubjectForMessage is KtElement) {
debugInfo.append(" ").append(resolutionSubjectForMessage.getDebugText())
//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) {
debugInfo.append(" ").append(resolutionSubjectForMessage);
}
return debugInfo.toString();
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
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
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
//any Diagnostics object returned by BindingContext#getDiagnostics() should implement this property
val modificationTracker: ModificationTracker
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 isEmpty(): Boolean = all().isEmpty()
fun noSuppression(): Diagnostics
override fun iterator() = all().iterator()
companion object {
val EMPTY: Diagnostics = object : Diagnostics {
override fun noSuppression(): Diagnostics = this
@@ -16,21 +16,20 @@
package org.jetbrains.kotlin.resolve.diagnostics
import com.intellij.openapi.util.Condition
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import java.util.ArrayList
class SimpleDiagnostics(diagnostics: Collection<Diagnostic>) : Diagnostics {
class SimpleDiagnostics(diagnostics: Collection<Diagnostic>) : SimpleGenericDiagnostics<Diagnostic>(diagnostics), Diagnostics {
//copy to prevent external change
private val diagnostics = ArrayList(diagnostics)
@Suppress("UNCHECKED_CAST")
private val elementsCache = DiagnosticsElementsCache(this, { true })
private val elementsCache = DiagnosticsElementsCache(this) { true }
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
}
@@ -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.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
@@ -324,7 +325,7 @@ abstract class AbstractFirBaseDiagnosticsTest : BaseDiagnosticsTest() {
private fun Iterable<FirDiagnostic<*>>.toActualDiagnostic(root: PsiElement): List<ActualDiagnostic> {
val result = mutableListOf<ActualDiagnostic>()
mapTo(result) {
filterIsInstance<Diagnostic>().mapTo(result) {
ActualDiagnostic(it, null, true)
}
for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) {
@@ -28,7 +28,7 @@ class DiagnosticTestTypeValidator(
private fun findTestCases(diagnostic: Diagnostic): TestCasesByNumbers {
val ranges = diagnostic.textRanges
val filename = diagnostic.psiFile!!.name
val filename = diagnostic.psiFile.name
val foundTestCases = testInfo.cases.byRanges[filename]!!.floorEntry(ranges[0].startOffset)
if (foundTestCases != null)
@@ -20,6 +20,7 @@ import com.intellij.icons.AllIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic;
import org.jetbrains.kotlin.diagnostics.rendering.*;
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
@@ -42,7 +43,7 @@ public class IdeErrorMessages {
private static final DiagnosticFactoryToRendererMap MAP = new DiagnosticFactoryToRendererMap("IDE");
@NotNull
public static String render(@NotNull Diagnostic diagnostic) {
public static String render(@NotNull UnboundDiagnostic diagnostic) {
DiagnosticRenderer renderer = MAP.get(diagnostic.getFactory());
if (renderer != null) {
@@ -54,7 +55,7 @@ public class IdeErrorMessages {
}
@TestOnly
public static boolean hasIdeSpecificMessage(@NotNull Diagnostic diagnostic) {
public static boolean hasIdeSpecificMessage(@NotNull UnboundDiagnostic diagnostic) {
return MAP.get(diagnostic.getFactory()) != null;
}
@@ -261,7 +261,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
answer.append("// ================\n")
for (diagnostic in diagnostics) {
answer.append("// Error at ")
.append(diagnostic.psiFile?.name)
.append(diagnostic.psiFile.name)
.append(join(diagnostic.textRanges, ","))
.append(": ")
.append(DefaultErrorMessages.render(diagnostic))
@@ -128,7 +128,7 @@ class AddFunctionToSupertypeFix private constructor(
val descriptors = generateFunctionsToAdd(function)
if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile!!.project
val project = diagnostic.psiFile.project
val functionData = descriptors.mapNotNull { createFunctionData(it, project) }
if (functionData.isEmpty()) return null
@@ -102,7 +102,7 @@ class AddPropertyToSupertypeFix private constructor(
val descriptors = generatePropertiesToAdd(property)
if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile!!.project
val project = diagnostic.psiFile.project
val propertyData = descriptors.mapNotNull { createPropertyData(it, property.initializer, project) }
if (propertyData.isEmpty()) return null
@@ -15,7 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory
class IdeDiagnosticMessageHolder : DiagnosticMessageHolder {
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))
}