c0c3b5daf24d7c97fd851e40ad37a7a07f2769fd
[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     return ApplicationManager.getApplication().runReadAction(new Computable<PsiElement>() {
165       @Nullable
166       public PsiElement compute() {
167         final PsiElement statement = SuppressionUtil.getStatementToolSuppressedIn(place, toolId, PsiStatement.class);
168         if (statement != null) {
169           return statement;
170         }
171
172         PsiVariable local = PsiTreeUtil.getParentOfType(place, PsiVariable.class);
173         if (local != null && getAnnotationMemberSuppressedIn(local, toolId) != null) {
174           PsiModifierList modifierList = local.getModifierList();
175           return modifierList != null ? modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
176         }
177
178         PsiDocCommentOwner container = PsiTreeUtil.getNonStrictParentOfType(place, PsiDocCommentOwner.class);
179         while (true) {
180           if (!(container instanceof PsiTypeParameter)) break;
181           container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
182         }
183
184         if (container != null) {
185           PsiElement element = getElementMemberSuppressedIn(container, toolId);
186           if (element != null) return element;
187         }
188         PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class, true);
189         if (classContainer != null) {
190           PsiElement element = getElementMemberSuppressedIn(classContainer, toolId);
191           if (element != null) return element;
192         }
193
194         return null;
195       }
196     });
197   }
198
199   @NotNull
200   public static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierList modifierList) {
201     if (modifierList == null) {
202       return Collections.emptyList();
203     }
204     final PsiModifierListOwner owner = (PsiModifierListOwner)modifierList.getParent();
205     PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
206     if (annotation == null) {
207       return Collections.emptyList();
208     }
209     final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
210     if (attributes.length == 0) {
211       return Collections.emptyList();
212     }
213     final PsiAnnotationMemberValue attributeValue = attributes[0].getValue();
214     Collection<String> result = new ArrayList<String>();
215     if (attributeValue instanceof PsiArrayInitializerMemberValue) {
216       final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)attributeValue).getInitializers();
217       for (PsiAnnotationMemberValue annotationMemberValue : initializers) {
218         final String id = getInspectionIdSuppressedInAnnotationAttribute(annotationMemberValue);
219         if (id != null) {
220           result.add(id);
221         }
222       }
223     }
224     else {
225       final String id = getInspectionIdSuppressedInAnnotationAttribute(attributeValue);
226       if (id != null) {
227         result.add(id);
228       }
229     }
230     return result;
231   }
232
233   @Nullable
234   public static String getInspectionIdSuppressedInAnnotationAttribute(PsiElement element) {
235     if (element instanceof PsiLiteralExpression) {
236       final Object value = ((PsiLiteralExpression)element).getValue();
237       if (value instanceof String) {
238         return (String)value;
239       }
240     }
241     else if (element instanceof PsiReferenceExpression) {
242       final PsiElement psiElement = ((PsiReferenceExpression)element).resolve();
243       if (psiElement instanceof PsiVariableEx) {
244         final Object val = ((PsiVariableEx)psiElement).computeConstantValue(new HashSet<PsiVariable>());
245         if (val instanceof String) {
246           return (String)val;
247         }
248       }
249     }
250     return null;
251   }
252
253   public boolean canHave15Suppressions(@NotNull final PsiElement file) {
254     final Module module = ModuleUtil.findModuleForPsiElement(file);
255     if (module == null) return false;
256     final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
257     if (jdk == null) return false;
258     final boolean is_1_5 = JavaSdk.getInstance().isOfVersionOrHigher(jdk, JavaSdkVersion.JDK_1_5);
259     return DaemonCodeAnalyzerSettings.getInstance().SUPPRESS_WARNINGS && is_1_5 && PsiUtil.isLanguageLevel5OrHigher(file);
260   }
261
262   public boolean alreadyHas14Suppressions(@NotNull final PsiDocCommentOwner commentOwner) {
263     final PsiDocComment docComment = commentOwner.getDocComment();
264     return docComment != null && docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME) != null;
265   }
266 }