filter out inspections, suppressed for file
[idea/community.git] / java / java-impl / src / com / intellij / codeInspection / SuppressManagerImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * User: anna
19  * Date: 24-Dec-2007
20  */
21 package com.intellij.codeInspection;
22
23 import com.intellij.codeInsight.AnnotationUtil;
24 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
25 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
26 import com.intellij.codeInsight.daemon.impl.actions.*;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.module.Module;
29 import com.intellij.openapi.module.ModuleUtil;
30 import com.intellij.openapi.projectRoots.JavaSdk;
31 import com.intellij.openapi.projectRoots.JavaSdkVersion;
32 import com.intellij.openapi.projectRoots.Sdk;
33 import com.intellij.openapi.roots.ModuleRootManager;
34 import com.intellij.openapi.util.Computable;
35 import com.intellij.openapi.util.text.StringUtil;
36 import com.intellij.psi.*;
37 import com.intellij.psi.impl.PsiVariableEx;
38 import com.intellij.psi.javadoc.PsiDocComment;
39 import com.intellij.psi.javadoc.PsiDocTag;
40 import com.intellij.psi.util.PsiTreeUtil;
41 import com.intellij.psi.util.PsiUtil;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
44
45 import javax.annotation.Generated;
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.HashSet;
50 import java.util.regex.Matcher;
51
52 public class SuppressManagerImpl extends SuppressManager {
53
54   @NotNull
55   public SuppressIntentionAction[] createSuppressActions(@NotNull final HighlightDisplayKey displayKey) {
56     return new SuppressIntentionAction[]{
57         new SuppressByJavaCommentFix(displayKey),
58         new SuppressParameterFix(displayKey),
59         new SuppressFix(displayKey),
60         new SuppressForClassFix(displayKey),
61         new SuppressAllForClassFix()
62       };
63   }
64
65   public boolean isSuppressedFor(@NotNull final PsiElement element, final String toolId) {
66     return getElementToolSuppressedIn(element, toolId) != null;
67   }
68
69   @Nullable
70   public PsiElement getElementMemberSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
71     PsiElement element = getDocCommentToolSuppressedIn(owner, inspectionToolID);
72     if (element != null) return element;
73     element = getAnnotationMemberSuppressedIn(owner, inspectionToolID);
74     if (element != null) return element;
75     PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(owner, PsiDocCommentOwner.class);
76     while (classContainer != null) {
77       element = getDocCommentToolSuppressedIn(classContainer, inspectionToolID);
78       if (element != null) return element;
79
80       element = getAnnotationMemberSuppressedIn(classContainer, inspectionToolID);
81       if (element != null) return element;
82
83       classContainer = PsiTreeUtil.getParentOfType(classContainer, PsiDocCommentOwner.class);
84     }
85     return null;
86   }
87
88   @Nullable
89   public PsiElement getAnnotationMemberSuppressedIn(@NotNull final PsiModifierListOwner owner, final String inspectionToolID) {
90     final PsiAnnotation generatedAnnotation = AnnotationUtil.findAnnotation(owner, Generated.class.getName());
91     if (generatedAnnotation != null) return generatedAnnotation;
92     PsiModifierList modifierList = owner.getModifierList();
93     Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation(modifierList);
94     for (String ids : suppressedIds) {
95       if (SuppressionUtil.isInspectionToolIdMentioned(ids, inspectionToolID)) {
96         return modifierList != null ? AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
97       }
98     }
99     return null;
100   }
101
102   @Nullable
103   public PsiElement getDocCommentToolSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
104     PsiDocComment docComment = owner.getDocComment();
105     if (docComment == null && owner.getParent() instanceof PsiDeclarationStatement) {
106       final PsiElement el = PsiTreeUtil.skipSiblingsBackward(owner.getParent(), PsiWhiteSpace.class);
107       if (el instanceof PsiDocComment) {
108         docComment = (PsiDocComment)el;
109       }
110     }
111     if (docComment != null) {
112       PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
113       if (inspectionTag != null) {
114         final PsiElement[] dataElements = inspectionTag.getDataElements();
115         for (PsiElement dataElement : dataElements) {
116           String valueText = dataElement.getText();
117           if (SuppressionUtil.isInspectionToolIdMentioned(valueText, inspectionToolID)) {
118             return docComment;
119           }
120         }
121       }
122     }
123     return null;
124   }
125
126   @NotNull
127   public Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull final PsiModifierListOwner owner) {
128     if (!PsiUtil.isLanguageLevel5OrHigher(owner)) return Collections.emptyList();
129     PsiModifierList modifierList = owner.getModifierList();
130     return getInspectionIdsSuppressedInAnnotation(modifierList);
131   }
132
133   @Nullable
134   public String getSuppressedInspectionIdsIn(@NotNull PsiElement element) {
135     if (element instanceof PsiComment) {
136       String text = element.getText();
137       Matcher matcher = SuppressionUtil.SUPPRESS_IN_LINE_COMMENT_PATTERN.matcher(text);
138       if (matcher.matches()) {
139         return matcher.group(1).trim();
140       }
141     }
142     if (element instanceof PsiDocCommentOwner) {
143       PsiDocComment docComment = ((PsiDocCommentOwner)element).getDocComment();
144       if (docComment != null) {
145         PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
146         if (inspectionTag != null) {
147           String valueText = "";
148           for (PsiElement dataElement : inspectionTag.getDataElements()) {
149             valueText += dataElement.getText();
150           }
151           return valueText;
152         }
153       }
154     }
155     if (element instanceof PsiModifierListOwner) {
156       Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation((PsiModifierListOwner)element);
157       return suppressedIds.isEmpty() ? null : StringUtil.join(suppressedIds, ",");
158     }
159     return null;
160   }
161
162   @Nullable
163   public PsiElement getElementToolSuppressedIn(@NotNull final PsiElement place, final String toolId) {
164     if (place instanceof PsiFile) return null;
165     return ApplicationManager.getApplication().runReadAction(new Computable<PsiElement>() {
166       @Nullable
167       public PsiElement compute() {
168         final PsiElement statement = SuppressionUtil.getStatementToolSuppressedIn(place, toolId, PsiStatement.class);
169         if (statement != null) {
170           return statement;
171         }
172
173         PsiVariable local = PsiTreeUtil.getParentOfType(place, PsiVariable.class);
174         if (local != null && getAnnotationMemberSuppressedIn(local, toolId) != null) {
175           PsiModifierList modifierList = local.getModifierList();
176           return modifierList != null ? modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
177         }
178
179         PsiDocCommentOwner container = PsiTreeUtil.getNonStrictParentOfType(place, PsiDocCommentOwner.class);
180         while (true) {
181           if (!(container instanceof PsiTypeParameter)) break;
182           container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
183         }
184
185         if (container != null) {
186           PsiElement element = getElementMemberSuppressedIn(container, toolId);
187           if (element != null) return element;
188         }
189         PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class, true);
190         if (classContainer != null) {
191           PsiElement element = getElementMemberSuppressedIn(classContainer, toolId);
192           if (element != null) return element;
193         }
194
195         return null;
196       }
197     });
198   }
199
200   @NotNull
201   public static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierList modifierList) {
202     if (modifierList == null) {
203       return Collections.emptyList();
204     }
205     final PsiModifierListOwner owner = (PsiModifierListOwner)modifierList.getParent();
206     PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
207     if (annotation == null) {
208       return Collections.emptyList();
209     }
210     final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
211     if (attributes.length == 0) {
212       return Collections.emptyList();
213     }
214     final PsiAnnotationMemberValue attributeValue = attributes[0].getValue();
215     Collection<String> result = new ArrayList<String>();
216     if (attributeValue instanceof PsiArrayInitializerMemberValue) {
217       final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)attributeValue).getInitializers();
218       for (PsiAnnotationMemberValue annotationMemberValue : initializers) {
219         final String id = getInspectionIdSuppressedInAnnotationAttribute(annotationMemberValue);
220         if (id != null) {
221           result.add(id);
222         }
223       }
224     }
225     else {
226       final String id = getInspectionIdSuppressedInAnnotationAttribute(attributeValue);
227       if (id != null) {
228         result.add(id);
229       }
230     }
231     return result;
232   }
233
234   @Nullable
235   public static String getInspectionIdSuppressedInAnnotationAttribute(PsiElement element) {
236     if (element instanceof PsiLiteralExpression) {
237       final Object value = ((PsiLiteralExpression)element).getValue();
238       if (value instanceof String) {
239         return (String)value;
240       }
241     }
242     else if (element instanceof PsiReferenceExpression) {
243       final PsiElement psiElement = ((PsiReferenceExpression)element).resolve();
244       if (psiElement instanceof PsiVariableEx) {
245         final Object val = ((PsiVariableEx)psiElement).computeConstantValue(new HashSet<PsiVariable>());
246         if (val instanceof String) {
247           return (String)val;
248         }
249       }
250     }
251     return null;
252   }
253
254   public boolean canHave15Suppressions(@NotNull final PsiElement file) {
255     final Module module = ModuleUtil.findModuleForPsiElement(file);
256     if (module == null) return false;
257     final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
258     if (jdk == null) return false;
259     final boolean is_1_5 = JavaSdk.getInstance().isOfVersionOrHigher(jdk, JavaSdkVersion.JDK_1_5);
260     return DaemonCodeAnalyzerSettings.getInstance().SUPPRESS_WARNINGS && is_1_5 && PsiUtil.isLanguageLevel5OrHigher(file);
261   }
262
263   public boolean alreadyHas14Suppressions(@NotNull final PsiDocCommentOwner commentOwner) {
264     final PsiDocComment docComment = commentOwner.getDocComment();
265     return docComment != null && docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME) != null;
266   }
267 }