mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 329497 - checker for no break at the end of case
This commit is contained in:
parent
acfb30df58
commit
83ea511e24
9 changed files with 800 additions and 5 deletions
|
@ -56,4 +56,7 @@ problem.description.ReturnStyle = Checks for return statements that do no return
|
||||||
checker.name.SuspiciousSemicolon = Suspicious semicolon
|
checker.name.SuspiciousSemicolon = Suspicious semicolon
|
||||||
problem.name.SuspiciousSemicolon = Suspicious semicolon
|
problem.name.SuspiciousSemicolon = Suspicious semicolon
|
||||||
problem.messagePattern.SuspiciousSemicolon = Suspicious semicolon
|
problem.messagePattern.SuspiciousSemicolon = Suspicious semicolon
|
||||||
problem.description.SuspiciousSemicolon = A semicolon is used as a null statement in a condition. For example, 'if(expression);'
|
problem.description.SuspiciousSemicolon = A semicolon is used as a null statement in a condition. For example, 'if(expression);'
|
||||||
|
checker.name.CaseBreak = No break at end of case
|
||||||
|
problem.description.CaseBreak = Looks for "case" statements which end without a "break" statement statement statement
|
||||||
|
problem.messagePattern.CaseBreak = No break at the end of this case
|
|
@ -306,5 +306,19 @@
|
||||||
name="%problem.name.SuspiciousSemicolon">
|
name="%problem.name.SuspiciousSemicolon">
|
||||||
</problem>
|
</problem>
|
||||||
</checker>
|
</checker>
|
||||||
|
<checker
|
||||||
|
class="org.eclipse.cdt.codan.internal.checkers.CaseBreakChecker"
|
||||||
|
id="org.eclipse.cdt.codan.internal.checkers.CaseBreak"
|
||||||
|
name="%checker.name.CaseBreak">
|
||||||
|
<problem
|
||||||
|
category="org.eclipse.cdt.codan.core.categories.ProgrammingProblems"
|
||||||
|
defaultEnabled="true"
|
||||||
|
defaultSeverity="Warning"
|
||||||
|
description="%problem.description.CaseBreak"
|
||||||
|
id="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem"
|
||||||
|
messagePattern="%problem.messagePattern.CaseBreak"
|
||||||
|
name="%checker.name.CaseBreak">
|
||||||
|
</problem>
|
||||||
|
</checker>
|
||||||
</extension>
|
</extension>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2010 Gil Barash
|
||||||
|
* 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:
|
||||||
|
* Gil Barash - Initial implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.codan.internal.checkers;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
||||||
|
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
||||||
|
import org.eclipse.cdt.codan.core.model.ICheckerWithPreferences;
|
||||||
|
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
|
||||||
|
public class CaseBreakChecker extends AbstractIndexAstChecker implements
|
||||||
|
ICheckerWithPreferences {
|
||||||
|
public static final String ER_ID = "org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem"; //$NON-NLS-1$
|
||||||
|
public static final String PARAM_LAST_CASE = "last_case_param"; //$NON-NLS-1$
|
||||||
|
public static final String PARAM_EMPTY_CASE = "empty_case_param"; //$NON-NLS-1$
|
||||||
|
public static final String PARAM_NO_BREAK_COMMENT = "no_break_comment"; //$NON-NLS-1$
|
||||||
|
public static final String DEFAULT_NO_BREAK_COMMENT = "no break"; //$NON-NLS-1$
|
||||||
|
private CommentsIterator _commentsIt; // Iterator over comments
|
||||||
|
private Boolean _checkLastCase; // Should we check the last case in the switch?
|
||||||
|
private Boolean _checkEmptyCase; // Should we check an empty case (a case without any statements within it)
|
||||||
|
private String _noBreakComment; // The comment suppressing this warning
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class receives the comments of the AST and iterates over them
|
||||||
|
*/
|
||||||
|
class CommentsIterator {
|
||||||
|
private int _next; // The next comment's index
|
||||||
|
private IASTComment[] _comments;
|
||||||
|
|
||||||
|
CommentsIterator(IASTComment[] comments) {
|
||||||
|
_comments = comments;
|
||||||
|
_next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Is there an unvisited comment?
|
||||||
|
*/
|
||||||
|
public boolean hasNext() {
|
||||||
|
return (_next < _comments.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The next comment (doesn't automatically advance to the next
|
||||||
|
* comment.
|
||||||
|
* i.e. Calling this function twice may return the same value).
|
||||||
|
* See {@link#advance}
|
||||||
|
*/
|
||||||
|
public IASTComment getNext() {
|
||||||
|
return (_comments[_next]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param node The node to compare the comment's location to
|
||||||
|
* @return Is the next comment located after 'node'
|
||||||
|
*/
|
||||||
|
public boolean isNextAfterThis(IASTNode node) {
|
||||||
|
return (_comments[_next].getFileLocation().getNodeOffset() > node
|
||||||
|
.getFileLocation().getNodeOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param node The node to compare the comment's location to
|
||||||
|
* @return Is the next comment located after 'node' ends
|
||||||
|
*/
|
||||||
|
public boolean isNextAfterThisEnds(IASTNode node) {
|
||||||
|
return (_comments[_next].getFileLocation().getNodeOffset() > node
|
||||||
|
.getFileLocation().getNodeOffset()
|
||||||
|
+ node.getFileLocation().getNodeLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance to the next comment
|
||||||
|
*/
|
||||||
|
public void advance() {
|
||||||
|
_next++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This visitor looks for "switch" statements and invokes "SwitchVisitor" on
|
||||||
|
* them
|
||||||
|
*/
|
||||||
|
class SwitchFindingVisitor extends ASTVisitor {
|
||||||
|
protected IASTStatement _switchStatement; // The "switch" we're visiting (used by inheriting classes to avoid re-visiting the same "switch" again)
|
||||||
|
|
||||||
|
SwitchFindingVisitor() {
|
||||||
|
shouldVisitStatements = true;
|
||||||
|
_switchStatement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int visit(IASTStatement statement) {
|
||||||
|
if (statement instanceof IASTSwitchStatement) {
|
||||||
|
// Are we already visiting this statement?
|
||||||
|
if (_switchStatement == null
|
||||||
|
|| !statement.equals(_switchStatement)) {
|
||||||
|
SwitchVisitor switch_visitor = new SwitchVisitor(statement);
|
||||||
|
statement.accept(switch_visitor);
|
||||||
|
return PROCESS_SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PROCESS_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This visitor visits a switch statement and checks the end of each
|
||||||
|
* "case" statement (to see that it ends with a "break").
|
||||||
|
* Because it extends SwitchFindingVisitor is would also check nested
|
||||||
|
* "switch"s
|
||||||
|
*/
|
||||||
|
class SwitchVisitor extends SwitchFindingVisitor {
|
||||||
|
private IASTStatement _last_case_stmnt;
|
||||||
|
private boolean _first_case_statement;
|
||||||
|
private int _last_break_stmnt_offset;
|
||||||
|
private int _last_normal_stmnt_offset;
|
||||||
|
private int _last_case_stmnt_offset;
|
||||||
|
|
||||||
|
SwitchVisitor(IASTStatement switch_statement) {
|
||||||
|
shouldVisitStatements = true;
|
||||||
|
_first_case_statement = true;
|
||||||
|
_switchStatement = switch_statement;
|
||||||
|
_last_break_stmnt_offset = 0;
|
||||||
|
_last_normal_stmnt_offset = 0;
|
||||||
|
_last_case_stmnt_offset = 0;
|
||||||
|
_last_case_stmnt = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Is this an "empty" case (i.e. with no statements in it)
|
||||||
|
*/
|
||||||
|
private boolean isEmptyCase() {
|
||||||
|
return _last_case_stmnt_offset > _last_normal_stmnt_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Was a "break" statement the last statement in this case
|
||||||
|
*/
|
||||||
|
private boolean breakFoundLast() {
|
||||||
|
return _last_normal_stmnt_offset < _last_break_stmnt_offset
|
||||||
|
&& _last_case_stmnt_offset < _last_break_stmnt_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the last case we've visited
|
||||||
|
*
|
||||||
|
* @param comment The comment ending this case (may be NULL)
|
||||||
|
*/
|
||||||
|
private void checkLastCase(IASTComment comment) {
|
||||||
|
if (comment != null) {
|
||||||
|
String str = new String(comment.getComment());
|
||||||
|
if (comment.isBlockComment())
|
||||||
|
str = str.substring(2, str.length() - 2);
|
||||||
|
else
|
||||||
|
str = str.substring(2);
|
||||||
|
str = str.trim();
|
||||||
|
if (str.equalsIgnoreCase(_noBreakComment))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_last_case_stmnt == null)
|
||||||
|
return; // This is an empty switch
|
||||||
|
if (breakFoundLast())
|
||||||
|
return; // There was a "break" before the current statement
|
||||||
|
if (!isEmptyCase() || _checkEmptyCase) {
|
||||||
|
reportProblem(ER_ID, _last_case_stmnt, (Object) null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int visit(IASTStatement statement) {
|
||||||
|
if (statement instanceof IASTCaseStatement
|
||||||
|
|| statement instanceof IASTDefaultStatement) {
|
||||||
|
if (_first_case_statement) {
|
||||||
|
/*
|
||||||
|
* This is the first "case", i.e. the beginning of the
|
||||||
|
* "switch"
|
||||||
|
*/
|
||||||
|
_first_case_statement = false;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This is not the 1st "case", meaning that a previous case
|
||||||
|
* has just ended,
|
||||||
|
* Let's check that case and see how it ended...
|
||||||
|
*/
|
||||||
|
IASTComment comment = null;
|
||||||
|
// Do we have a comment which is before this "case" statement (but after the previous statement)?
|
||||||
|
while (_commentsIt.hasNext()
|
||||||
|
&& !_commentsIt.isNextAfterThis(statement)) {
|
||||||
|
comment = _commentsIt.getNext();
|
||||||
|
_commentsIt.advance();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 'comment' is the last comment found in this case (after
|
||||||
|
* the last statement in this "case"
|
||||||
|
*/
|
||||||
|
checkLastCase(comment);
|
||||||
|
}
|
||||||
|
/* Update variables with the new opened "case" */
|
||||||
|
_last_case_stmnt_offset = statement.getFileLocation()
|
||||||
|
.getNodeOffset();
|
||||||
|
_last_case_stmnt = statement;
|
||||||
|
} else if (isBreakOrExitStatement(statement)) { // A "break" statement
|
||||||
|
_last_break_stmnt_offset = statement.getFileLocation()
|
||||||
|
.getNodeOffset();
|
||||||
|
} else { // a non-switch related statement
|
||||||
|
_last_normal_stmnt_offset = statement.getFileLocation()
|
||||||
|
.getNodeOffset();
|
||||||
|
}
|
||||||
|
/* advance comments we already passed */
|
||||||
|
while (_commentsIt.hasNext()
|
||||||
|
&& !_commentsIt.isNextAfterThis(statement))
|
||||||
|
_commentsIt.advance();
|
||||||
|
return super.visit(statement); // This would handle nested "switch"s
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int leave(IASTStatement statement) {
|
||||||
|
/*
|
||||||
|
* Are we leaving the "switch" altogether? (we need to see how the
|
||||||
|
* last "case" ended)
|
||||||
|
*/
|
||||||
|
if (_checkLastCase && statement instanceof IASTCompoundStatement
|
||||||
|
&& statement.getParent() == _switchStatement) {
|
||||||
|
IASTComment comment = null;
|
||||||
|
// is "Next" still in the switch's scope? if it is it was after the last statement
|
||||||
|
while (_commentsIt.hasNext()
|
||||||
|
&& !_commentsIt.isNextAfterThisEnds(statement)) {
|
||||||
|
comment = _commentsIt.getNext();
|
||||||
|
_commentsIt.advance();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 'comment' is the last comment found in this case (after the
|
||||||
|
* last statement in this "case"
|
||||||
|
*/
|
||||||
|
checkLastCase(comment);
|
||||||
|
}
|
||||||
|
return super.leave(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* This class's functions...
|
||||||
|
************************************************/
|
||||||
|
public CaseBreakChecker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statement
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isBreakOrExitStatement(IASTStatement statement) {
|
||||||
|
CxxAstUtils utils = CxxAstUtils.getInstance();
|
||||||
|
return statement instanceof IASTBreakStatement
|
||||||
|
|| statement instanceof IASTReturnStatement
|
||||||
|
|| statement instanceof IASTContinueStatement
|
||||||
|
|| statement instanceof IASTGotoStatement
|
||||||
|
|| utils.isThrowStatement(statement) || utils.isExitStatement(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initPreferences(IProblemWorkingCopy problem) {
|
||||||
|
super.initPreferences(problem);
|
||||||
|
addPreference(
|
||||||
|
problem,
|
||||||
|
PARAM_NO_BREAK_COMMENT,
|
||||||
|
CheckersMessages.CaseBreakChecker_DefaultNoBreakCommentDescription,
|
||||||
|
DEFAULT_NO_BREAK_COMMENT);
|
||||||
|
addPreference(problem, PARAM_EMPTY_CASE,
|
||||||
|
CheckersMessages.CaseBreakChecker_EmptyCaseDescription,
|
||||||
|
Boolean.TRUE);
|
||||||
|
addPreference(problem, PARAM_LAST_CASE,
|
||||||
|
CheckersMessages.CaseBreakChecker_LastCaseDescription,
|
||||||
|
Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processAst(IASTTranslationUnit ast) {
|
||||||
|
_checkLastCase = (Boolean) getPreference(
|
||||||
|
getProblemById(ER_ID, getFile()), PARAM_LAST_CASE);
|
||||||
|
_checkEmptyCase = (Boolean) getPreference(
|
||||||
|
getProblemById(ER_ID, getFile()), PARAM_EMPTY_CASE);
|
||||||
|
_noBreakComment = (String) getPreference(
|
||||||
|
getProblemById(ER_ID, getFile()), PARAM_NO_BREAK_COMMENT);
|
||||||
|
SwitchFindingVisitor visitor = new SwitchFindingVisitor();
|
||||||
|
_commentsIt = new CommentsIterator(ast.getComments());
|
||||||
|
ast.accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,9 @@ import org.eclipse.osgi.util.NLS;
|
||||||
*/
|
*/
|
||||||
public class CheckersMessages extends NLS {
|
public class CheckersMessages extends NLS {
|
||||||
private static final String BUNDLE_NAME = "org.eclipse.cdt.codan.internal.checkers.messages"; //$NON-NLS-1$
|
private static final String BUNDLE_NAME = "org.eclipse.cdt.codan.internal.checkers.messages"; //$NON-NLS-1$
|
||||||
|
public static String CaseBreakChecker_DefaultNoBreakCommentDescription;
|
||||||
|
public static String CaseBreakChecker_EmptyCaseDescription;
|
||||||
|
public static String CaseBreakChecker_LastCaseDescription;
|
||||||
public static String CatchByReference_ReportForUnknownType;
|
public static String CatchByReference_ReportForUnknownType;
|
||||||
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
||||||
public static String ReturnChecker_Param0;
|
public static String ReturnChecker_Param0;
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
# Contributors:
|
# Contributors:
|
||||||
# Alena Laskavaia - initial API and implementation
|
# Alena Laskavaia - initial API and implementation
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
CaseBreakChecker_DefaultNoBreakCommentDescription=Comment text to suppress the problem (regular expression):
|
||||||
|
CaseBreakChecker_EmptyCaseDescription=Check also empty case statement
|
||||||
|
CaseBreakChecker_LastCaseDescription=Check also the last case statement
|
||||||
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
|
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
|
||||||
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern
|
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern
|
||||||
ReturnChecker_Param0=Also check functions with implicit return value
|
ReturnChecker_Param0=Also check functions with implicit return value
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||||
|
@ -35,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
|
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IFunction;
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
|
@ -408,4 +410,30 @@ public final class CxxAstUtils {
|
||||||
});
|
});
|
||||||
return returnSpecifier[0];
|
return returnSpecifier[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param body
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isThrowStatement(IASTNode body) {
|
||||||
|
if (!(body instanceof IASTExpressionStatement))
|
||||||
|
return false;
|
||||||
|
IASTExpression expression = ((IASTExpressionStatement) body)
|
||||||
|
.getExpression();
|
||||||
|
if (!(expression instanceof IASTUnaryExpression))
|
||||||
|
return false;
|
||||||
|
return ((IASTUnaryExpression) expression).getOperator() == IASTUnaryExpression.op_throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExitStatement(IASTNode body) {
|
||||||
|
if (!(body instanceof IASTExpressionStatement))
|
||||||
|
return false;
|
||||||
|
IASTExpression expression = ((IASTExpressionStatement) body)
|
||||||
|
.getExpression();
|
||||||
|
if (!(expression instanceof IASTFunctionCallExpression))
|
||||||
|
return false;
|
||||||
|
IASTExpression functionNameExpression = ((IASTFunctionCallExpression) expression)
|
||||||
|
.getFunctionNameExpression();
|
||||||
|
return functionNameExpression.getRawSignature().equals("exit"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2010 Gil Barash
|
||||||
|
* 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:
|
||||||
|
* Gil Barash - Initial implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.codan.core.internal.checkers;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.core.param.IProblemPreference;
|
||||||
|
import org.eclipse.cdt.codan.core.test.CheckerTestCase;
|
||||||
|
import org.eclipse.cdt.codan.internal.checkers.CaseBreakChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link#CaseBreakChecker} class
|
||||||
|
*/
|
||||||
|
public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseBad() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// default:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseDefaultBad() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseBad() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyCaseBad() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseOKbreak() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseWithReturn() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(int a) {
|
||||||
|
// while (a--)
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseWithContinue() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(int a) {
|
||||||
|
//
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// throw 1;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseWithThrow() {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseOKbreak() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// break;
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyCaseOKbreak() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// /* no break */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseOKcomment() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(int a, int b) {
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// switch (b) {
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseTwoSwitches() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseOKcomment() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// /* no break */
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
public void testEmptyCaseOKcomment() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// bye();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseBadCommentNotLast() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// /*no break*/
|
||||||
|
// case 3:
|
||||||
|
// b = 2;
|
||||||
|
// //no break
|
||||||
|
// case 4:
|
||||||
|
// b = 2;
|
||||||
|
// // no break
|
||||||
|
// case 5:
|
||||||
|
// b = 2;
|
||||||
|
// /* no brea */
|
||||||
|
// case 6:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break1 */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testDifferentComments() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(16, 19);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// // lolo
|
||||||
|
// case 2:
|
||||||
|
// case 3:
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// case 3:
|
||||||
|
// case 4:
|
||||||
|
// break;
|
||||||
|
// case 5:
|
||||||
|
// case 6:
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// case 3:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// case 4:
|
||||||
|
// b = 2;
|
||||||
|
// case 5:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// case 6:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// b = 2;
|
||||||
|
// case 7:
|
||||||
|
// b = 2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// default:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testGeneral1() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4, 6, 7, 11, 14, 16, 19, 20, 24, 27, 32, 37, 41, 46,
|
||||||
|
49, 51);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// /* no break */
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// // lolo
|
||||||
|
// case 3:
|
||||||
|
// /* no break */
|
||||||
|
// b = 2;
|
||||||
|
// // loo
|
||||||
|
// case 4:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// /* no break */
|
||||||
|
// case 5:
|
||||||
|
// // lolo
|
||||||
|
// b = 2;
|
||||||
|
// /* no break */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testGeneralComments1() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(8, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 0:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// case 1:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// case 3:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case 4:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// /* no break */
|
||||||
|
// }
|
||||||
|
// case 5:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// }
|
||||||
|
// /* no break */
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testNestedSwitches() {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLines(4, 6, 9, 20, 27);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseIgnore() {
|
||||||
|
setLast(false);
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
setLast(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// case 3: case 4:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyCaseIgnore() {
|
||||||
|
setEmpty(false);
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrors();
|
||||||
|
setEmpty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch( a ) {
|
||||||
|
// case 1:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseIgnore() {
|
||||||
|
String code = getAboveComment();
|
||||||
|
setLast(false);
|
||||||
|
loadCodeAndRun(code);
|
||||||
|
checkNoErrors();
|
||||||
|
setLast(true);
|
||||||
|
setEmpty(false);
|
||||||
|
loadCodeAndRun(code);
|
||||||
|
checkNoErrors();
|
||||||
|
setEmpty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLast(boolean val) {
|
||||||
|
IProblemPreference pref = getPreference(CaseBreakChecker.ER_ID,
|
||||||
|
CaseBreakChecker.PARAM_LAST_CASE);
|
||||||
|
pref.setValue(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setEmpty(boolean val) {
|
||||||
|
IProblemPreference pref = getPreference(CaseBreakChecker.ER_ID,
|
||||||
|
CaseBreakChecker.PARAM_EMPTY_CASE);
|
||||||
|
pref.setValue(val);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import junit.framework.TestSuite;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.AssignmentInConditionCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.AssignmentInConditionCheckerTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.AssignmentToItselfCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.AssignmentToItselfCheckerTest;
|
||||||
|
import org.eclipse.cdt.codan.core.internal.checkers.CaseBreakCheckerTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.CatchByReferenceTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.CatchByReferenceTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.ReturnCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.ReturnCheckerTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.ReturnStyleCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.ReturnStyleCheckerTest;
|
||||||
|
@ -51,6 +52,7 @@ public class AutomatedIntegrationSuite extends TestSuite {
|
||||||
suite.addTestSuite(AssignmentToItselfCheckerTest.class);
|
suite.addTestSuite(AssignmentToItselfCheckerTest.class);
|
||||||
suite.addTestSuite(ReturnStyleCheckerTest.class);
|
suite.addTestSuite(ReturnStyleCheckerTest.class);
|
||||||
suite.addTestSuite(SuspiciousSemicolonCheckerTest.class);
|
suite.addTestSuite(SuspiciousSemicolonCheckerTest.class);
|
||||||
|
suite.addTestSuite(CaseBreakCheckerTest.class);
|
||||||
// framework
|
// framework
|
||||||
suite.addTest(CodanFastTestSuite.suite());
|
suite.addTest(CodanFastTestSuite.suite());
|
||||||
// quick fixes
|
// quick fixes
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2009, 2010 Alena Laskavaia
|
* Copyright (c) 2009, 2010 Alena Laskavaia
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -27,7 +27,7 @@ import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Alena
|
* @author Alena
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CheckerTestCase extends CodanTestCase {
|
public class CheckerTestCase extends CodanTestCase {
|
||||||
protected IMarker[] markers;
|
protected IMarker[] markers;
|
||||||
|
@ -36,6 +36,13 @@ public class CheckerTestCase extends CodanTestCase {
|
||||||
return checkErrorLine(currentFile, i);
|
return checkErrorLine(currentFile, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkErrorLines( Object... args ) {
|
||||||
|
for( Object i : args ) {
|
||||||
|
checkErrorLine((Integer) i);
|
||||||
|
}
|
||||||
|
assertEquals(args.length, markers.length);
|
||||||
|
}
|
||||||
|
|
||||||
public IMarker checkErrorLine(int i, String problemId) {
|
public IMarker checkErrorLine(int i, String problemId) {
|
||||||
return checkErrorLine(currentFile, i, problemId);
|
return checkErrorLine(currentFile, i, problemId);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +102,7 @@ public class CheckerTestCase extends CodanTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void runOnProject() {
|
public void runOnProject() {
|
||||||
try {
|
try {
|
||||||
|
@ -117,7 +124,7 @@ public class CheckerTestCase extends CodanTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected void runCodan() {
|
protected void runCodan() {
|
||||||
CodanRuntime
|
CodanRuntime
|
||||||
|
|
Loading…
Add table
Reference in a new issue