NPE
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / java15api / Java15APIUsageInspection.java
blob6a2da5caec6a123c11b16cf29c4273c01018caa4
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.codeInspection.java15api;
18 import com.intellij.ExtensionPoints;
19 import com.intellij.codeHighlighting.HighlightDisplayLevel;
20 import com.intellij.codeInsight.daemon.GroupNames;
21 import com.intellij.codeInspection.*;
22 import com.intellij.openapi.extensions.ExtensionPoint;
23 import com.intellij.openapi.extensions.Extensions;
24 import com.intellij.openapi.module.LanguageLevelUtil;
25 import com.intellij.openapi.module.Module;
26 import com.intellij.openapi.module.ModuleUtil;
27 import com.intellij.openapi.vfs.CharsetToolkit;
28 import com.intellij.pom.java.LanguageLevel;
29 import com.intellij.psi.*;
30 import com.intellij.psi.javadoc.PsiDocComment;
31 import com.intellij.psi.util.PsiTreeUtil;
32 import com.intellij.psi.util.PsiUtil;
33 import com.intellij.util.containers.HashMap;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.NonNls;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
39 import java.io.*;
41 /**
42 * @author max
44 public class Java15APIUsageInspection extends BaseJavaLocalInspectionTool {
45 @NonNls public static final String SHORT_NAME = "Since15";
47 private static final HashMap<LanguageLevel, THashSet<String>> ourForbiddenAPI = new HashMap<LanguageLevel, THashSet<String>>(5);
48 private static final THashSet<String> ourIgnored16ClassesAPI = new THashSet<String>(10);
49 private static final HashMap<LanguageLevel, String> ourAPIPresentationMap = new HashMap<LanguageLevel, String>(5);
51 static {
52 final THashSet<String> ourForbidden14API = new THashSet<String>(1000);
53 initForbiddenApi("api14List.txt", ourForbidden14API);
54 ourForbiddenAPI.put(LanguageLevel.JDK_1_3, ourForbidden14API);
55 ourAPIPresentationMap.put(LanguageLevel.JDK_1_3, "1.4");
56 final THashSet<String> ourForbidden15API = new THashSet<String>(1000);
57 initForbiddenApi("apiList.txt", ourForbidden15API);
58 ourForbiddenAPI.put(LanguageLevel.JDK_1_4, ourForbidden15API);
59 ourAPIPresentationMap.put(LanguageLevel.JDK_1_4, "1.5");
60 final THashSet<String> ourForbidden16API = new THashSet<String>(1000);
61 initForbiddenApi("api16List.txt", ourForbidden16API);
62 ourForbiddenAPI.put(LanguageLevel.JDK_1_5, ourForbidden16API);
63 ourAPIPresentationMap.put(LanguageLevel.JDK_1_5, "1.6");
64 initForbiddenApi("ignore16List.txt", ourIgnored16ClassesAPI);
67 private static void initForbiddenApi(@NonNls String list, THashSet<String> set) {
68 BufferedReader reader = null;
69 try {
70 final InputStream stream = Java15APIUsageInspection.class.getResourceAsStream(list);
71 reader = new BufferedReader(new InputStreamReader(stream, CharsetToolkit.UTF8_CHARSET));
73 do {
74 String line = reader.readLine();
75 if (line == null) break;
77 set.add(line);
78 } while(true);
80 catch (UnsupportedEncodingException e) {
81 // can't be.
83 catch (IOException e) {
84 // can't be
86 finally {
87 if (reader != null) {
88 try {
89 reader.close();
91 catch (IOException e) {
92 // Will not happen
98 @NotNull
99 public String getGroupDisplayName() {
100 return GroupNames.JDK15_SPECIFIC_GROUP_NAME;
103 @NotNull
104 public String getDisplayName() {
105 return InspectionsBundle.message("inspection.1.5.display.name", "@since 1.5(1.6)");
108 @NotNull
109 public String getShortName() {
110 return SHORT_NAME;
114 @NotNull
115 @Override
116 public HighlightDisplayLevel getDefaultLevel() {
117 return HighlightDisplayLevel.ERROR;
120 @Override
121 public boolean isEnabledByDefault() {
122 return false;
125 @NotNull
126 public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
127 return new MyVisitor(holder);
130 private static boolean isInProject(final PsiElement elt) {
131 return elt.getManager().isInProject(elt);
134 @Override @Nullable
135 public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
136 ExtensionPoint<FileCheckingInspection> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.JAVA15_INSPECTION_TOOL);
137 final FileCheckingInspection[] fileCheckingInspections = point.getExtensions();
138 for(FileCheckingInspection obj: fileCheckingInspections) {
139 ProblemDescriptor[] descriptors = obj.checkFile(file, manager, isOnTheFly);
140 if (descriptors != null) {
141 return descriptors;
145 return null;
148 public static String getPresentable(LanguageLevel languageLevel) {
149 return ourAPIPresentationMap.get(languageLevel);
152 private class MyVisitor extends JavaElementVisitor {
153 private final ProblemsHolder myHolder;
155 public MyVisitor(final ProblemsHolder holder) {
156 myHolder = holder;
159 @Override public void visitDocComment(PsiDocComment comment) {
160 // No references inside doc comment are of interest.
163 @Override public void visitClass(PsiClass aClass) {
164 // Don't go into classes (anonymous, locals).
167 @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
168 visitReferenceElement(expression);
171 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
172 super.visitReferenceElement(reference);
173 final PsiElement resolved = reference.resolve();
175 if (resolved instanceof PsiCompiledElement && resolved instanceof PsiMember) {
176 final Module module = ModuleUtil.findModuleForPsiElement(reference.getElement());
177 if (module != null) {
178 final LanguageLevel languageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module);
179 if (isForbiddenApiUsage((PsiMember)resolved, languageLevel)) {
180 PsiClass psiClass = null;
181 final PsiElement qualifier = reference.getQualifier();
182 if (qualifier != null) {
183 if (qualifier instanceof PsiExpression) {
184 psiClass = PsiUtil.resolveClassInType(((PsiExpression)qualifier).getType());
187 else {
188 psiClass = PsiTreeUtil.getParentOfType(reference, PsiClass.class);
190 if (psiClass != null) {
191 if (isIgnored(psiClass)) return;
192 for (PsiClass superClass : psiClass.getSupers()) {
193 if (isIgnored(superClass)) return;
196 registerError(reference, languageLevel);
202 private boolean isIgnored(PsiClass psiClass) {
203 final String qualifiedName = psiClass.getQualifiedName();
204 return qualifiedName != null && ourIgnored16ClassesAPI.contains(qualifiedName);
207 @Override public void visitNewExpression(final PsiNewExpression expression) {
208 super.visitNewExpression(expression);
209 final PsiMethod constructor = expression.resolveConstructor();
210 final Module module = ModuleUtil.findModuleForPsiElement(expression);
211 if (module != null) {
212 final LanguageLevel languageLevel = LanguageLevelUtil.getEffectiveLanguageLevel(module);
213 if (constructor instanceof PsiCompiledElement) {
214 if (isForbiddenApiUsage(constructor, languageLevel)) {
215 registerError(expression.getClassReference(), languageLevel);
221 private void registerError(PsiJavaCodeReferenceElement reference, LanguageLevel api) {
222 if (isInProject(reference)) {
223 myHolder.registerProblem(reference, InspectionsBundle.message("inspection.1.5.problem.descriptor", getPresentable(api)));
228 public static boolean isForbiddenApiUsage(final PsiMember member, LanguageLevel languageLevel) {
229 if (member == null) return false;
231 // Annotations caught by special inspection if necessary
232 if (member instanceof PsiClass && ((PsiClass)member).isAnnotationType()) return false;
234 if (member instanceof PsiAnonymousClass) return false;
235 if (member.getContainingClass() instanceof PsiAnonymousClass) return false;
236 if (member instanceof PsiClass && !(member.getParent() instanceof PsiClass || member.getParent() instanceof PsiFile)) return false;
238 return isForbiddenSignature(member, languageLevel) ||
239 isForbiddenApiUsage(member.getContainingClass(), languageLevel);
243 private static boolean isForbiddenSignature(PsiMember member, LanguageLevel languageLevel) {
245 final THashSet<String> forbiddenApi = ourForbiddenAPI.get(languageLevel);
246 if (forbiddenApi == null) return false;
247 return forbiddenApi.contains(getSignature(member)) ||
248 (languageLevel.compareTo(LanguageLevel.HIGHEST) != 0 && isForbiddenSignature(member, LanguageLevel.values()[languageLevel.ordinal() + 1]));
251 public static String getSignature(PsiMember member) {
252 if (member instanceof PsiClass) {
253 return ((PsiClass)member).getQualifiedName();
255 if (member instanceof PsiField) {
256 return getSignature(member.getContainingClass()) + "#" + member.getName();
258 if (member instanceof PsiMethod) {
259 final PsiMethod method = (PsiMethod)member;
260 StringBuffer buf = new StringBuffer();
261 buf.append(getSignature(method.getContainingClass()));
262 buf.append('#');
263 buf.append(method.getName());
264 buf.append('(');
265 final PsiType[] params = method.getSignature(PsiSubstitutor.EMPTY).getParameterTypes();
266 for (PsiType type : params) {
267 buf.append(type.getCanonicalText());
268 buf.append(";");
270 buf.append(')');
271 return buf.toString();
273 assert false;
274 return null;