| /* |
| * Copyright 2007-2008 Dave Griffith |
| * |
| * 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 org.jetbrains.plugins.groovy.codeInspection.control; |
| |
| import com.intellij.codeInsight.PsiEquivalenceUtil; |
| import com.intellij.codeInspection.ProblemDescriptor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.psi.CommonClassNames; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiMethod; |
| import com.intellij.psi.PsiType; |
| import com.intellij.psi.util.InheritanceUtil; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; |
| import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; |
| import org.jetbrains.plugins.groovy.codeInspection.GroovyFix; |
| import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; |
| import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; |
| import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; |
| import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; |
| |
| public class GroovyConditionalCanBeElvisInspection extends BaseInspection { |
| |
| @Override |
| @NotNull |
| public String getDisplayName() { |
| return "Conditional expression can be elvis"; |
| } |
| |
| @Override |
| @NotNull |
| public String getGroupDisplayName() { |
| return CONTROL_FLOW; |
| } |
| |
| @Override |
| public String buildErrorString(Object... args) { |
| return "Conditional expression can be elvis #loc"; |
| } |
| |
| @Override |
| public GroovyFix buildFix(@NotNull PsiElement location) { |
| return new GroovyFix() { |
| @Override |
| @NotNull |
| public String getName() { |
| return "Convert Conditional to Elvis"; |
| } |
| |
| @Override |
| public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { |
| final GrConditionalExpression expr = (GrConditionalExpression)descriptor.getPsiElement(); |
| |
| final GrExpression condition = expr.getCondition(); |
| final GrExpression thenExpression = expr.getThenBranch(); |
| final GrExpression elseExpression = expr.getElseBranch(); |
| assert elseExpression != null; |
| assert thenExpression != null; |
| |
| final String newExpression; |
| if (checkForStringIsEmpty(condition, elseExpression) || checkForListIsEmpty(condition, elseExpression) || checkForEqualsNotElse(condition, elseExpression)) { |
| newExpression = elseExpression.getText() + " ?: " + thenExpression.getText(); |
| } |
| else { |
| newExpression = thenExpression.getText() + " ?: " + elseExpression.getText(); |
| } |
| PsiImplUtil.replaceExpression(newExpression, expr); |
| } |
| }; |
| } |
| |
| private static boolean checkPsiElement(GrConditionalExpression expr) { |
| if (expr instanceof GrElvisExpression) return false; |
| GrExpression condition = expr.getCondition(); |
| |
| final GrExpression then = expr.getThenBranch(); |
| final GrExpression elseBranch = expr.getElseBranch(); |
| if (then == null || elseBranch == null) return false; |
| |
| |
| return checkForEqualsThen(condition, then) || |
| checkForEqualsNotElse(condition, elseBranch) || |
| checkForNull(condition, then) || |
| checkForStringIsEmpty(condition, elseBranch) || |
| checkForStringIsNotEmpty(condition, then) || |
| checkForListIsEmpty(condition, elseBranch) || |
| checkForListIsNotEmpty(condition, then); |
| } |
| |
| private static boolean checkForEqualsNotElse(GrExpression condition, GrExpression elseBranch) { |
| if (!(condition instanceof GrUnaryExpression)) return false; |
| if (((GrUnaryExpression)condition).getOperationTokenType() != GroovyTokenTypes.mLNOT) return false; |
| |
| final GrExpression operand = ((GrUnaryExpression)condition).getOperand(); |
| return operand != null && PsiEquivalenceUtil.areElementsEquivalent(operand, elseBranch); |
| } |
| |
| private static boolean checkForEqualsThen(GrExpression condition, GrExpression then) { |
| return PsiEquivalenceUtil.areElementsEquivalent(condition, then); |
| } |
| |
| private static boolean checkForListIsNotEmpty(GrExpression condition, GrExpression then) { |
| if (!(condition instanceof GrUnaryExpression)) return false; |
| |
| if (((GrUnaryExpression)condition).getOperationTokenType() != GroovyTokenTypes.mLNOT) return false; |
| |
| return checkForListIsEmpty(((GrUnaryExpression)condition).getOperand(), then); |
| } |
| |
| private static boolean checkForListIsEmpty(GrExpression condition, GrExpression elseBranch) { |
| if (condition instanceof GrMethodCall) condition = ((GrMethodCall)condition).getInvokedExpression(); |
| if (!(condition instanceof GrReferenceExpression)) return false; |
| |
| final GrExpression qualifier = ((GrReferenceExpression)condition).getQualifier(); |
| if (qualifier == null) return false; |
| |
| if (!PsiEquivalenceUtil.areElementsEquivalent(qualifier, elseBranch)) return false; |
| |
| final PsiType type = qualifier.getType(); |
| if (type == null) return false; |
| if (!InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_LIST)) return false; |
| |
| final PsiElement resolved = ((GrReferenceExpression)condition).resolve(); |
| |
| return resolved instanceof PsiMethod && |
| "isEmpty".equals(((PsiMethod)resolved).getName()) && |
| ((PsiMethod)resolved).getParameterList().getParametersCount() == 0; |
| } |
| |
| /** |
| * checks for the case !string.isEmpty ? string : something_else |
| */ |
| private static boolean checkForStringIsNotEmpty(GrExpression condition, GrExpression then) { |
| if (!(condition instanceof GrUnaryExpression)) return false; |
| |
| if (((GrUnaryExpression)condition).getOperationTokenType() != GroovyTokenTypes.mLNOT) return false; |
| |
| return checkForStringIsEmpty(((GrUnaryExpression)condition).getOperand(), then); |
| } |
| |
| /** |
| * checks for the case string.isEmpty() ? something_else : string |
| */ |
| private static boolean checkForStringIsEmpty(GrExpression condition, GrExpression elseBranch) { |
| if (condition instanceof GrMethodCall) condition = ((GrMethodCall)condition).getInvokedExpression(); |
| if (!(condition instanceof GrReferenceExpression)) return false; |
| |
| final GrExpression qualifier = ((GrReferenceExpression)condition).getQualifier(); |
| if (qualifier == null) return false; |
| |
| if (!PsiEquivalenceUtil.areElementsEquivalent(qualifier, elseBranch)) return false; |
| |
| final PsiType type = qualifier.getType(); |
| if (type == null) return false; |
| if (!type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) return false; |
| |
| final PsiElement resolved = ((GrReferenceExpression)condition).resolve(); |
| |
| return resolved instanceof PsiMethod && |
| "isEmpty".equals(((PsiMethod)resolved).getName()) && |
| ((PsiMethod)resolved).getParameterList().getParametersCount() == 0; |
| } |
| |
| private static boolean checkForNull(GrExpression condition, GrExpression then) { |
| if (!(condition instanceof GrBinaryExpression)) return false; |
| |
| GrBinaryExpression binaryExpression = (GrBinaryExpression)condition; |
| if (GroovyTokenTypes.mNOT_EQUAL != binaryExpression.getOperationTokenType()) return false; |
| |
| GrExpression left = binaryExpression.getLeftOperand(); |
| GrExpression right = binaryExpression.getRightOperand(); |
| if (left instanceof GrLiteral && "null".equals(left.getText()) && right != null) { |
| return PsiEquivalenceUtil.areElementsEquivalent(right, then); |
| } |
| if (right instanceof GrLiteral && "null".equals(right.getText())) { |
| return PsiEquivalenceUtil.areElementsEquivalent(left, then); |
| } |
| |
| return false; |
| } |
| |
| @NotNull |
| @Override |
| public BaseInspectionVisitor buildVisitor() { |
| return new Visitor(); |
| } |
| |
| private static class Visitor extends BaseInspectionVisitor { |
| @Override |
| public void visitConditionalExpression(GrConditionalExpression expression) { |
| super.visitConditionalExpression(expression); |
| if (checkPsiElement(expression)) { |
| registerError(expression); |
| } |
| } |
| } |
| } |