Basic implementation of DiagnosticsWithSuppression

This commit is contained in:
Andrey Breslav
2013-09-17 18:50:53 +04:00
parent 887e4276ee
commit 1dff2fcf36
4 changed files with 134 additions and 3 deletions
@@ -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;
}
@@ -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
@@ -43,7 +43,7 @@ public class DelegatingBindingTrace implements BindingTrace {
public Diagnostics getDiagnostics() {
ArrayList<Diagnostic> mergedDiagnostics = new ArrayList<Diagnostic>(diagnostics);
mergedDiagnostics.addAll(parentContext.getDiagnostics().noSuppression().all());
return new SimpleDiagnostics(mergedDiagnostics);
return new DiagnosticsWithSuppression(this, mergedDiagnostics);
}
@Override
@@ -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<Diagnostic> diagnostics;
public DiagnosticsWithSuppression(@NotNull BindingContext context, @NotNull Collection<Diagnostic> diagnostics) {
this.context = context;
this.diagnostics = diagnostics;
}
@NotNull
@Override
public Diagnostics noSuppression() {
return new SimpleDiagnostics(diagnostics);
}
@NotNull
@Override
public Iterator<Diagnostic> iterator() {
return all().iterator();
}
@NotNull
@Override
public Collection<Diagnostic> all() {
return ContainerUtil.filter(diagnostics, new Condition<Diagnostic>() {
@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<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = annotationDescriptor.getAllValueArguments();
CompileTimeConstant<?> value = arguments.get(parameter);
if (value instanceof ArrayValue) {
ArrayValue arrayValue = (ArrayValue) value;
List<CompileTimeConstant<?>> values = arrayValue.getValue();
if (isSuppressedByStrings(diagnostic, strings(values))) {
}
}
}
return false;
}
public static boolean isSuppressedByStrings(@NotNull Diagnostic diagnostic, @NotNull Set<String> 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<String> strings(List<CompileTimeConstant<?>> values) {
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (CompileTimeConstant<?> value : values) {
if (value instanceof StringValue) {
StringValue stringValue = (StringValue) value;
builder.add(stringValue.getValue().toLowerCase());
}
}
return builder.build();
}
}