Support suppression on expressions
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
+34
-38
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user