mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
[171808] - Added "suggested parenthesis checker"
This commit is contained in:
parent
a2908eaedf
commit
dcd879a08f
3 changed files with 155 additions and 2 deletions
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
|
|
@ -52,6 +52,16 @@
|
|||
name="Catch uses reference to exception">
|
||||
</problem>
|
||||
</checker>
|
||||
|
||||
<checker
|
||||
class="org.eclipse.cdt.codan.checkers.sample.SuggestedParenthesisChecker"
|
||||
id="org.eclipse.cdt.codan.checkers.sample.SuggestedParenthesisChecker"
|
||||
name="SuggestedParenthesisChecker">
|
||||
<problem
|
||||
category="org.eclipse.cdt.codan.core.categories.ProgrammingProblems"
|
||||
defaultSeverity="Warning"
|
||||
id="org.eclipse.cdt.codan.checkers.sample.SuggestedParenthesisProblem"
|
||||
name="Suggested parenthesis around expression">
|
||||
</problem>
|
||||
</checker>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 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.checkers.sample;
|
||||
|
||||
import org.eclipse.cdt.codan.core.model.AbstractIndexAstChecker;
|
||||
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.IASTForStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||
|
||||
/**
|
||||
* This checker finds a problems that cause 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 {
|
||||
private static final String ER_ID = "org.eclipse.cdt.codan.checkers.sample.SuggestedParenthesisProblem";
|
||||
|
||||
public void processAst(IASTTranslationUnit ast) {
|
||||
// traverse the ast using the visitor pattern.
|
||||
ast.accept(new ExpressionVisitor());
|
||||
}
|
||||
|
||||
class ExpressionVisitor extends ASTVisitor {
|
||||
private SuspiciousExpressionVisitor svis;
|
||||
|
||||
ExpressionVisitor() {
|
||||
shouldVisitExpressions = true;
|
||||
svis = new SuspiciousExpressionVisitor();
|
||||
}
|
||||
|
||||
public int visit(IASTExpression expression) {
|
||||
int precedence = getPrecedence(expression);
|
||||
if (precedence == 2) { // unary not
|
||||
if (isUsedAsOperand(expression)) {
|
||||
reportProblem(ER_ID, svis.other,
|
||||
"Suggested parenthesis around expression");
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
if (precedence >= 0) {
|
||||
synchronized (svis) { // since we use only one instance of this
|
||||
// visitor sync just in case
|
||||
svis.init(expression);
|
||||
expression.accept(svis);
|
||||
if (svis.suspicious == true) {
|
||||
reportProblem(ER_ID, svis.other,
|
||||
"Suggested parenthesis around expression");
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
class SuspiciousExpressionVisitor extends ASTVisitor {
|
||||
IASTExpression parent;
|
||||
IASTExpression other;
|
||||
boolean suspicious = false;
|
||||
|
||||
void init(IASTExpression e) {
|
||||
parent = e;
|
||||
suspicious = false;
|
||||
}
|
||||
|
||||
SuspiciousExpressionVisitor() {
|
||||
shouldVisitExpressions = true;
|
||||
}
|
||||
|
||||
public int visit(IASTExpression expression) {
|
||||
if (expression == parent)
|
||||
return PROCESS_CONTINUE;
|
||||
if (expression instanceof IASTUnaryExpression) {
|
||||
IASTUnaryExpression uExpr = (IASTUnaryExpression) expression;
|
||||
int operator = uExpr.getOperator();
|
||||
if (operator == IASTUnaryExpression.op_bracketedPrimary) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
if (getPrecedence(expression) < 0) // not considered operator
|
||||
return PROCESS_CONTINUE;
|
||||
if (getPrecedence(expression) == getPrecedence(parent)) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
suspicious = true;
|
||||
other = expression;
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue