Support suppression on expressions

This commit is contained in:
Andrey Breslav
2013-09-22 22:05:45 +04:00
parent 716718fb0d
commit c7c151a726
6 changed files with 71 additions and 38 deletions
@@ -150,6 +150,16 @@ public class JetControlFlowProcessor {
} }
} }
@Override
public void visitAnnotatedExpression(JetAnnotatedExpression expression) {
builder.read(expression);
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
generateInstructions(baseExpression, inCondition);
}
}
@Override @Override
public void visitThisExpression(JetThisExpression expression) { public void visitThisExpression(JetThisExpression expression) {
builder.read(expression); builder.read(expression);
@@ -9,16 +9,14 @@ import com.intellij.util.containers.ConcurrentWeakValueHashMap;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FilteringIterator; import com.intellij.util.containers.FilteringIterator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.psi.JetAnnotated;
import org.jetbrains.jet.lang.psi.JetAnnotationEntry; 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.ArrayValue; import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.constants.StringValue;
@@ -34,7 +32,7 @@ public class DiagnosticsWithSuppression implements Diagnostics {
private final Collection<Diagnostic> diagnostics; private final Collection<Diagnostic> diagnostics;
// The cache is weak: we're OK with losing it // The cache is weak: we're OK with losing it
private final Map<JetDeclaration, Suppressor> suppressors = new ConcurrentWeakValueHashMap<JetDeclaration, Suppressor>(); private final Map<JetAnnotated, Suppressor> suppressors = new ConcurrentWeakValueHashMap<JetAnnotated, Suppressor>();
// Caching frequently used values: // Caching frequently used values:
private final ClassDescriptor suppressClass; private final ClassDescriptor suppressClass;
@@ -82,14 +80,14 @@ public class DiagnosticsWithSuppression implements Diagnostics {
private boolean isSuppressed(@NotNull Diagnostic diagnostic) { private boolean isSuppressed(@NotNull Diagnostic diagnostic) {
PsiElement element = diagnostic.getPsiElement(); PsiElement element = diagnostic.getPsiElement();
JetDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetDeclaration.class, false); JetAnnotated annotated = PsiTreeUtil.getParentOfType(element, JetAnnotated.class, false);
if (declaration == null) return false; if (annotated == null) return false;
return isSuppressedByDeclaration(diagnostic, declaration, 0); return isSuppressedByAnnotated(diagnostic, annotated, 0);
} }
/* /*
The cache is optimized for the case where no warnings are suppressed at a declaration (most frequent one) The cache is optimized for the case where no warnings are suppressed (most frequent one)
trait Root { trait Root {
suppress("X") suppress("X")
@@ -117,52 +115,50 @@ public class DiagnosticsWithSuppression implements Diagnostics {
This way we need no more lookups than the number of suppress() annotations from here to the root. This way we need no more lookups than the number of suppress() annotations from here to the root.
*/ */
private boolean isSuppressedByDeclaration(@NotNull Diagnostic diagnostic, @NotNull JetDeclaration declaration, int debugDepth) { private boolean isSuppressedByAnnotated(@NotNull Diagnostic diagnostic, @NotNull JetAnnotated annotated, int debugDepth) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Declaration: ", declaration.getName()); LOG.debug("Annotated: ", annotated.getName());
LOG.debug("Depth: ", debugDepth); LOG.debug("Depth: ", debugDepth);
LOG.debug("Cache size: ", suppressors.size(), "\n"); LOG.debug("Cache size: ", suppressors.size(), "\n");
} }
Suppressor suppressor = getOrCreateSuppressor(declaration); Suppressor suppressor = getOrCreateSuppressor(annotated);
if (suppressor.isSuppressed(diagnostic)) return true; if (suppressor.isSuppressed(diagnostic)) return true;
JetDeclaration declarationAbove = PsiTreeUtil.getParentOfType(suppressor.getDeclaration(), JetDeclaration.class, true); JetAnnotated annotatedAbove = PsiTreeUtil.getParentOfType(suppressor.getAnnotatedElement(), JetAnnotated.class, true);
if (declarationAbove == null) return false; if (annotatedAbove == null) return false;
boolean suppressed = isSuppressedByDeclaration(diagnostic, declarationAbove, debugDepth + 1); boolean suppressed = isSuppressedByAnnotated(diagnostic, annotatedAbove, debugDepth + 1);
Suppressor suppressorAbove = suppressors.get(declarationAbove); Suppressor suppressorAbove = suppressors.get(annotatedAbove);
if (suppressorAbove != null && suppressorAbove.dominates(suppressor)) { if (suppressorAbove != null && suppressorAbove.dominates(suppressor)) {
suppressors.put(declaration, suppressorAbove); suppressors.put(annotated, suppressorAbove);
} }
return suppressed; return suppressed;
} }
@NotNull @NotNull
private Suppressor getOrCreateSuppressor(@NotNull JetDeclaration declaration) { private Suppressor getOrCreateSuppressor(@NotNull JetAnnotated annotated) {
Suppressor suppressor = suppressors.get(declaration); Suppressor suppressor = suppressors.get(annotated);
if (suppressor == null) { if (suppressor == null) {
Set<String> strings = getSuppressingStrings(declaration.getModifierList()); Set<String> strings = getSuppressingStrings(annotated);
if (strings.isEmpty()) { if (strings.isEmpty()) {
suppressor = new EmptySuppressor(declaration); suppressor = new EmptySuppressor(annotated);
} }
else if (strings.size() == 1) { else if (strings.size() == 1) {
suppressor = new SingularSuppressor(declaration, strings.iterator().next()); suppressor = new SingularSuppressor(annotated, strings.iterator().next());
} }
else { else {
suppressor = new MultiSuppressor(declaration, strings); suppressor = new MultiSuppressor(annotated, strings);
} }
suppressors.put(declaration, suppressor); suppressors.put(annotated, suppressor);
} }
return suppressor; return suppressor;
} }
private Set<String> getSuppressingStrings(@Nullable JetModifierList modifierList) { private Set<String> getSuppressingStrings(@NotNull JetAnnotated annotated) {
if (modifierList == null) return ImmutableSet.of();
ImmutableSet.Builder<String> builder = ImmutableSet.builder(); ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { for (JetAnnotationEntry annotationEntry : annotated.getAnnotationEntries()) {
AnnotationDescriptor annotationDescriptor = context.get(BindingContext.ANNOTATION, annotationEntry); AnnotationDescriptor annotationDescriptor = context.get(BindingContext.ANNOTATION, annotationEntry);
if (annotationDescriptor == null) { if (annotationDescriptor == null) {
continue; continue;
@@ -200,15 +196,15 @@ public class DiagnosticsWithSuppression implements Diagnostics {
} }
private static abstract class Suppressor { private static abstract class Suppressor {
private final JetDeclaration declaration; private final JetAnnotated annotated;
protected Suppressor(@NotNull JetDeclaration declaration) { protected Suppressor(@NotNull JetAnnotated annotated) {
this.declaration = declaration; this.annotated = annotated;
} }
@NotNull @NotNull
public JetDeclaration getDeclaration() { public JetAnnotated getAnnotatedElement() {
return declaration; return annotated;
} }
public abstract boolean isSuppressed(@NotNull Diagnostic diagnostic); public abstract boolean isSuppressed(@NotNull Diagnostic diagnostic);
@@ -219,8 +215,8 @@ public class DiagnosticsWithSuppression implements Diagnostics {
private static class EmptySuppressor extends Suppressor { private static class EmptySuppressor extends Suppressor {
private EmptySuppressor(@NotNull JetDeclaration declaration) { private EmptySuppressor(@NotNull JetAnnotated annotated) {
super(declaration); super(annotated);
} }
@Override @Override
@@ -237,8 +233,8 @@ public class DiagnosticsWithSuppression implements Diagnostics {
private static class SingularSuppressor extends Suppressor { private static class SingularSuppressor extends Suppressor {
private final String string; private final String string;
private SingularSuppressor(@NotNull JetDeclaration declaration, @NotNull String string) { private SingularSuppressor(@NotNull JetAnnotated annotated, @NotNull String string) {
super(declaration); super(annotated);
this.string = string; this.string = string;
} }
@@ -257,8 +253,8 @@ public class DiagnosticsWithSuppression implements Diagnostics {
private static class MultiSuppressor extends Suppressor { private static class MultiSuppressor extends Suppressor {
private final Set<String> strings; private final Set<String> strings;
private MultiSuppressor(@NotNull JetDeclaration declaration, @NotNull Set<String> strings) { private MultiSuppressor(@NotNull JetAnnotated annotated, @NotNull Set<String> strings) {
super(declaration); super(annotated);
this.strings = strings; this.strings = strings;
} }
@@ -0,0 +1,4 @@
fun foo() {
[suppress("warnings")]
("": String??)
}
@@ -0,0 +1,4 @@
fun foo(): Any? {
[suppress("REDUNDANT_NULLABLE", "UNNECESSARY_NOT_NULL_ASSERTION")]
return ""!! <!USELESS_CAST_STATIC_ASSERT_IS_FINE!>as<!> String??
}
@@ -0,0 +1,4 @@
fun foo(): Any? {
[suppress("REDUNDANT_NULLABLE")]
return null <!USELESS_CAST!>as<!> Nothing??
}
@@ -5598,6 +5598,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/suppress/allWarnings/suppressWarningsOnClassObject.kt"); doTest("compiler/testData/diagnostics/tests/suppress/allWarnings/suppressWarningsOnClassObject.kt");
} }
@TestMetadata("suppressWarningsOnExpression.kt")
public void testSuppressWarningsOnExpression() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/allWarnings/suppressWarningsOnExpression.kt");
}
@TestMetadata("suppressWarningsOnFunction.kt") @TestMetadata("suppressWarningsOnFunction.kt")
public void testSuppressWarningsOnFunction() throws Exception { public void testSuppressWarningsOnFunction() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/allWarnings/suppressWarningsOnFunction.kt"); doTest("compiler/testData/diagnostics/tests/suppress/allWarnings/suppressWarningsOnFunction.kt");
@@ -5646,6 +5651,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/suppress/manyWarnings/onClassObject.kt"); doTest("compiler/testData/diagnostics/tests/suppress/manyWarnings/onClassObject.kt");
} }
@TestMetadata("onExpression.kt")
public void testOnExpression() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/manyWarnings/onExpression.kt");
}
@TestMetadata("onFunction.kt") @TestMetadata("onFunction.kt")
public void testOnFunction() throws Exception { public void testOnFunction() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/manyWarnings/onFunction.kt"); doTest("compiler/testData/diagnostics/tests/suppress/manyWarnings/onFunction.kt");
@@ -5689,6 +5699,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/suppress/oneWarning/onClassObject.kt"); doTest("compiler/testData/diagnostics/tests/suppress/oneWarning/onClassObject.kt");
} }
@TestMetadata("onExpression.kt")
public void testOnExpression() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/oneWarning/onExpression.kt");
}
@TestMetadata("onFunction.kt") @TestMetadata("onFunction.kt")
public void testOnFunction() throws Exception { public void testOnFunction() throws Exception {
doTest("compiler/testData/diagnostics/tests/suppress/oneWarning/onFunction.kt"); doTest("compiler/testData/diagnostics/tests/suppress/oneWarning/onFunction.kt");