/*******************************************************************************
* 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);
}
}