diff options
Diffstat (limited to 'org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java')
-rw-r--r-- | org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java b/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java new file mode 100644 index 0000000..659703d --- /dev/null +++ b/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.internal.checkers; + +import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker; +import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy; +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; + +/** + * This checker finds a problems which are caused by lack of understanding + * operator + * precedence in C. In any case it is better to surround expressions in + * parenthesis to improve readability. Example: ! x>0 && x<10 (this would be + * (!x)>0 && x<10 in C) We only look for &&, || and ! operators (and binary | & + * ^ ~) + * + * @author Alena + * + */ +public class SuggestedParenthesisChecker extends AbstractIndexAstChecker { + public static final String ER_ID = "org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem"; //$NON-NLS-1$ + public static final String PARAM_NOT = "paramNot"; //$NON-NLS-1$ + + + + public void processAst(IASTTranslationUnit ast) { + // traverse the ast using the visitor pattern. + ast.accept(new ExpressionVisitor()); + } + + class ExpressionVisitor extends ASTVisitor { + ExpressionVisitor() { + shouldVisitExpressions = true; + } + + public int visit(IASTExpression expression) { + int precedence = getPrecedence(expression); + IASTNode parent = expression.getParent(); + if (parent instanceof IASTExpression) { + IASTExpression parentExpr = (IASTExpression) parent; + if (isInParentesis(expression)) + return PROCESS_CONTINUE; + if (precedence == 2) { // unary not + if (isParamNot() && isUsedAsOperand(expression)) { + reportProblem(ER_ID, expression, expression.getRawSignature()); + return PROCESS_SKIP; + } + } else if (precedence >= 0) { + int pp = getPrecedence(parentExpr); + if (pp == -1 || pp == precedence) + return PROCESS_CONTINUE; + reportProblem(ER_ID, expression, expression.getRawSignature()); + } + } + return PROCESS_CONTINUE; + } + + private boolean isUsedAsOperand(IASTExpression expression) { + ASTNodeProperty prop = expression.getPropertyInParent(); + if (prop == IASTBinaryExpression.OPERAND_ONE + // || prop == IASTBinaryExpression.OPERAND_TWO + || prop == IASTUnaryExpression.OPERAND) + return true; + return false; + } + } + + private int getPrecedence(IASTExpression e) { + if (e instanceof IASTBinaryExpression) { + IASTBinaryExpression binExpr = (IASTBinaryExpression) e; + int operator = binExpr.getOperator(); + if (operator == IASTBinaryExpression.op_binaryAnd) + return 8; + if (operator == IASTBinaryExpression.op_binaryXor) + return 9; + if (operator == IASTBinaryExpression.op_binaryOr) + return 10; + if (operator == IASTBinaryExpression.op_logicalAnd) + return 11; + if (operator == IASTBinaryExpression.op_logicalOr) + return 12; + } + if (e instanceof IASTUnaryExpression) { + IASTUnaryExpression binExpr = (IASTUnaryExpression) e; + int operator = binExpr.getOperator(); + if (operator == IASTUnaryExpression.op_not) + return 2; + if (operator == IASTUnaryExpression.op_tilde) + return 2; + } + return -1; + } + + /** + * @param parent + * @return + */ + private boolean isInParentesis(IASTExpression node) { + IASTNode parent = node.getParent(); + if (parent instanceof IASTUnaryExpression) { + IASTUnaryExpression br = (IASTUnaryExpression) parent; + if (br.getOperator() == IASTUnaryExpression.op_bracketedPrimary) { + return true; + } + } + return false; + } + + public boolean isParamNot() { + return (Boolean) getPreference(getProblemById(ER_ID, getFile()), + PARAM_NOT); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences + * #initPreferences(org.eclipse.cdt.codan.core.model.IProblemWorkingCopy) + */ + @Override + public void initPreferences(IProblemWorkingCopy problem) { + super.initPreferences(problem); + addPreference(problem, PARAM_NOT, + CheckersMessages.SuggestedParenthesisChecker_SuggestParanthesesAroundNot, Boolean.FALSE); + } +} |