From 1dff2fcf36b45062f65a9cef376d337c7a2764b5 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 17 Sep 2013 18:50:53 +0400 Subject: [PATCH] Basic implementation of DiagnosticsWithSuppression --- .../AbstractDiagnosticFactory.java | 5 +- .../jet/lang/resolve/BindingTraceContext.java | 2 +- .../lang/resolve/DelegatingBindingTrace.java | 2 +- .../resolve/DiagnosticsWithSuppression.java | 128 ++++++++++++++++++ 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/DiagnosticsWithSuppression.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnosticFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnosticFactory.java index dd148b5cb0f..023b2fbe7d0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnosticFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnosticFactory.java @@ -16,14 +16,17 @@ package org.jetbrains.jet.lang.diagnostics; +import org.jetbrains.annotations.NotNull; + public abstract class AbstractDiagnosticFactory { private String name = null; - /*package*/ void setName(String name) { + /*package*/ void setName(@NotNull String name) { this.name = name; } + @NotNull public String getName() { return name; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 1d5401bd010..92a85601509 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -71,7 +71,7 @@ public class BindingTraceContext implements BindingTrace { private BindingTraceContext(@NotNull MutableSlicedMap map) { this.map = map; - this.diagnostics = new SimpleDiagnostics(diagnosticList); + this.diagnostics = new DiagnosticsWithSuppression(getBindingContext(), diagnosticList); } @TestOnly diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java index 0caa311ebe3..477ba68d392 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java @@ -43,7 +43,7 @@ public class DelegatingBindingTrace implements BindingTrace { public Diagnostics getDiagnostics() { ArrayList mergedDiagnostics = new ArrayList(diagnostics); mergedDiagnostics.addAll(parentContext.getDiagnostics().noSuppression().all()); - return new SimpleDiagnostics(mergedDiagnostics); + return new DiagnosticsWithSuppression(this, mergedDiagnostics); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DiagnosticsWithSuppression.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DiagnosticsWithSuppression.java new file mode 100644 index 00000000000..5a42063c3fb --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DiagnosticsWithSuppression.java @@ -0,0 +1,128 @@ +package org.jetbrains.jet.lang.resolve; + +import com.google.common.collect.ImmutableSet; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.Severity; +import org.jetbrains.jet.lang.psi.JetAnnotationEntry; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetModifierList; +import org.jetbrains.jet.lang.resolve.constants.*; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; + +import java.util.*; + +public class DiagnosticsWithSuppression implements Diagnostics { + private final BindingContext context; + private final Collection diagnostics; + + public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection diagnostics) { + this.context = context; + this.diagnostics = diagnostics; + } + + @NotNull + @Override + public Diagnostics noSuppression() { + return new SimpleDiagnostics(diagnostics); + } + + @NotNull + @Override + public Iterator iterator() { + return all().iterator(); + } + + @NotNull + @Override + public Collection all() { + return ContainerUtil.filter(diagnostics, new Condition() { + @Override + public boolean value(Diagnostic diagnostic) { + return isSuppressed(diagnostic); + } + }); + } + + @Override + public boolean isEmpty() { + return all().isEmpty(); + } + + private boolean isSuppressed(@NotNull Diagnostic diagnostic) { + PsiElement element = diagnostic.getPsiElement(); + if (element instanceof JetDeclaration && isSuppressedByDeclaration(diagnostic, (JetDeclaration) element)) return true; + + while (true) { + JetDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetDeclaration.class, true); + if (declaration == null) return false; + + if (isSuppressedByDeclaration(diagnostic, declaration)) return true; + + if (element == declaration) { + element = declaration.getParent(); + } + else { + element = declaration; + } + } + } + + private boolean isSuppressedByDeclaration(@NotNull Diagnostic diagnostic, @NotNull JetDeclaration declaration) { + JetModifierList modifierList = declaration.getModifierList(); + if (modifierList == null) return false; + + ClassDescriptor suppress = KotlinBuiltIns.getInstance().getSuppressAnnotationClass(); + ConstructorDescriptor primaryConstructor = suppress.getUnsubstitutedPrimaryConstructor(); + assert primaryConstructor != null : "No primary constructor in " + suppress; + ValueParameterDescriptor parameter = primaryConstructor.getValueParameters().get(0); + + for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { + AnnotationDescriptor annotationDescriptor = context.get(BindingContext.ANNOTATION, annotationEntry); + if (annotationDescriptor == null) { + continue; + } + + if (!suppress.equals(annotationDescriptor.getType().getConstructor().getDeclarationDescriptor())) continue; + + Map> arguments = annotationDescriptor.getAllValueArguments(); + CompileTimeConstant value = arguments.get(parameter); + if (value instanceof ArrayValue) { + ArrayValue arrayValue = (ArrayValue) value; + List> values = arrayValue.getValue(); + + if (isSuppressedByStrings(diagnostic, strings(values))) { + + } + } + + } + return false; + } + + public static boolean isSuppressedByStrings(@NotNull Diagnostic diagnostic, @NotNull Set strings) { + if (strings.contains("warnings") && diagnostic.getSeverity() == Severity.WARNING) return true; + + return strings.contains(diagnostic.getFactory().getName().toLowerCase()); + } + + // We only add strings and skip other values to facilitate recovery in presence of erroneous code + private static Set strings(List> values) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (CompileTimeConstant value : values) { + if (value instanceof StringValue) { + StringValue stringValue = (StringValue) value; + builder.add(stringValue.getValue().toLowerCase()); + } + } + return builder.build(); + } +}