mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 352221 - Quick Fix for "case break" checker
This commit is contained in:
parent
53e62ebcc5
commit
6f2671b1ee
13 changed files with 345 additions and 68 deletions
|
@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.ui,
|
||||||
org.eclipse.cdt.core,
|
org.eclipse.cdt.core,
|
||||||
org.eclipse.cdt.codan.core.cxx,
|
org.eclipse.cdt.codan.core.cxx,
|
||||||
org.eclipse.cdt.codan.ui.cxx,
|
org.eclipse.cdt.codan.ui.cxx,
|
||||||
org.eclipse.cdt.codan.core
|
org.eclipse.cdt.codan.core,
|
||||||
|
org.eclipse.cdt.codan.checkers
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||||
Bundle-Vendor: %Bundle-Vendor
|
Bundle-Vendor: %Bundle-Vendor
|
||||||
|
|
|
@ -37,6 +37,15 @@
|
||||||
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixCreateParameter"
|
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.QuickFixCreateParameter"
|
||||||
problemId="org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem">
|
problemId="org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem">
|
||||||
</resolution>
|
</resolution>
|
||||||
|
<resolution
|
||||||
|
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixBreak"
|
||||||
|
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
|
||||||
|
</resolution>
|
||||||
|
<resolution
|
||||||
|
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixComment"
|
||||||
|
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
|
||||||
|
</resolution>
|
||||||
|
|
||||||
</extension>
|
</extension>
|
||||||
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 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.ui.quickfix;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
||||||
|
import org.eclipse.cdt.codan.internal.checkers.ui.CheckersUiActivator;
|
||||||
|
import org.eclipse.cdt.codan.ui.AbstractAstRewriteQuickFix;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.core.resources.IMarker;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.IRegion;
|
||||||
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
|
|
||||||
|
public class CaseBreakQuickFixBreak extends AbstractAstRewriteQuickFix {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(IMarker marker) {
|
||||||
|
int line = marker.getAttribute(IMarker.LINE_NUMBER, -1) - 1;
|
||||||
|
if (line < 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return Messages.CaseBreakQuickFixBreak_Label;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IASTStatement getStmtBeforeBreak(IMarker marker, IASTTranslationUnit ast) throws BadLocationException {
|
||||||
|
int line = marker.getAttribute(IMarker.LINE_NUMBER, -1) - 1;
|
||||||
|
if (line < 0)
|
||||||
|
return null;
|
||||||
|
IRegion lineInformation = getDocument().getLineInformation(line);
|
||||||
|
IASTNodeSelector nodeSelector = ast.getNodeSelector(null);
|
||||||
|
IASTNode containedNode = nodeSelector.findFirstContainedNode(lineInformation.getOffset(), lineInformation.getLength());
|
||||||
|
IASTNode beforeBreakNode = null;
|
||||||
|
if (containedNode != null)
|
||||||
|
beforeBreakNode = CxxAstUtils.getInstance().getEnclosingStatement(containedNode);
|
||||||
|
else
|
||||||
|
beforeBreakNode = nodeSelector.findEnclosingNode(lineInformation.getOffset(), lineInformation.getLength());
|
||||||
|
if (beforeBreakNode instanceof IASTCompoundStatement) {
|
||||||
|
while (beforeBreakNode != null) {
|
||||||
|
if (beforeBreakNode.getParent() instanceof IASTCompoundStatement
|
||||||
|
&& beforeBreakNode.getParent().getParent() instanceof IASTSwitchStatement) {
|
||||||
|
if (beforeBreakNode instanceof IASTCompoundStatement) {
|
||||||
|
IASTStatement[] statements = ((IASTCompoundStatement) beforeBreakNode).getStatements();
|
||||||
|
return statements[statements.length - 1]; // return last one
|
||||||
|
}
|
||||||
|
return (IASTStatement) beforeBreakNode;
|
||||||
|
}
|
||||||
|
beforeBreakNode = beforeBreakNode.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (beforeBreakNode instanceof IASTStatement)
|
||||||
|
return (IASTStatement) beforeBreakNode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyAST(IIndex index, IMarker marker) {
|
||||||
|
try {
|
||||||
|
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker).getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
||||||
|
IASTStatement beforeBreak = getStmtBeforeBreak(marker, ast);
|
||||||
|
if (beforeBreak.getParent() instanceof IASTCompoundStatement) {
|
||||||
|
IASTCompoundStatement enclosingStatement = (IASTCompoundStatement) beforeBreak.getParent();
|
||||||
|
IASTStatement after = getAfterStatement(beforeBreak);
|
||||||
|
ASTRewrite r = ASTRewrite.create(enclosingStatement.getTranslationUnit());
|
||||||
|
IASTBreakStatement breakStatement = ast.getASTNodeFactory().newBreakStatement();
|
||||||
|
r.insertBefore(enclosingStatement, after, breakStatement, null);
|
||||||
|
Change c = r.rewriteAST();
|
||||||
|
c.perform(new NullProgressMonitor());
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CheckersUiActivator.log(e);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
CheckersUiActivator.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IASTStatement getAfterStatement(IASTStatement beforeBreak) {
|
||||||
|
IASTCompoundStatement enclosingStatement = (IASTCompoundStatement) beforeBreak.getParent();
|
||||||
|
IASTStatement after = null;
|
||||||
|
IASTStatement[] statements = enclosingStatement.getStatements();
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
IASTStatement st = statements[i];
|
||||||
|
if (st == beforeBreak) {
|
||||||
|
if (i < statements.length - 1) {
|
||||||
|
after = statements[i + 1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return after;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.core.model.IProblem;
|
||||||
|
import org.eclipse.cdt.codan.core.param.RootProblemPreference;
|
||||||
|
import org.eclipse.cdt.codan.internal.checkers.CaseBreakChecker;
|
||||||
|
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
|
||||||
|
import org.eclipse.core.resources.IMarker;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.eclipse.jface.text.IRegion;
|
||||||
|
import org.eclipse.text.edits.InsertEdit;
|
||||||
|
import org.eclipse.text.edits.MalformedTreeException;
|
||||||
|
|
||||||
|
public class CaseBreakQuickFixComment extends AbstractCodanCMarkerResolution {
|
||||||
|
public String getLabel() {
|
||||||
|
return Messages.CaseBreakQuickFixComment_Label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(IMarker marker, IDocument document) {
|
||||||
|
try {
|
||||||
|
int line = marker.getAttribute(IMarker.LINE_NUMBER, -1);
|
||||||
|
if (line < 0)
|
||||||
|
return;
|
||||||
|
int offset = document.getLineOffset(line);
|
||||||
|
String indent = getIndentationStr(document, line);
|
||||||
|
String comment = getNoBreakComment(marker);
|
||||||
|
String editStr = String.format("%s/* %s */\n", indent, comment);//$NON-NLS-1$
|
||||||
|
InsertEdit edit = new InsertEdit(offset, editStr);
|
||||||
|
edit.apply(document);
|
||||||
|
} catch (MalformedTreeException e) {
|
||||||
|
return;
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getIndentationStr(IDocument document, int line) throws BadLocationException {
|
||||||
|
int prevLine = line - 1;
|
||||||
|
IRegion lineInformation = document.getLineInformation(prevLine);
|
||||||
|
String prevLineStr = document.get(lineInformation.getOffset(), lineInformation.getLength());
|
||||||
|
int nonSpace = prevLineStr.indexOf(prevLineStr.trim());
|
||||||
|
String indent = prevLineStr.substring(0, nonSpace);
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getNoBreakComment(IMarker marker) {
|
||||||
|
IProblem problem = getProblem(marker);
|
||||||
|
RootProblemPreference map = (RootProblemPreference) problem.getPreference();
|
||||||
|
String comment = (String) map.getChildValue(CaseBreakChecker.PARAM_NO_BREAK_COMMENT);
|
||||||
|
if (comment == null || comment.trim().length() == 0)
|
||||||
|
comment = "no break"; //$NON-NLS-1$
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import org.eclipse.osgi.util.NLS;
|
||||||
|
|
||||||
public class Messages extends NLS {
|
public class Messages extends NLS {
|
||||||
private static final String BUNDLE_NAME = "org.eclipse.cdt.codan.internal.checkers.ui.quickfix.messages"; //$NON-NLS-1$
|
private static final String BUNDLE_NAME = "org.eclipse.cdt.codan.internal.checkers.ui.quickfix.messages"; //$NON-NLS-1$
|
||||||
|
public static String CaseBreakQuickFixBreak_Label;
|
||||||
|
public static String CaseBreakQuickFixComment_Label;
|
||||||
public static String QuickFixCreateField_0;
|
public static String QuickFixCreateField_0;
|
||||||
public static String QuickFixCreateLocalVariable_0;
|
public static String QuickFixCreateLocalVariable_0;
|
||||||
public static String QuickFixCreateParameter_0;
|
public static String QuickFixCreateParameter_0;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
CaseBreakQuickFixBreak_Label=Add break statement
|
||||||
|
CaseBreakQuickFixComment_Label=Add supressing comment
|
||||||
QuickFixCreateField_0=Create field
|
QuickFixCreateField_0=Create field
|
||||||
QuickFixCreateLocalVariable_0=Create local variable
|
QuickFixCreateLocalVariable_0=Create local variable
|
||||||
QuickFixCreateParameter_0=Create parameter
|
QuickFixCreateParameter_0=Create parameter
|
|
@ -1,10 +1,10 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2010,2011 Gil Barash
|
* Copyright (c) 2010,2011 Gil Barash
|
||||||
* 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
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Gil Barash - Initial implementation
|
* Gil Barash - Initial implementation
|
||||||
* Elena laskavaia - Rewrote checker to reduce false positives in complex cases
|
* Elena laskavaia - Rewrote checker to reduce false positives in complex cases
|
||||||
|
@ -14,6 +14,8 @@ package org.eclipse.cdt.codan.internal.checkers;
|
||||||
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
||||||
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
||||||
import org.eclipse.cdt.codan.core.model.ICheckerWithPreferences;
|
import org.eclipse.cdt.codan.core.model.ICheckerWithPreferences;
|
||||||
|
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
||||||
|
import org.eclipse.cdt.codan.core.model.IProblemLocationFactory;
|
||||||
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
||||||
|
@ -23,9 +25,11 @@ import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTContinueStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
|
@ -40,7 +44,10 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
public static final String DEFAULT_NO_BREAK_COMMENT = "no break"; //$NON-NLS-1$
|
public static final String DEFAULT_NO_BREAK_COMMENT = "no break"; //$NON-NLS-1$
|
||||||
private Boolean _checkLastCase; // Should we check the last case in the switch?
|
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 Boolean _checkEmptyCase; // Should we check an empty case (a case without any statements within it)
|
||||||
private String _noBreakComment; // The comment suppressing this warning
|
private String _noBreakComment; // The comment suppressing this warning
|
||||||
|
|
||||||
|
public CaseBreakChecker() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This visitor looks for "switch" statements and invokes "SwitchVisitor" on
|
* This visitor looks for "switch" statements and invokes "SwitchVisitor" on
|
||||||
|
@ -72,7 +79,7 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTStatement statement) {
|
public int visit(IASTStatement statement) {
|
||||||
if (statement instanceof IASTSwitchStatement && !isProducedMyMacroExpansion(statement)) {
|
if (statement instanceof IASTSwitchStatement && !isProducedByMacroExpansion(statement)) {
|
||||||
IASTSwitchStatement switchStmt = (IASTSwitchStatement) statement;
|
IASTSwitchStatement switchStmt = (IASTSwitchStatement) statement;
|
||||||
IASTStatement body = switchStmt.getBody();
|
IASTStatement body = switchStmt.getBody();
|
||||||
if (body instanceof IASTCompoundStatement) {
|
if (body instanceof IASTCompoundStatement) {
|
||||||
|
@ -110,10 +117,10 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
}
|
}
|
||||||
if (comment != null) {
|
if (comment != null) {
|
||||||
String str = getTrimmedComment(comment);
|
String str = getTrimmedComment(comment);
|
||||||
if (str.equalsIgnoreCase(_noBreakComment))
|
if (str.toLowerCase().contains(_noBreakComment.toLowerCase()))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
reportProblem(ER_ID, prevCase, (Object) null);
|
reportProblem(curr, prevCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,13 +143,13 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean isFallThroughStamement(IASTStatement body) {
|
public boolean isFallThroughStamement(IASTStatement body) {
|
||||||
if (body == null) return true;
|
if (body == null)
|
||||||
|
return true;
|
||||||
if (body instanceof IASTCompoundStatement) {
|
if (body instanceof IASTCompoundStatement) {
|
||||||
IASTStatement[] statements = ((IASTCompoundStatement) body).getStatements();
|
IASTStatement[] statements = ((IASTCompoundStatement) body).getStatements();
|
||||||
if (statements.length > 0) {
|
if (statements.length > 0) {
|
||||||
return isFallThroughStamement(statements[statements.length - 1]);
|
return isFallThroughStamement(statements[statements.length - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (isBreakOrExitStatement(body)) {
|
} else if (isBreakOrExitStatement(body)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -150,26 +157,36 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
return true;
|
return true;
|
||||||
} else if (body instanceof IASTIfStatement) {
|
} else if (body instanceof IASTIfStatement) {
|
||||||
IASTIfStatement ifs = (IASTIfStatement) body;
|
IASTIfStatement ifs = (IASTIfStatement) body;
|
||||||
return isFallThroughStamement(ifs.getThenClause()) || isFallThroughStamement(ifs.getElseClause()) ;
|
return isFallThroughStamement(ifs.getThenClause()) || isFallThroughStamement(ifs.getElseClause());
|
||||||
}
|
}
|
||||||
return true; // TODO
|
return true; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given statement is a result of macro expansion with a possible
|
|
||||||
* exception for the trailing semicolon.
|
|
||||||
*
|
|
||||||
* @param statement the statement to check.
|
|
||||||
* @return <code>true</code> if the statement is a result of macro expansion
|
|
||||||
*/
|
|
||||||
private boolean isProducedMyMacroExpansion(IASTStatement statement) {
|
|
||||||
IASTNodeLocation[] locations = statement.getNodeLocations();
|
|
||||||
return locations.length > 0 && locations[0] instanceof IASTMacroExpansionLocation &&
|
|
||||||
(locations.length == 1 || locations.length == 2 && locations[1].getNodeLength() == 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaseBreakChecker() {
|
public void reportProblem(IASTStatement curr, IASTStatement prevCase) {
|
||||||
|
reportProblem(ER_ID, getProblemLocationAtEndOfNode(curr));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IProblemLocation getProblemLocationAtEndOfNode(IASTNode astNode) {
|
||||||
|
IASTFileLocation astLocation = astNode.getFileLocation();
|
||||||
|
int line = astLocation.getEndingLineNumber();
|
||||||
|
IProblemLocationFactory locFactory = getRuntime().getProblemLocationFactory();
|
||||||
|
return locFactory.createProblemLocation(getFile(), -1,
|
||||||
|
-1, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given statement is a result of macro expansion with a
|
||||||
|
* possible
|
||||||
|
* exception for the trailing semicolon.
|
||||||
|
*
|
||||||
|
* @param statement the statement to check.
|
||||||
|
* @return <code>true</code> if the statement is a result of macro expansion
|
||||||
|
*/
|
||||||
|
private boolean isProducedByMacroExpansion(IASTStatement statement) {
|
||||||
|
IASTNodeLocation[] locations = statement.getNodeLocations();
|
||||||
|
return locations.length > 0 && locations[0] instanceof IASTMacroExpansionLocation
|
||||||
|
&& (locations.length == 1 || locations.length == 2 && locations[1].getNodeLength() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# 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_DefaultNoBreakCommentDescription=Comment text to suppress the problem:
|
||||||
CaseBreakChecker_EmptyCaseDescription=Check also empty case statement (except if last)
|
CaseBreakChecker_EmptyCaseDescription=Check also empty case statement (except if last)
|
||||||
CaseBreakChecker_LastCaseDescription=Check also the last case statement
|
CaseBreakChecker_LastCaseDescription=Check also the last case statement
|
||||||
ClassMembersInitializationChecker_SkipConstructorsWithFCalls=Skip constructors with initialization function calls
|
ClassMembersInitializationChecker_SkipConstructorsWithFCalls=Skip constructors with initialization function calls
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// }
|
// }
|
||||||
public void testLastCaseBad() {
|
public void testLastCaseBad() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(4);
|
checkErrorLines(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -181,7 +181,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// }
|
// }
|
||||||
public void testEmptyLastCaseTwoSwitches() {
|
public void testEmptyLastCaseTwoSwitches() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(3);
|
checkErrorLines(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -222,7 +222,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// }
|
// }
|
||||||
public void testLastCaseBadCommentNotLast() {
|
public void testLastCaseBadCommentNotLast() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(4);
|
checkErrorLines(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -246,70 +246,74 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// case 6:
|
// case 6:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// /* no break1 */
|
// /* no break1 */
|
||||||
|
// case 7:
|
||||||
|
// b = 2;
|
||||||
|
// /* fallthrough */
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public void testDifferentComments() {
|
public void testDifferentComments() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(16, 19);
|
checkErrorLines(17,23);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 1:
|
// case 1: //err
|
||||||
// // lolo
|
// // lolo
|
||||||
// case 2:
|
// case 2: //err
|
||||||
// case 3:
|
// case 3://err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 1:
|
// case 1:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// // lolo
|
// // lolo
|
||||||
// case 2:
|
// case 2:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// case 3:
|
// case 3: // err
|
||||||
// case 4:
|
// case 4:
|
||||||
// break;
|
// break;
|
||||||
// case 5:
|
// case 5: // err
|
||||||
// case 6:
|
// case 6: // err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 1:
|
// case 1:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// // lolo
|
// // lolo
|
||||||
// case 2:
|
// case 2:
|
||||||
// b = 2;
|
// b = 2; //err
|
||||||
// case 3:
|
// case 3:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// case 4:
|
// case 4:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// case 5:
|
// case 5:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// break;
|
// break;
|
||||||
// case 6:
|
// case 6:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// b = 2;
|
// b = 2; //err
|
||||||
// case 7:
|
// case 7:
|
||||||
// b = 2;
|
// b = 2;//err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 1:
|
// case 1:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// // lolo
|
// // lolo
|
||||||
// case 2:
|
// case 2:
|
||||||
// b = 2;
|
// b = 2; // err
|
||||||
// default:
|
// default: //err
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public void testGeneral1() {
|
public void testGeneral1() {
|
||||||
setEmpty(true);
|
setEmpty(true);
|
||||||
|
setLast(true);
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(4, 6, 7, 11, 14, 16, 19, 20, 24, 27, 32, 37, 41, 46, 49, 51);
|
checkErrorComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -339,7 +343,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// }
|
// }
|
||||||
public void testGeneralComments1() {
|
public void testGeneralComments1() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(8, 12);
|
checkErrorLines(9, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -347,14 +351,14 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 0:
|
// case 0:
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
// case 2:
|
// case 2: // err
|
||||||
// }
|
// } // err
|
||||||
//
|
//
|
||||||
// case 1:
|
// case 1:
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
// case 2:
|
// case 2:
|
||||||
// break;
|
// break;
|
||||||
// }
|
// } // err
|
||||||
// case 3:
|
// case 3:
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
// case 2:
|
// case 2:
|
||||||
|
@ -365,17 +369,17 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
// case 2:
|
// case 2:
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// }
|
// } // err
|
||||||
// case 5:
|
// case 5:
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
// case 2:
|
// case 2: // err
|
||||||
// }
|
// }
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public void testNestedSwitches() {
|
public void testNestedSwitches() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(4, 20, 6, 9, 27);
|
checkErrorComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
|
@ -441,16 +445,16 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// switch( a ) {
|
// switch( a ) {
|
||||||
// case 1:
|
// case 1:
|
||||||
// while (a--)
|
// while (a--)
|
||||||
// break;
|
// break; // err
|
||||||
// case 2:
|
// case 2:
|
||||||
// while (a--) {
|
// while (a--) {
|
||||||
// break;
|
// break;
|
||||||
// }
|
// } // err
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public void testEmptyCaseWithLoopBreak() {
|
public void testEmptyCaseWithLoopBreak() {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLines(3, 6);
|
checkErrorComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void foo(int a) {
|
// void foo(int a) {
|
||||||
|
@ -518,7 +522,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
public void testIfErr() {
|
public void testIfErr() {
|
||||||
String code = getAboveComment();
|
String code = getAboveComment();
|
||||||
loadCodeAndRun(code);
|
loadCodeAndRun(code);
|
||||||
checkErrorLine(3);
|
checkErrorLine(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define DEFINE_BREAK {break;}
|
// #define DEFINE_BREAK {break;}
|
||||||
|
@ -568,6 +572,6 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
public void testEmptyCompoundStatement() {
|
public void testEmptyCompoundStatement() {
|
||||||
String code = getAboveComment();
|
String code = getAboveComment();
|
||||||
loadCodeAndRun(code);
|
loadCodeAndRun(code);
|
||||||
checkErrorLine(4);
|
checkErrorLine(6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.cdt.codan.core.internal.checkers.StatementHasNoEffectCheckerT
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.SuggestedParenthesisCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.SuggestedParenthesisCheckerTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.SuspiciousSemicolonCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.SuspiciousSemicolonCheckerTest;
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.UnusedSymbolInFileScopeCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.UnusedSymbolInFileScopeCheckerTest;
|
||||||
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixTest;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CatchByReferenceQuickFixTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CatchByReferenceQuickFixTest;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CreateLocalVariableQuickFixTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CreateLocalVariableQuickFixTest;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.SuggestedParenthesisQuickFixTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.SuggestedParenthesisQuickFixTest;
|
||||||
|
@ -74,6 +75,7 @@ public class AutomatedIntegrationSuite extends TestSuite {
|
||||||
suite.addTestSuite(CreateLocalVariableQuickFixTest.class);
|
suite.addTestSuite(CreateLocalVariableQuickFixTest.class);
|
||||||
suite.addTestSuite(SuggestedParenthesisQuickFixTest.class);
|
suite.addTestSuite(SuggestedParenthesisQuickFixTest.class);
|
||||||
suite.addTestSuite(CatchByReferenceQuickFixTest.class);
|
suite.addTestSuite(CatchByReferenceQuickFixTest.class);
|
||||||
|
suite.addTestSuite(CaseBreakQuickFixTest.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
* method to get source directory for the tests,
|
* method to get source directory for the tests,
|
||||||
* default is "src". To make it read comment from java class, you need to
|
* default is "src". To make it read comment from java class, you need to
|
||||||
* include this source directory (with test java files) into the build bundle.
|
* include this source directory (with test java files) into the build bundle.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("nls")
|
@SuppressWarnings("nls")
|
||||||
public class CheckerTestCase extends CodanTestCase {
|
public class CheckerTestCase extends CodanTestCase {
|
||||||
|
@ -50,6 +50,13 @@ public class CheckerTestCase extends CodanTestCase {
|
||||||
assertEquals(args.length, markers.length);
|
assertEquals(args.length, markers.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkErrorComments() {
|
||||||
|
for (Object i : errLines) {
|
||||||
|
checkErrorLine((Integer) i);
|
||||||
|
}
|
||||||
|
assertEquals("Expected number of errors "+errLines.size(),errLines.size(), 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);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +89,7 @@ public class CheckerTestCase extends CodanTestCase {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertEquals(Integer.valueOf(expectedLine), line);
|
assertEquals("Error on line "+expectedLine+" is not found",Integer.valueOf(expectedLine), line);
|
||||||
if (file != null)
|
if (file != null)
|
||||||
assertEquals(file.getName(), mfile);
|
assertEquals(file.getName(), mfile);
|
||||||
assertTrue(found);
|
assertTrue(found);
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.codan.core.test;
|
package org.eclipse.cdt.codan.core.test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.IPDOMManager;
|
import org.eclipse.cdt.core.dom.IPDOMManager;
|
||||||
import org.eclipse.cdt.core.model.CModelException;
|
import org.eclipse.cdt.core.model.CModelException;
|
||||||
|
@ -30,12 +36,6 @@ import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
import org.eclipse.core.runtime.Plugin;
|
import org.eclipse.core.runtime.Plugin;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: add description
|
* TODO: add description
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +47,7 @@ public class CodanTestCase extends BaseTestCase {
|
||||||
protected File currentFile;
|
protected File currentFile;
|
||||||
protected ICElement currentCElem;
|
protected ICElement currentCElem;
|
||||||
protected IFile currentIFile;
|
protected IFile currentIFile;
|
||||||
|
protected ArrayList<Integer> errLines= new ArrayList<Integer>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -220,7 +221,9 @@ public class CodanTestCase extends BaseTestCase {
|
||||||
private File loadcode(String code, File testFile) {
|
private File loadcode(String code, File testFile) {
|
||||||
try {
|
try {
|
||||||
tempFiles.add(testFile);
|
tempFiles.add(testFile);
|
||||||
TestUtils.saveFile(new ByteArrayInputStream(code.trim().getBytes()), testFile);
|
String trim = code.trim();
|
||||||
|
loadErrorComments(trim);
|
||||||
|
TestUtils.saveFile(new ByteArrayInputStream(trim.getBytes()), testFile);
|
||||||
currentFile = testFile;
|
currentFile = testFile;
|
||||||
try {
|
try {
|
||||||
cproject.getProject().refreshLocal(1, null);
|
cproject.getProject().refreshLocal(1, null);
|
||||||
|
@ -240,6 +243,17 @@ public class CodanTestCase extends BaseTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadErrorComments(String trim) {
|
||||||
|
String[] lines = trim.split("\n");
|
||||||
|
for (int i = 0; i < lines.length; i++) {
|
||||||
|
String string = lines[i];
|
||||||
|
if (string.matches(".*//\\s*err\\s*")) {
|
||||||
|
|
||||||
|
errLines.add(i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public File loadcode_c(String code) {
|
public File loadcode_c(String code) {
|
||||||
return loadcode(code, true);
|
return loadcode(code, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class CaseBreakQuickFixTest extends QuickFixTestCase {
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
@Override
|
||||||
|
protected AbstractCodanCMarkerResolution createQuickFix() {
|
||||||
|
return new CaseBreakQuickFixBreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1:
|
||||||
|
// hello();
|
||||||
|
// case 2:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testMiddleCase() {
|
||||||
|
loadcode(getAboveComment());
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("break; case 2:", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1:
|
||||||
|
// hello();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCase() {
|
||||||
|
loadcode(getAboveComment());
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("break; }", result);
|
||||||
|
}
|
||||||
|
// void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1: {
|
||||||
|
// hello();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseComp() {
|
||||||
|
loadcode(getAboveComment());
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("hello(); break;", result);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue