| /* |
| * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.siyeh.ig.assignment; |
| |
| import com.intellij.codeInspection.ProblemDescriptor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.search.LocalSearchScope; |
| import com.intellij.psi.search.SearchScope; |
| import com.intellij.psi.tree.IElementType; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.siyeh.InspectionGadgetsBundle; |
| import com.siyeh.ig.BaseInspection; |
| import com.siyeh.ig.BaseInspectionVisitor; |
| import com.siyeh.ig.InspectionGadgetsFix; |
| import com.siyeh.ig.PsiReplacementUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| public class IncrementDecrementUsedAsExpressionInspection |
| extends BaseInspection { |
| |
| @Override |
| @NotNull |
| public String getID() { |
| return "ValueOfIncrementOrDecrementUsed"; |
| } |
| |
| @Override |
| @NotNull |
| public String getDisplayName() { |
| return InspectionGadgetsBundle.message( |
| "increment.decrement.display.name"); |
| } |
| |
| @Override |
| @NotNull |
| public String buildErrorString(Object... infos) { |
| final Object info = infos[0]; |
| if (info instanceof PsiPostfixExpression) { |
| final PsiPostfixExpression postfixExpression = |
| (PsiPostfixExpression)info; |
| final IElementType tokenType = |
| postfixExpression.getOperationTokenType(); |
| if (tokenType.equals(JavaTokenType.PLUSPLUS)) { |
| return InspectionGadgetsBundle.message( |
| "value.of.post.increment.problem.descriptor"); |
| } |
| else { |
| return InspectionGadgetsBundle.message( |
| "value.of.post.decrement.problem.descriptor"); |
| } |
| } |
| else { |
| final PsiPrefixExpression prefixExpression = |
| (PsiPrefixExpression)info; |
| final IElementType tokenType = |
| prefixExpression.getOperationTokenType(); |
| if (tokenType.equals(JavaTokenType.PLUSPLUS)) { |
| return InspectionGadgetsBundle.message( |
| "value.of.pre.increment.problem.descriptor"); |
| } |
| else { |
| return InspectionGadgetsBundle.message( |
| "value.of.pre.decrement.problem.descriptor"); |
| } |
| } |
| } |
| |
| @Override |
| @Nullable |
| protected InspectionGadgetsFix buildFix(Object... infos) { |
| final PsiExpression expression = (PsiExpression)infos[0]; |
| if (PsiTreeUtil.getParentOfType(expression, PsiCodeBlock.class, true, PsiMember.class) == null) { |
| return null; |
| } |
| return new IncrementDecrementUsedAsExpressionFix(expression.getText()); |
| } |
| |
| private static class IncrementDecrementUsedAsExpressionFix |
| extends InspectionGadgetsFix { |
| |
| private final String elementText; |
| |
| IncrementDecrementUsedAsExpressionFix(String elementText) { |
| this.elementText = elementText; |
| } |
| |
| @Override |
| @NotNull |
| public String getName() { |
| return InspectionGadgetsBundle.message( |
| "increment.decrement.used.as.expression.quickfix", |
| elementText); |
| } |
| |
| @NotNull |
| @Override |
| public String getFamilyName() { |
| return "Extract to separate statement"; |
| } |
| |
| @Override |
| protected void doFix(Project project, ProblemDescriptor descriptor) { |
| // see also the Extract Increment intention of IPP |
| final PsiElement element = descriptor.getPsiElement(); |
| final PsiExpression operand; |
| if (element instanceof PsiPostfixExpression) { |
| final PsiPostfixExpression postfixExpression = |
| (PsiPostfixExpression)element; |
| operand = postfixExpression.getOperand(); |
| } |
| else { |
| final PsiPrefixExpression prefixExpression = |
| (PsiPrefixExpression)element; |
| operand = prefixExpression.getOperand(); |
| } |
| if (operand == null) { |
| return; |
| } |
| final PsiStatement statement = |
| PsiTreeUtil.getParentOfType(element, PsiStatement.class); |
| if (statement == null) { |
| return; |
| } |
| final PsiElement parent = statement.getParent(); |
| if (parent == null) { |
| return; |
| } |
| final PsiElementFactory factory = |
| JavaPsiFacade.getInstance(project).getElementFactory(); |
| final String newStatementText = element.getText() + ';'; |
| final String operandText = operand.getText(); |
| if (parent instanceof PsiIfStatement || |
| parent instanceof PsiLoopStatement) { |
| // need to add braces because |
| // in/decrement is inside braceless control statement body |
| final StringBuilder text = new StringBuilder(); |
| text.append('{'); |
| final String elementText = |
| getElementText(statement, element, operandText); |
| if (element instanceof PsiPostfixExpression) { |
| text.append(elementText); |
| text.append(newStatementText); |
| } |
| else { |
| text.append(newStatementText); |
| text.append(elementText); |
| } |
| text.append('}'); |
| final PsiCodeBlock codeBlock = |
| factory.createCodeBlockFromText(text.toString(), parent); |
| statement.replace(codeBlock); |
| return; |
| } |
| final PsiStatement newStatement = |
| factory.createStatementFromText(newStatementText, element); |
| if (statement instanceof PsiReturnStatement) { |
| if (element instanceof PsiPostfixExpression) { |
| // special handling of postfix expression in return statement |
| final PsiReturnStatement returnStatement = |
| (PsiReturnStatement)statement; |
| final PsiExpression returnValue = |
| returnStatement.getReturnValue(); |
| if (returnValue == null) { |
| return; |
| } |
| final JavaCodeStyleManager javaCodeStyleManager = |
| JavaCodeStyleManager.getInstance(project); |
| final String variableName = |
| javaCodeStyleManager.suggestUniqueVariableName( |
| "result", returnValue, true); |
| final PsiType type = returnValue.getType(); |
| if (type == null) { |
| return; |
| } |
| final String newReturnValueText = getElementText( |
| returnValue, element, operandText); |
| final String declarationStatementText = |
| type.getCanonicalText() + ' ' + variableName + |
| '=' + newReturnValueText + ';'; |
| final PsiStatement declarationStatement = |
| factory.createStatementFromText(declarationStatementText, |
| returnStatement); |
| parent.addBefore(declarationStatement, statement); |
| parent.addBefore(newStatement, statement); |
| final PsiStatement newReturnStatement = |
| factory.createStatementFromText( |
| "return " + variableName + ';', |
| returnStatement); |
| returnStatement.replace(newReturnStatement); |
| return; |
| } |
| else { |
| parent.addBefore(newStatement, statement); |
| } |
| } |
| else if (statement instanceof PsiThrowStatement) { |
| if (element instanceof PsiPostfixExpression) { |
| // special handling of postfix expression in throw statement |
| final PsiThrowStatement returnStatement = |
| (PsiThrowStatement)statement; |
| final PsiExpression exception = |
| returnStatement.getException(); |
| if (exception == null) { |
| return; |
| } |
| final JavaCodeStyleManager javaCodeStyleManager = |
| JavaCodeStyleManager.getInstance(project); |
| final String variableName = |
| javaCodeStyleManager.suggestUniqueVariableName( |
| "e", exception, true); |
| final PsiType type = exception.getType(); |
| if (type == null) { |
| return; |
| } |
| final String newReturnValueText = getElementText( |
| exception, element, operandText); |
| final String declarationStatementText = |
| type.getCanonicalText() + ' ' + variableName + |
| '=' + newReturnValueText + ';'; |
| final PsiStatement declarationStatement = |
| factory.createStatementFromText(declarationStatementText, |
| returnStatement); |
| parent.addBefore(declarationStatement, statement); |
| parent.addBefore(newStatement, statement); |
| final PsiStatement newReturnStatement = |
| factory.createStatementFromText( |
| "throw " + variableName + ';', |
| returnStatement); |
| returnStatement.replace(newReturnStatement); |
| return; |
| } |
| else { |
| parent.addBefore(newStatement, statement); |
| } |
| } |
| else if (!(statement instanceof PsiForStatement)) { |
| if (element instanceof PsiPostfixExpression) { |
| parent.addAfter(newStatement, statement); |
| } |
| else { |
| parent.addBefore(newStatement, statement); |
| } |
| } |
| else if (operand instanceof PsiReferenceExpression) { |
| final PsiReferenceExpression referenceExpression = |
| (PsiReferenceExpression)operand; |
| final PsiElement target = referenceExpression.resolve(); |
| if (target != null) { |
| final SearchScope useScope = target.getUseScope(); |
| if (!new LocalSearchScope(statement).equals(useScope)) { |
| if (element instanceof PsiPostfixExpression) { |
| parent.addAfter(newStatement, statement); |
| } |
| else { |
| parent.addBefore(newStatement, statement); |
| } |
| } |
| } |
| } |
| if (statement instanceof PsiLoopStatement) { |
| // in/decrement inside loop statement condition |
| final PsiLoopStatement loopStatement = |
| (PsiLoopStatement)statement; |
| final PsiStatement body = loopStatement.getBody(); |
| if (body instanceof PsiBlockStatement) { |
| final PsiBlockStatement blockStatement = |
| (PsiBlockStatement)body; |
| final PsiCodeBlock codeBlock = |
| blockStatement.getCodeBlock(); |
| if (element instanceof PsiPostfixExpression) { |
| final PsiElement firstElement = |
| codeBlock.getFirstBodyElement(); |
| codeBlock.addBefore(newStatement, firstElement); |
| } |
| else { |
| codeBlock.add(newStatement); |
| } |
| } |
| else { |
| final StringBuilder blockText = new StringBuilder(); |
| blockText.append('{'); |
| if (element instanceof PsiPostfixExpression) { |
| blockText.append(newStatementText); |
| if (body != null) { |
| blockText.append(body.getText()); |
| } |
| } |
| else { |
| if (body != null) { |
| blockText.append(body.getText()); |
| } |
| blockText.append(newStatementText); |
| } |
| blockText.append('}'); |
| final PsiStatement blockStatement = |
| factory.createStatementFromText( |
| blockText.toString(), statement); |
| if (body == null) { |
| loopStatement.add(blockStatement); |
| } |
| else { |
| body.replace(blockStatement); |
| } |
| } |
| } |
| PsiReplacementUtil.replaceExpression((PsiExpression)element, operandText); |
| } |
| } |
| |
| @Override |
| public BaseInspectionVisitor buildVisitor() { |
| return new IncrementDecrementUsedAsExpressionVisitor(); |
| } |
| |
| private static class IncrementDecrementUsedAsExpressionVisitor |
| extends BaseInspectionVisitor { |
| |
| @Override |
| public void visitPostfixExpression( |
| @NotNull PsiPostfixExpression expression) { |
| super.visitPostfixExpression(expression); |
| final PsiElement parent = expression.getParent(); |
| if (parent instanceof PsiExpressionStatement || |
| (parent instanceof PsiExpressionList && |
| parent.getParent() instanceof |
| PsiExpressionListStatement)) { |
| return; |
| } |
| final IElementType tokenType = expression.getOperationTokenType(); |
| if (!tokenType.equals(JavaTokenType.PLUSPLUS) && |
| !tokenType.equals(JavaTokenType.MINUSMINUS)) { |
| return; |
| } |
| registerError(expression, expression); |
| } |
| |
| @Override |
| public void visitPrefixExpression( |
| @NotNull PsiPrefixExpression expression) { |
| super.visitPrefixExpression(expression); |
| final PsiElement parent = expression.getParent(); |
| if (parent instanceof PsiExpressionStatement || |
| (parent instanceof PsiExpressionList && |
| parent.getParent() instanceof |
| PsiExpressionListStatement)) { |
| return; |
| } |
| final IElementType tokenType = expression.getOperationTokenType(); |
| if (!tokenType.equals(JavaTokenType.PLUSPLUS) && |
| !tokenType.equals(JavaTokenType.MINUSMINUS)) { |
| return; |
| } |
| registerError(expression, expression); |
| } |
| } |
| } |