make inspection usable (also for while and more complex conditions and pay attention...
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / dataflow / ConstantValueVariableUseInspection.java
blobf4a187d62224bcc71e607070bd3222253d80b25f
1 /*
2 * Copyright 2008 Bas Leijdekkers
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.siyeh.ig.dataflow;
18 import com.intellij.codeInspection.ProblemDescriptor;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.psi.*;
21 import com.intellij.psi.tree.IElementType;
22 import com.intellij.psi.util.PsiUtil;
23 import com.intellij.util.IncorrectOperationException;
24 import com.siyeh.ig.BaseInspection;
25 import com.siyeh.ig.BaseInspectionVisitor;
26 import com.siyeh.ig.InspectionGadgetsFix;
27 import com.siyeh.InspectionGadgetsBundle;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
31 public class ConstantValueVariableUseInspection extends BaseInspection {
33 @Override
34 @NotNull
35 public String getDisplayName() {
36 return InspectionGadgetsBundle.message(
37 "constant.value.variable.use.display.name");
40 @Override
41 @NotNull
42 protected String buildErrorString(Object... infos) {
43 return InspectionGadgetsBundle.message(
44 "constant.value.variable.use.problem.descriptor");
47 @Override
48 protected InspectionGadgetsFix buildFix(Object... infos) {
49 final PsiExpression expression = (PsiExpression) infos[0];
50 return new ReplaceReferenceWithExpressionFix(expression);
53 private static class ReplaceReferenceWithExpressionFix
54 extends InspectionGadgetsFix {
56 private final PsiExpression expression;
58 ReplaceReferenceWithExpressionFix(
59 PsiExpression expression) {
60 this.expression = expression;
64 @NotNull
65 public String getName() {
66 return InspectionGadgetsBundle.message(
67 "replace.reference.with.expression.quickfix",
68 expression.getText());
71 @Override
72 protected void doFix(Project project, ProblemDescriptor descriptor)
73 throws IncorrectOperationException {
74 final PsiElement element = descriptor.getPsiElement();
75 element.replace(expression);
79 @Override
80 public BaseInspectionVisitor buildVisitor() {
81 return new ConstantValueVariableUseVisitor();
84 private static class ConstantValueVariableUseVisitor
85 extends BaseInspectionVisitor {
87 @Override
88 public void visitIfStatement(PsiIfStatement statement) {
89 super.visitIfStatement(statement);
90 final PsiExpression condition = statement.getCondition();
91 final PsiStatement body = statement.getThenBranch();
92 checkCondition(condition, body);
95 @Override
96 public void visitWhileStatement(PsiWhileStatement statement) {
97 super.visitWhileStatement(statement);
98 final PsiExpression condition = statement.getCondition();
99 final PsiStatement body = statement.getBody();
100 checkCondition(condition, body);
103 private boolean checkCondition(@Nullable PsiExpression condition,
104 @Nullable PsiStatement body) {
105 if (body == null) {
106 return false;
108 if (!(condition instanceof PsiBinaryExpression)) {
109 return false;
111 final PsiBinaryExpression binaryExpression =
112 (PsiBinaryExpression) condition;
113 final IElementType tokenType =
114 binaryExpression.getOperationTokenType();
115 final PsiExpression lhs = binaryExpression.getLOperand();
116 final PsiExpression rhs = binaryExpression.getROperand();
117 if (JavaTokenType.ANDAND == tokenType) {
118 return checkCondition(lhs, body) ||
119 checkCondition(rhs, body);
121 if (JavaTokenType.EQEQ != tokenType) {
122 return false;
124 if (rhs == null) {
125 return false;
127 if (PsiUtil.isConstantExpression(lhs)) {
128 return checkConstantValueVariableUse(rhs, lhs, body);
129 } else if (PsiUtil.isConstantExpression(rhs)) {
130 return checkConstantValueVariableUse(lhs, rhs, body);
132 return false;
135 private boolean checkConstantValueVariableUse(
136 @Nullable PsiExpression expression,
137 @NotNull PsiExpression constantExpression,
138 @NotNull PsiElement body) {
139 if (!(expression instanceof PsiReferenceExpression)) {
140 return false;
142 final PsiReferenceExpression referenceExpression =
143 (PsiReferenceExpression) expression;
144 final PsiElement target = referenceExpression.resolve();
145 if (!(target instanceof PsiVariable)) {
146 return false;
148 if (target instanceof PsiField) {
149 return false;
151 final PsiVariable variable = (PsiVariable) target;
152 final VariableReadVisitor visitor =
153 new VariableReadVisitor(variable);
154 body.accept(visitor);
155 if (!visitor.isRead()) {
156 return false;
158 registerError(visitor.getReference(), constantExpression);
159 return true;
163 private static class VariableReadVisitor
164 extends JavaRecursiveElementVisitor {
166 @NotNull
167 private final PsiVariable variable;
168 private boolean read = false;
169 private boolean written = false;
170 private PsiReferenceExpression reference = null;
172 VariableReadVisitor(@NotNull PsiVariable variable) {
173 this.variable = variable;
176 @Override
177 public void visitElement(@NotNull PsiElement element) {
178 if (read || written) {
179 return;
181 super.visitElement(element);
184 @Override
185 public void visitAssignmentExpression(
186 @NotNull PsiAssignmentExpression assignment) {
187 if (read || written) {
188 return;
190 super.visitAssignmentExpression(assignment);
191 final PsiExpression lhs = assignment.getLExpression();
192 if (lhs instanceof PsiReferenceExpression) {
193 PsiReferenceExpression referenceExpression =
194 (PsiReferenceExpression) lhs;
195 final PsiElement target = referenceExpression.resolve();
196 if (variable.equals(target)) {
197 written = true;
198 return;
201 final PsiExpression rhs = assignment.getRExpression();
202 if (rhs == null) {
203 return;
205 final VariableUsedVisitor visitor =
206 new VariableUsedVisitor(variable);
207 rhs.accept(visitor);
208 read = visitor.isUsed();
209 reference = visitor.getReference();
212 @Override
213 public void visitPrefixExpression(
214 @NotNull PsiPrefixExpression prefixExpression) {
215 if (read || written) {
216 return;
218 super.visitPrefixExpression(prefixExpression);
219 final PsiJavaToken operationSign =
220 prefixExpression.getOperationSign();
221 final IElementType tokenType = operationSign.getTokenType();
222 if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
223 !tokenType.equals(JavaTokenType.MINUSMINUS)) {
224 return;
226 final PsiExpression operand = prefixExpression.getOperand();
227 if (!(operand instanceof PsiReferenceExpression)) {
228 return;
230 final PsiReferenceExpression referenceExpression =
231 (PsiReferenceExpression) operand;
232 final PsiElement target = referenceExpression.resolve();
233 if (!variable.equals(target)) {
234 return;
236 written = true;
239 @Override
240 public void visitPostfixExpression(
241 @NotNull PsiPostfixExpression postfixExpression) {
242 if (read || written) {
243 return;
245 super.visitPostfixExpression(postfixExpression);
246 final PsiJavaToken operationSign =
247 postfixExpression.getOperationSign();
248 final IElementType tokenType = operationSign.getTokenType();
249 if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
250 !tokenType.equals(JavaTokenType.MINUSMINUS)) {
251 return;
253 final PsiExpression operand = postfixExpression.getOperand();
254 if (!(operand instanceof PsiReferenceExpression)) {
255 return;
257 final PsiReferenceExpression referenceExpression =
258 (PsiReferenceExpression) operand;
259 final PsiElement target = referenceExpression.resolve();
260 if (!variable.equals(target)) {
261 return;
263 written = true;
266 @Override
267 public void visitVariable(@NotNull PsiVariable variable) {
268 if (read || written) {
269 return;
271 super.visitVariable(variable);
272 final PsiExpression initalizer = variable.getInitializer();
273 if (initalizer == null) {
274 return;
276 final VariableUsedVisitor visitor =
277 new VariableUsedVisitor(variable);
278 initalizer.accept(visitor);
279 read = visitor.isUsed();
280 reference = visitor.getReference();
283 @Override
284 public void visitMethodCallExpression(
285 @NotNull PsiMethodCallExpression call) {
286 if (read || written) {
287 return;
289 super.visitMethodCallExpression(call);
290 final PsiExpressionList argumentList = call.getArgumentList();
291 final PsiExpression[] arguments = argumentList.getExpressions();
292 for (final PsiExpression argument : arguments) {
293 final VariableUsedVisitor visitor =
294 new VariableUsedVisitor(variable);
295 argument.accept(visitor);
296 if (visitor.isUsed()) {
297 read = true;
298 reference = visitor.getReference();
299 return;
304 @Override
305 public void visitNewExpression(
306 @NotNull PsiNewExpression newExpression) {
307 if (read || written) {
308 return;
310 super.visitNewExpression(newExpression);
311 final PsiExpressionList argumentList =
312 newExpression.getArgumentList();
313 if (argumentList == null) {
314 return;
316 final PsiExpression[] arguments = argumentList.getExpressions();
317 for (final PsiExpression argument : arguments) {
318 final VariableUsedVisitor visitor =
319 new VariableUsedVisitor(variable);
320 argument.accept(visitor);
321 if (visitor.isUsed()) {
322 read = true;
323 reference = visitor.getReference();
324 return;
329 @Override
330 public void visitArrayInitializerExpression(
331 PsiArrayInitializerExpression expression) {
332 if (read || written) {
333 return;
335 super.visitArrayInitializerExpression(expression);
336 final PsiExpression[] arguments = expression.getInitializers();
337 for (final PsiExpression argument : arguments) {
338 final VariableUsedVisitor visitor =
339 new VariableUsedVisitor(variable);
340 argument.accept(visitor);
341 if (visitor.isUsed()) {
342 read = true;
343 reference = visitor.getReference();
344 return;
349 @Override
350 public void visitReturnStatement(
351 @NotNull PsiReturnStatement returnStatement) {
352 if (read || written) {
353 return;
355 super.visitReturnStatement(returnStatement);
356 final PsiExpression returnValue = returnStatement.getReturnValue();
357 if (returnValue == null) {
358 return;
360 final VariableUsedVisitor visitor =
361 new VariableUsedVisitor(variable);
362 returnValue.accept(visitor);
363 read = visitor.isUsed();
364 reference = visitor.getReference();
368 * check if variable is used in nested/inner class.
370 @Override
371 public void visitClass(PsiClass aClass) {
372 if (read || written) {
373 return;
375 super.visitClass(aClass);
376 final VariableUsedVisitor visitor =
377 new VariableUsedVisitor(variable);
378 aClass.accept(visitor);
379 read = visitor.isUsed();
380 reference = visitor.getReference();
383 public boolean isRead() {
384 return read;
387 public PsiReferenceExpression getReference() {
388 return reference;
392 private static class VariableUsedVisitor
393 extends JavaRecursiveElementVisitor {
395 private final PsiVariable variable;
396 private boolean used = false;
397 private PsiReferenceExpression reference = null;
399 VariableUsedVisitor(PsiVariable variable) {
400 this.variable = variable;
403 @Override
404 public void visitElement(PsiElement element) {
405 if (used) {
406 return;
408 super.visitElement(element);
411 @Override
412 public void visitReferenceExpression(
413 @NotNull PsiReferenceExpression expression) {
414 if (used) {
415 return;
417 super.visitReferenceExpression(expression);
418 final PsiElement referent = expression.resolve();
419 if (referent == null) {
420 return;
422 if (referent.equals(variable)) {
423 reference = expression;
424 used = true;
428 public boolean isUsed() {
429 return used;
432 public PsiReferenceExpression getReference() {
433 return reference;