2 * Copyright (c) 2005 JetBrains s.r.o. All Rights Reserved.
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
;
28 * @author Konstantin Bulenkov
30 public class InvalidPropertyKeyInspection
extends BaseJavaLocalInspectionTool
{
33 public String
getGroupDisplayName() {
34 return GroupNames
.INTERNATIONALIZATION_GROUP_NAME
;
38 public String
getDisplayName() {
39 return CodeInsightBundle
.message("inspection.unresolved.property.key.reference.name");
43 public String
getShortName() {
44 return "UnresolvedPropertyKey";
48 public HighlightDisplayLevel
getDefaultLevel() {
49 return HighlightDisplayLevel
.ERROR
;
52 public boolean isEnabledByDefault() {
58 public ProblemDescriptor
[] checkMethod(@NotNull PsiMethod method
, @NotNull InspectionManager manager
, boolean isOnTheFly
) {
59 return checkElement(method
, manager
);
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()]);
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
);
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()]);
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) {
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
) {
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
,
143 new JavaCreatePropertyFix(expression
, key
, propertiesFiles
),
144 ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
);
145 myProblems
.add(problem
);
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
,
159 ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
);
160 myProblems
.add(problem
);
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
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
));
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() {