Check if array is passed as a parameter
[fedora-idea.git] / plugins / java-i18n / src / com / intellij / codeInspection / i18n / InvalidPropertyKeyInspection.java
blobc620ca4c387b3bf622691155a6033172fd02e530
1 /*
2 * Copyright (c) 2005 JetBrains s.r.o. All Rights Reserved.
3 */
4 package com.intellij.codeInspection.i18n;
6 import com.intellij.ExtensionPoints;
7 import com.intellij.codeHighlighting.HighlightDisplayLevel;
8 import com.intellij.codeInsight.AnnotationUtil;
9 import com.intellij.codeInsight.CodeInsightBundle;
10 import com.intellij.codeInsight.daemon.GroupNames;
11 import com.intellij.codeInspection.*;
12 import com.intellij.lang.properties.PropertiesReferenceManager;
13 import com.intellij.lang.properties.psi.PropertiesFile;
14 import com.intellij.openapi.extensions.ExtensionPoint;
15 import com.intellij.openapi.extensions.Extensions;
16 import com.intellij.openapi.module.Module;
17 import com.intellij.openapi.module.ModuleUtil;
18 import com.intellij.openapi.util.Comparing;
19 import com.intellij.openapi.util.Ref;
20 import com.intellij.psi.*;
21 import org.jetbrains.annotations.NotNull;
22 import org.jetbrains.annotations.Nullable;
24 import java.util.*;
26 /**
27 * @author max
28 * @author Konstantin Bulenkov
30 public class InvalidPropertyKeyInspection extends BaseJavaLocalInspectionTool {
32 @NotNull
33 public String getGroupDisplayName() {
34 return GroupNames.INTERNATIONALIZATION_GROUP_NAME;
37 @NotNull
38 public String getDisplayName() {
39 return CodeInsightBundle.message("inspection.unresolved.property.key.reference.name");
42 @NotNull
43 public String getShortName() {
44 return "UnresolvedPropertyKey";
47 @NotNull
48 public HighlightDisplayLevel getDefaultLevel() {
49 return HighlightDisplayLevel.ERROR;
52 public boolean isEnabledByDefault() {
53 return true;
56 @Override
57 @Nullable
58 public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) {
59 return checkElement(method, manager);
62 @Override
63 @Nullable
64 public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
65 final PsiClassInitializer[] initializers = aClass.getInitializers();
66 List<ProblemDescriptor> result = new ArrayList<ProblemDescriptor>();
67 for (PsiClassInitializer initializer : initializers) {
68 final ProblemDescriptor[] descriptors = checkElement(initializer, manager);
69 if (descriptors != null) {
70 result.addAll(Arrays.asList(descriptors));
74 return result.isEmpty() ? null : result.toArray(new ProblemDescriptor[result.size()]);
77 @Override
78 @Nullable
79 public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
80 final PsiExpression initializer = field.getInitializer();
81 if (initializer != null) return checkElement(initializer, manager);
83 if (field instanceof PsiEnumConstant) {
84 return checkElement(((PsiEnumConstant)field).getArgumentList(), manager);
86 return null;
89 @Nullable private static ProblemDescriptor[] checkElement(PsiElement element, final InspectionManager manager) {
90 UnresolvedPropertyVisitor visitor = new UnresolvedPropertyVisitor(manager);
91 element.accept(visitor);
92 List<ProblemDescriptor> problems = visitor.getProblems();
93 return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]);
96 @Override
97 @Nullable
98 public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager, boolean isOnTheFly) {
99 ExtensionPoint<FileCheckingInspection> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.INVALID_PROPERTY_KEY_INSPECTION_TOOL);
100 final FileCheckingInspection[] fileCheckingInspections = point.getExtensions();
101 for(FileCheckingInspection obj: fileCheckingInspections) {
102 ProblemDescriptor[] descriptors = obj.checkFile(file, manager, isOnTheFly);
103 if (descriptors != null) {
104 return descriptors;
108 return null;
111 private static class UnresolvedPropertyVisitor extends JavaRecursiveElementWalkingVisitor {
112 private final InspectionManager myManager;
113 private final List<ProblemDescriptor> myProblems = new ArrayList<ProblemDescriptor>();
116 public UnresolvedPropertyVisitor(final InspectionManager manager) {
117 myManager = manager;
120 @Override public void visitAnonymousClass(PsiAnonymousClass aClass) {
121 final PsiExpressionList argList = aClass.getArgumentList();
122 if (argList != null) {
123 argList.accept(this);
127 @Override public void visitClass(PsiClass aClass) {}
129 @Override public void visitField(PsiField field) {}
131 @Override public void visitLiteralExpression(PsiLiteralExpression expression) {
132 Object value = expression.getValue();
133 if (!(value instanceof String)) return;
134 String key = (String)value;
135 if (isComputablePropertyExpression(expression)) return;
136 Ref<String> resourceBundleName = new Ref<String>();
137 if (!JavaI18nUtil.isValidPropertyReference(expression, key, resourceBundleName)) {
138 final String description = CodeInsightBundle.message("inspection.unresolved.property.key.reference.message", key);
139 final String bundleName = resourceBundleName.get();
140 final List<PropertiesFile> propertiesFiles = JavaI18nUtil.propertiesFilesByBundleName(bundleName, expression);
141 final ProblemDescriptor problem = myManager.createProblemDescriptor(expression,
142 description,
143 new JavaCreatePropertyFix(expression, key, propertiesFiles),
144 ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
145 myProblems.add(problem);
146 } else
147 if (expression.getParent() instanceof PsiNameValuePair) {
148 PsiNameValuePair nvp = (PsiNameValuePair) expression.getParent();
149 if (Comparing.equal(nvp.getName(), AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER)) {
150 PropertiesReferenceManager manager = PropertiesReferenceManager.getInstance(expression.getProject());
151 Module module = ModuleUtil.findModuleForPsiElement(expression);
152 if (module != null) {
153 List<PropertiesFile> propFiles = manager.findPropertiesFiles(module, key);
154 if (propFiles.isEmpty()) {
155 final String description = CodeInsightBundle.message("inspection.invalid.resource.bundle.reference", key);
156 final ProblemDescriptor problem = myManager.createProblemDescriptor(expression,
157 description,
158 (LocalQuickFix)null,
159 ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
160 myProblems.add(problem);
164 } else
165 if (expression.getParent() instanceof PsiExpressionList && expression.getParent().getParent() instanceof PsiMethodCallExpression) {
166 final Map<String, Object> annotationParams = new HashMap<String, Object>();
167 annotationParams.put(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER, null);
168 if (! JavaI18nUtil.mustBePropertyKey(expression, annotationParams)) return;
170 final int paramsCount = JavaI18nUtil.getPropertyValueParamsMaxCount(expression);
171 if (paramsCount == -1) return;
173 final PsiExpressionList expressions = (PsiExpressionList)expression.getParent();
174 final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expressions.getParent();
175 final PsiMethod method = methodCall.resolveMethod();
176 final PsiExpression[] args = expressions.getExpressions();
177 for (int i = 0; i < args.length; i++) {
178 if (args[i] == expression) {
179 if (i + paramsCount >= args.length
180 && method != null
181 && method.getParameterList().getParametersCount() == i+2
182 && method.getParameterList().getParameters()[i+1].isVarArgs()
183 && !hasArrayTypeAt(i+1, methodCall)) {
184 myProblems.add(myManager.createProblemDescriptor(methodCall,
185 CodeInsightBundle.message("property.has.more.parameters.than.passed", key, paramsCount, args.length-i-1),
186 new LocalQuickFix[0],
187 ProblemHighlightType.GENERIC_ERROR));
189 break;
195 private boolean hasArrayTypeAt(int i, PsiMethodCallExpression methodCall) {
196 return methodCall != null
197 && methodCall.getArgumentList().getExpressionTypes().length > i
198 && methodCall.getArgumentList().getExpressionTypes()[i] instanceof PsiArrayType;
201 private static boolean isComputablePropertyExpression(PsiExpression expression) {
202 while (expression != null && expression.getParent() instanceof PsiParenthesizedExpression) expression = (PsiExpression)expression.getParent();
203 return expression != null && expression.getParent() instanceof PsiExpression;
206 public List<ProblemDescriptor> getProblems() {
207 return myProblems;