summaryrefslogtreecommitdiffstats
path: root/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/SuggestedParenthesisChecker.java
diff options
context:
space:
mode:
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.java141
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);
+ }
+}