diff options
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java')
-rw-r--r-- | plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java new file mode 100644 index 000000000000..0413d835f139 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/LogStatementGuardedByLogConditionInspectionBase.java @@ -0,0 +1,273 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * 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.logging; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.psiutils.TypeUtils; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class LogStatementGuardedByLogConditionInspectionBase extends BaseInspection { + final List<String> logMethodNameList = new ArrayList(); + final List<String> logConditionMethodNameList = new ArrayList(); + @SuppressWarnings({"PublicField"}) + public String loggerClassName = "java.util.logging.Logger"; + @NonNls + @SuppressWarnings({"PublicField"}) + public String loggerMethodAndconditionMethodNames = + "fine,isLoggable(java.util.logging.Level.FINE)," + + "finer,isLoggable(java.util.logging.Level.FINER)," + + "finest,isLoggable(java.util.logging.Level.FINEST)"; + @SuppressWarnings("PublicField") + public boolean flagAllUnguarded = false; + + public LogStatementGuardedByLogConditionInspectionBase() { + parseString(loggerMethodAndconditionMethodNames, logMethodNameList, logConditionMethodNameList); + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.display.name"); + } + + @Override + @NotNull + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.problem.descriptor"); + } + + @Override + @Nullable + protected InspectionGadgetsFix buildFix(Object... infos) { + return new LogStatementGuardedByLogConditionFix(); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new LogStatementGuardedByLogConditionVisitor(); + } + + @Override + public void readSettings(@NotNull Element element) throws InvalidDataException { + super.readSettings(element); + parseString(loggerMethodAndconditionMethodNames, logMethodNameList, logConditionMethodNameList); + } + + @Override + public void writeSettings(@NotNull Element element) throws WriteExternalException { + loggerMethodAndconditionMethodNames = formatString(logMethodNameList, logConditionMethodNameList); + super.writeSettings(element); + } + + private class LogStatementGuardedByLogConditionFix extends InspectionGadgetsFix { + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + @NotNull + public String getName() { + return InspectionGadgetsBundle.message("log.statement.guarded.by.log.condition.quickfix"); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element.getParent().getParent(); + final PsiStatement statement = PsiTreeUtil.getParentOfType(methodCallExpression, PsiStatement.class); + if (statement == null) { + return; + } + final List<PsiStatement> logStatements = new ArrayList(); + logStatements.add(statement); + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final String referenceName = methodExpression.getReferenceName(); + if (referenceName == null) { + return; + } + PsiStatement previousStatement = PsiTreeUtil.getPrevSiblingOfType(statement, PsiStatement.class); + while (previousStatement != null && isSameLogMethodCall(previousStatement, referenceName)) { + logStatements.add(0, previousStatement); + previousStatement = PsiTreeUtil.getPrevSiblingOfType(previousStatement, PsiStatement.class); + } + PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(statement, PsiStatement.class); + while (nextStatement != null && isSameLogMethodCall(nextStatement, referenceName)) { + logStatements.add(nextStatement); + nextStatement = PsiTreeUtil.getNextSiblingOfType(nextStatement, PsiStatement.class); + } + final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final int index = logMethodNameList.indexOf(referenceName); + final String conditionMethodText = logConditionMethodNameList.get(index); + @NonNls final String ifStatementText = "if (" + qualifier.getText() + '.' + conditionMethodText + ") {}"; + final PsiIfStatement ifStatement = (PsiIfStatement)factory.createStatementFromText(ifStatementText, statement); + final PsiBlockStatement blockStatement = (PsiBlockStatement)ifStatement.getThenBranch(); + if (blockStatement == null) { + return; + } + final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); + for (PsiStatement logStatement : logStatements) { + codeBlock.add(logStatement); + } + final PsiStatement firstStatement = logStatements.get(0); + final PsiElement parent = firstStatement.getParent(); + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); + if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getElseBranch() != null) { + final PsiBlockStatement newBlockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", statement); + newBlockStatement.getCodeBlock().add(ifStatement); + final PsiElement result = firstStatement.replace(newBlockStatement); + codeStyleManager.shortenClassReferences(result); + return; + } + final PsiElement result = parent.addBefore(ifStatement, firstStatement); + codeStyleManager.shortenClassReferences(result); + for (PsiStatement logStatement : logStatements) { + logStatement.delete(); + } + } + + private boolean isSameLogMethodCall(PsiStatement statement, @NotNull String methodName) { + if (statement == null) { + return false; + } + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement; + final PsiExpression expression = expressionStatement.getExpression(); + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final String referenceName = methodExpression.getReferenceName(); + if (!methodName.equals(referenceName)) { + return false; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + return qualifier != null && TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName); + } + } + + private class LogStatementGuardedByLogConditionVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String referenceName = methodExpression.getReferenceName(); + if (!logMethodNameList.contains(referenceName)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName)) { + return; + } + if (isSurroundedByLogGuard(expression, referenceName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression[] arguments = argumentList.getExpressions(); + if (arguments.length == 0) { + return; + } + if (!flagAllUnguarded) { + boolean constant = true; + for (PsiExpression argument : arguments) { + if (!PsiUtil.isConstantExpression(argument)) { + constant = false; + break; + } + } + if (constant) { + return; + } + } + registerMethodCallError(expression); + } + + private boolean isSurroundedByLogGuard(PsiElement element, String logMethodName) { + while (true) { + final PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(element, PsiIfStatement.class); + if (ifStatement == null) { + return false; + } + final PsiExpression condition = ifStatement.getCondition(); + if (isLogGuardCheck(condition, logMethodName)) { + return true; + } + element = ifStatement; + } + } + + private boolean isLogGuardCheck(@Nullable PsiExpression expression, String logMethodName) { + if (expression instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return false; + } + if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, loggerClassName)) { + return false; + } + final String referenceName = methodExpression.getReferenceName(); + if (referenceName == null) { + return false; + } + final int index = logMethodNameList.indexOf(logMethodName); + final String conditionName = logConditionMethodNameList.get(index); + return conditionName.startsWith(referenceName); + } + else if (expression instanceof PsiPolyadicExpression) { + final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression; + final PsiExpression[] operands = polyadicExpression.getOperands(); + for (PsiExpression operand : operands) { + if (isLogGuardCheck(operand, logMethodName)) { + return true; + } + } + } + return false; + } + } +} |