mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-05 08:46:02 +02:00
Bug 514685 - codan: handle fallthrough attribute
and provide quickfix for adding fallthrough attribute and add JUnit Tests and add StandardAttributes class Change-Id: I8cf0238771dc92bd1784b9dfb35a680d078b1db6 Depends-On: Ic09aa96f896b0a5dd998156e05930704775f695b Signed-off-by: Rolf Bislin <romibi@bluewin.ch> Signed-off-by: Thomas Corbat <tcorbat@hsr.ch>
This commit is contained in:
parent
0f27b20848
commit
a583190f52
15 changed files with 542 additions and 89 deletions
|
@ -75,5 +75,9 @@
|
||||||
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixComment"
|
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixComment"
|
||||||
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
|
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
|
||||||
</resolution>
|
</resolution>
|
||||||
|
<resolution
|
||||||
|
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixFallthroughAttribute"
|
||||||
|
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
|
||||||
|
</resolution>
|
||||||
</extension>
|
</extension>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||||
|
* 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:
|
||||||
|
* Rolf Bislin - Initial implementation
|
||||||
|
* Gil Barash - getStmtBeforeBreak, getStatementAfter
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
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.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.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.IDocument;
|
||||||
|
import org.eclipse.jface.text.IRegion;
|
||||||
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
|
|
||||||
|
abstract public class AbstractCaseBreakQuickFix extends AbstractAstRewriteQuickFix {
|
||||||
|
protected void addNewNodeAtMarkedCaseEnd(IASTNode newnode, IASTTranslationUnit ast, IMarker marker) {
|
||||||
|
try {
|
||||||
|
IASTStatement beforeCaseEnd = getStmtBeforeCaseEnd(marker, ast);
|
||||||
|
if (beforeCaseEnd != null && beforeCaseEnd.getParent() instanceof IASTCompoundStatement) {
|
||||||
|
IASTCompoundStatement enclosingStatement;
|
||||||
|
IASTStatement after;
|
||||||
|
if (beforeCaseEnd instanceof IASTCompoundStatement) {
|
||||||
|
// Case body is enclosed in braces. Add 'break' as last statement inside braces.
|
||||||
|
enclosingStatement = (IASTCompoundStatement) beforeCaseEnd;
|
||||||
|
after = null;
|
||||||
|
} else {
|
||||||
|
enclosingStatement = (IASTCompoundStatement) beforeCaseEnd.getParent();
|
||||||
|
after = getNextStatement(beforeCaseEnd);
|
||||||
|
}
|
||||||
|
ASTRewrite r = ASTRewrite.create(enclosingStatement.getTranslationUnit());
|
||||||
|
r.insertBefore(enclosingStatement, after, newnode, null);
|
||||||
|
Change c = r.rewriteAST();
|
||||||
|
c.perform(new NullProgressMonitor());
|
||||||
|
}
|
||||||
|
} catch (CoreException | BadLocationException e) {
|
||||||
|
CheckersUiActivator.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IASTStatement getStmtBeforeCaseEnd(IMarker marker, IASTTranslationUnit ast) throws BadLocationException {
|
||||||
|
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0) - 1;
|
||||||
|
if (line < 0)
|
||||||
|
return null;
|
||||||
|
IDocument doc = getDocument();
|
||||||
|
if (doc == null)
|
||||||
|
doc = openDocument(marker);
|
||||||
|
IRegion lineInformation = doc.getLineInformation(line);
|
||||||
|
IASTNodeSelector nodeSelector = ast.getNodeSelector(null);
|
||||||
|
IASTNode containedNode = nodeSelector.findFirstContainedNode(lineInformation.getOffset(), lineInformation.getLength());
|
||||||
|
IASTNode beforeCaseEndNode = null;
|
||||||
|
if (containedNode != null) {
|
||||||
|
beforeCaseEndNode = CxxAstUtils.getEnclosingStatement(containedNode);
|
||||||
|
} else {
|
||||||
|
beforeCaseEndNode = nodeSelector.findEnclosingNode(lineInformation.getOffset(), lineInformation.getLength());
|
||||||
|
}
|
||||||
|
if (beforeCaseEndNode instanceof IASTCompoundStatement) {
|
||||||
|
while (beforeCaseEndNode != null) {
|
||||||
|
if (beforeCaseEndNode.getParent() instanceof IASTCompoundStatement
|
||||||
|
&& beforeCaseEndNode.getParent().getParent() instanceof IASTSwitchStatement) {
|
||||||
|
return (IASTStatement) beforeCaseEndNode;
|
||||||
|
}
|
||||||
|
beforeCaseEndNode = beforeCaseEndNode.getParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (beforeCaseEndNode instanceof IASTStatement)
|
||||||
|
return (IASTStatement) beforeCaseEndNode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IASTStatement getNextStatement(IASTStatement beforeStatement) {
|
||||||
|
assert(beforeStatement != null);
|
||||||
|
IASTNode parent = beforeStatement.getParent();
|
||||||
|
if (parent instanceof IASTCompoundStatement) {
|
||||||
|
IASTCompoundStatement enclosingStatement = (IASTCompoundStatement) parent;
|
||||||
|
IASTStatement[] statements = enclosingStatement.getStatements();
|
||||||
|
int indexOfNext = Arrays.asList(statements).indexOf(beforeStatement) + 1;
|
||||||
|
if (indexOfNext < statements.length) {
|
||||||
|
return statements[indexOfNext];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,27 +10,15 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
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.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.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.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
|
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.core.resources.IMarker;
|
import org.eclipse.core.resources.IMarker;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
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 {
|
public class CaseBreakQuickFixBreak extends AbstractCaseBreakQuickFix {
|
||||||
@Override
|
@Override
|
||||||
public boolean isApplicable(IMarker marker) {
|
public boolean isApplicable(IMarker marker) {
|
||||||
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0) - 1;
|
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0) - 1;
|
||||||
|
@ -44,75 +32,14 @@ public class CaseBreakQuickFixBreak extends AbstractAstRewriteQuickFix {
|
||||||
return QuickFixMessages.CaseBreakQuickFixBreak_Label;
|
return QuickFixMessages.CaseBreakQuickFixBreak_Label;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IASTStatement getStmtBeforeBreak(IMarker marker, IASTTranslationUnit ast) throws BadLocationException {
|
|
||||||
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0) - 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.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) {
|
|
||||||
return (IASTStatement) beforeBreakNode;
|
|
||||||
}
|
|
||||||
beforeBreakNode = beforeBreakNode.getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (beforeBreakNode instanceof IASTStatement)
|
|
||||||
return (IASTStatement) beforeBreakNode;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void modifyAST(IIndex index, IMarker marker) {
|
public void modifyAST(IIndex index, IMarker marker) {
|
||||||
try {
|
try {
|
||||||
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker).getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker).getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
||||||
IASTStatement beforeBreak = getStmtBeforeBreak(marker, ast);
|
IASTBreakStatement breakStatement = ast.getASTNodeFactory().newBreakStatement();
|
||||||
if (beforeBreak != null && beforeBreak.getParent() instanceof IASTCompoundStatement) {
|
addNewNodeAtMarkedCaseEnd(breakStatement, ast, marker);
|
||||||
IASTCompoundStatement enclosingStatement;
|
|
||||||
IASTStatement after;
|
|
||||||
if (beforeBreak instanceof IASTCompoundStatement) {
|
|
||||||
// Case body is enclosed in braces. Add 'break' as last statement inside braces.
|
|
||||||
enclosingStatement = (IASTCompoundStatement) beforeBreak;
|
|
||||||
after = null;
|
|
||||||
} else {
|
|
||||||
enclosingStatement = (IASTCompoundStatement) beforeBreak.getParent();
|
|
||||||
after = getStatementAfter(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) {
|
} catch (CoreException e) {
|
||||||
CheckersUiActivator.log(e);
|
CheckersUiActivator.log(e);
|
||||||
} catch (BadLocationException e) {
|
|
||||||
CheckersUiActivator.log(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IASTStatement getStatementAfter(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,74 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||||
|
* 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
|
||||||
|
*******************************************************************************/
|
||||||
|
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.internal.checkers.ui.CheckersUiActivator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTAttributeList;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNullStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.parser.StandardAttributes;
|
||||||
|
import org.eclipse.core.resources.IMarker;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
|
||||||
|
public class CaseBreakQuickFixFallthroughAttribute extends AbstractCaseBreakQuickFix {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(IMarker marker) {
|
||||||
|
IProblem problem = getProblem(marker);
|
||||||
|
RootProblemPreference map = (RootProblemPreference) problem.getPreference();
|
||||||
|
boolean enabled = (boolean) map.getChildValue(CaseBreakChecker.PARAM_ENABLE_FALLTHROUGH_QUICKFIX);
|
||||||
|
boolean last_case_enabled = (boolean) map.getChildValue(CaseBreakChecker.PARAM_LAST_CASE);
|
||||||
|
ITranslationUnit tu = getTranslationUnitViaEditor(marker);
|
||||||
|
return enabled && tu.isCXXLanguage() && (!last_case_enabled || validPositionForFallthrough(marker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLabel() {
|
||||||
|
return QuickFixMessages.CaseBreakQuickFixFallthroughAttribute_Label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyAST(IIndex index, IMarker marker) {
|
||||||
|
try {
|
||||||
|
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker).getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
||||||
|
ICPPNodeFactory factory = (ICPPNodeFactory) ast.getASTNodeFactory();
|
||||||
|
IASTNullStatement nullStatement = factory.newNullStatement();
|
||||||
|
nullStatement.addAttributeSpecifier(getFallthroughAttributeList(factory));
|
||||||
|
addNewNodeAtMarkedCaseEnd(nullStatement, ast, marker);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CheckersUiActivator.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validPositionForFallthrough(IMarker marker) {
|
||||||
|
try {
|
||||||
|
IASTTranslationUnit ast = getTranslationUnitViaEditor(marker).getAST(null, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
||||||
|
IASTStatement beforeCaseEnd = getStmtBeforeCaseEnd(marker, ast);
|
||||||
|
if (getNextStatement(beforeCaseEnd) == null)
|
||||||
|
return false;
|
||||||
|
} catch (CoreException | BadLocationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IASTAttributeList getFallthroughAttributeList(ICPPNodeFactory factory) {
|
||||||
|
IASTAttribute attribute = factory.newAttribute(StandardAttributes.cFALLTHROUGH, null);
|
||||||
|
IASTAttributeList attributeList = factory.newAttributeList();
|
||||||
|
attributeList.addAttribute(attribute);
|
||||||
|
return attributeList;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import org.eclipse.osgi.util.NLS;
|
||||||
public class QuickFixMessages extends NLS {
|
public class QuickFixMessages extends NLS {
|
||||||
public static String CaseBreakQuickFixBreak_Label;
|
public static String CaseBreakQuickFixBreak_Label;
|
||||||
public static String CaseBreakQuickFixComment_Label;
|
public static String CaseBreakQuickFixComment_Label;
|
||||||
|
public static String CaseBreakQuickFixFallthroughAttribute_Label;
|
||||||
public static String QuickFixCreateClass_CreateNewClass;
|
public static String QuickFixCreateClass_CreateNewClass;
|
||||||
public static String QuickFixCreateField_create_field;
|
public static String QuickFixCreateField_create_field;
|
||||||
public static String QuickFixCreateLocalVariable_create_local_variable;
|
public static String QuickFixCreateLocalVariable_create_local_variable;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
###############################################################################
|
###############################################################################
|
||||||
CaseBreakQuickFixBreak_Label=Add break statement
|
CaseBreakQuickFixBreak_Label=Add break statement
|
||||||
CaseBreakQuickFixComment_Label=Add suppressing comment
|
CaseBreakQuickFixComment_Label=Add suppressing comment
|
||||||
|
CaseBreakQuickFixFallthroughAttribute_Label=Add [[fallthrough]] attribute
|
||||||
QuickFixCreateClass_CreateNewClass=Create new class
|
QuickFixCreateClass_CreateNewClass=Create new class
|
||||||
QuickFixCreateField_create_field=Create field
|
QuickFixCreateField_create_field=Create field
|
||||||
QuickFixCreateLocalVariable_create_local_variable=Create local variable
|
QuickFixCreateLocalVariable_create_local_variable=Create local variable
|
||||||
|
|
|
@ -37,12 +37,15 @@ import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.parser.StandardAttributes;
|
||||||
|
import org.eclipse.cdt.core.parser.util.AttributeUtil;
|
||||||
|
|
||||||
public class CaseBreakChecker extends AbstractIndexAstChecker implements ICheckerWithPreferences {
|
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 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_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_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 PARAM_NO_BREAK_COMMENT = "no_break_comment"; //$NON-NLS-1$
|
||||||
|
public static final String PARAM_ENABLE_FALLTHROUGH_QUICKFIX = "enable_fallthrough_quickfix_param"; //$NON-NLS-1$
|
||||||
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 fCheckLastCase; // Should we check the last case in the switch?
|
private boolean fCheckLastCase; // Should we check the last case in the switch?
|
||||||
private boolean fCheckEmptyCase; // Should we check an empty case (a case without any statements within it)
|
private boolean fCheckEmptyCase; // Should we check an empty case (a case without any statements within it)
|
||||||
|
@ -106,6 +109,9 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
if (!fCheckLastCase && next == null) {
|
if (!fCheckLastCase && next == null) {
|
||||||
continue; // Last case and we don't care
|
continue; // Last case and we don't care
|
||||||
}
|
}
|
||||||
|
if (next != null && hasValidFallthroughAttribute(curr)) {
|
||||||
|
continue; // Explicit fallthrough, do not analyse case further (not valid in last case)
|
||||||
|
}
|
||||||
// If this is the null statement, base the decision on the previous statement
|
// If this is the null statement, base the decision on the previous statement
|
||||||
// instead (if there is one). Null statements can sneak in via macros in cases
|
// instead (if there is one). Null statements can sneak in via macros in cases
|
||||||
// where the macro expansion ends in a semicolon, and the macro use is followed
|
// where the macro expansion ends in a semicolon, and the macro use is followed
|
||||||
|
@ -168,6 +174,30 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
}
|
}
|
||||||
return true; // TODO
|
return true; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether {@code statement} (or its last inner statement if it
|
||||||
|
* is a compound statement) is a {@code IASTNullStatement} and has the
|
||||||
|
* C++ standard [[fallthrough]] attribute
|
||||||
|
*
|
||||||
|
* @param statement The {@code IASTStatement} to check
|
||||||
|
* @return {@code true} if the {@code statement} has the [[fallthrough]]
|
||||||
|
* attribute,
|
||||||
|
* {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasValidFallthroughAttribute(IASTStatement statement) {
|
||||||
|
IASTStatement lastStatement = statement;
|
||||||
|
while (lastStatement instanceof IASTCompoundStatement && lastStatement.getChildren().length > 0) {
|
||||||
|
IASTCompoundStatement compoundStatement = (IASTCompoundStatement) lastStatement;
|
||||||
|
IASTStatement[] nestedStatements = compoundStatement.getStatements();
|
||||||
|
lastStatement = nestedStatements[nestedStatements.length - 1];
|
||||||
|
}
|
||||||
|
if (lastStatement instanceof IASTNullStatement) {
|
||||||
|
if (AttributeUtil.hasAttribute(lastStatement, new String[] { StandardAttributes.FALLTHROUGH }))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportProblem(IASTStatement curr) {
|
private void reportProblem(IASTStatement curr) {
|
||||||
|
@ -231,6 +261,7 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
|
||||||
DEFAULT_NO_BREAK_COMMENT);
|
DEFAULT_NO_BREAK_COMMENT);
|
||||||
addPreference(problem, PARAM_LAST_CASE, CheckersMessages.CaseBreakChecker_LastCaseDescription, Boolean.FALSE);
|
addPreference(problem, PARAM_LAST_CASE, CheckersMessages.CaseBreakChecker_LastCaseDescription, Boolean.FALSE);
|
||||||
addPreference(problem, PARAM_EMPTY_CASE, CheckersMessages.CaseBreakChecker_EmptyCaseDescription, Boolean.FALSE);
|
addPreference(problem, PARAM_EMPTY_CASE, CheckersMessages.CaseBreakChecker_EmptyCaseDescription, Boolean.FALSE);
|
||||||
|
addPreference(problem, PARAM_ENABLE_FALLTHROUGH_QUICKFIX, CheckersMessages.CaseBreakChecker_EnableFallthroughQuickfixDescription, Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,6 +19,7 @@ public class CheckersMessages extends NLS {
|
||||||
public static String CaseBreakChecker_DefaultNoBreakCommentDescription;
|
public static String CaseBreakChecker_DefaultNoBreakCommentDescription;
|
||||||
public static String CaseBreakChecker_EmptyCaseDescription;
|
public static String CaseBreakChecker_EmptyCaseDescription;
|
||||||
public static String CaseBreakChecker_LastCaseDescription;
|
public static String CaseBreakChecker_LastCaseDescription;
|
||||||
|
public static String CaseBreakChecker_EnableFallthroughQuickfixDescription;
|
||||||
public static String CatchByReference_ReportForUnknownType;
|
public static String CatchByReference_ReportForUnknownType;
|
||||||
public static String ClassMembersInitializationChecker_SkipConstructorsWithFCalls;
|
public static String ClassMembersInitializationChecker_SkipConstructorsWithFCalls;
|
||||||
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
public static String NamingConventionFunctionChecker_LabelNamePattern;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
CaseBreakChecker_DefaultNoBreakCommentDescription=Comment text to suppress the problem:
|
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
|
||||||
|
CaseBreakChecker_EnableFallthroughQuickfixDescription=Enable quick fix to add fallthrough attribute (C++17)
|
||||||
ClassMembersInitializationChecker_SkipConstructorsWithFCalls=Skip constructors with initialization function calls
|
ClassMembersInitializationChecker_SkipConstructorsWithFCalls=Skip constructors with initialization function calls
|
||||||
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
|
||||||
|
|
|
@ -166,6 +166,18 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkNoErrorsOfKind(ER_ID);
|
checkNoErrorsOfKind(ER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// [[fallthrough]]; // invalid in last case
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyLastCaseBadFallthrough_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkErrorLine(5);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(int a, int b) {
|
// void foo(int a, int b) {
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
// case 1:
|
// case 1:
|
||||||
|
@ -195,6 +207,19 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkNoErrorsOfKind(ER_ID);
|
checkNoErrorsOfKind(ER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseBadFallthrough_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkErrorLine(5);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
@ -204,11 +229,27 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
// }
|
||||||
public void testEmptyCaseOKcomment() throws Exception {
|
public void testEmptyCaseOKcomment() throws Exception {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkNoErrorsOfKind(ER_ID);
|
checkNoErrorsOfKind(ER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// [[fallthrough]];
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testEmptyCaseOKFallthrough_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkNoErrorsOfKind(ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
@ -223,6 +264,21 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkErrorLines(7);
|
checkErrorLines(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void bye() {}
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// bye();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testLastCaseBadFallthroughNotLast_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkErrorLines(8);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
@ -254,6 +310,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkErrorLines(17,23);
|
checkErrorLines(17,23);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// [[ fallthrough ]];
|
||||||
|
// case 3:
|
||||||
|
// b = 2;
|
||||||
|
// [ [ fallthrough ] ] ;
|
||||||
|
// case 4:
|
||||||
|
// b = 2;[[fallthrough]];
|
||||||
|
// case 5:
|
||||||
|
// b = 2;
|
||||||
|
// [[fall]];
|
||||||
|
// case 6:
|
||||||
|
// b = 2;
|
||||||
|
// [[FALLTHROUGH]];
|
||||||
|
// case 7:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testDifferentFallthroughs_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkErrorLines(16, 19, 24);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
@ -286,15 +372,22 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// case 4:
|
// case 4:
|
||||||
// b = 2; // err
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
// case 5:
|
// case 5:
|
||||||
|
// b = 2; // err
|
||||||
|
// case 6:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// break;
|
// break;
|
||||||
// case 6:
|
// case 7:
|
||||||
// b = 2;
|
// b = 2;
|
||||||
// /* no break */
|
// /* no break */
|
||||||
// b = 2; //err
|
// b = 2; //err
|
||||||
// case 7:
|
// case 8:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// b = 2; //err
|
||||||
|
// case 9:
|
||||||
// b = 2;//err
|
// b = 2;//err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -310,7 +403,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
public void testGeneral1() throws Exception {
|
public void testGeneral1() throws Exception {
|
||||||
setEmpty(true);
|
setEmpty(true);
|
||||||
setLast(true);
|
setLast(true);
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
checkErrorComments();
|
checkErrorComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,6 +437,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkErrorLines(9, 14);
|
checkErrorLines(9, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo(void) {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// [[fallthrough]];
|
||||||
|
// case 2:
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// // lolo
|
||||||
|
// case 3:
|
||||||
|
// [[fallthrough]]; // not valid, not last statement
|
||||||
|
// b = 2;
|
||||||
|
// // loo
|
||||||
|
// case 4:
|
||||||
|
// b = 2;
|
||||||
|
// // lolo
|
||||||
|
// [[fallthrough]];
|
||||||
|
// case 5:
|
||||||
|
// // lolo
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]]; // not valid in last case
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testGeneralFallthroughs1_514685() throws Exception {
|
||||||
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
|
checkErrorLines(14, 22);
|
||||||
|
}
|
||||||
|
|
||||||
// void foo(void) {
|
// void foo(void) {
|
||||||
// int a, b;
|
// int a, b;
|
||||||
// switch (a) {
|
// switch (a) {
|
||||||
|
@ -370,13 +493,23 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
// } // err
|
// } // err
|
||||||
// case 5:
|
// case 5:
|
||||||
// switch( b ) {
|
// switch( b ) {
|
||||||
|
// case 2:
|
||||||
|
// [[fallthrough]]; // err
|
||||||
|
// } // err
|
||||||
|
// case 6:
|
||||||
|
// switch( b ) {
|
||||||
// case 2: // err
|
// case 2: // err
|
||||||
// }
|
// }
|
||||||
// /* no break */
|
// /* no break */
|
||||||
|
// case 7:
|
||||||
|
// switch( b ) {
|
||||||
|
// case 2: // err
|
||||||
|
// } // err
|
||||||
|
// [[fallthrough]];
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
public void testNestedSwitches() throws Exception {
|
public void testNestedSwitches() throws Exception {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRunCpp(getAboveComment());
|
||||||
checkErrorComments();
|
checkErrorComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,6 +562,61 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
|
||||||
checkErrorLine(4, ER_ID);
|
checkErrorLine(4, ER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void foo() {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1: {
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// }
|
||||||
|
// case 2: {
|
||||||
|
// b = 2;
|
||||||
|
// }
|
||||||
|
// [[fallthrough]];
|
||||||
|
// case 3: {
|
||||||
|
// {
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// case 4: {
|
||||||
|
// b = 2;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
public void testFallthroughAndCompoundStatementCombinations_514685() throws Exception {
|
||||||
|
String code = getAboveComment();
|
||||||
|
loadCodeAndRunCpp(code);
|
||||||
|
checkNoErrorsOfKind(ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void foo() {
|
||||||
|
// int a, b;
|
||||||
|
// switch (a) {
|
||||||
|
// case 1:
|
||||||
|
// b = 2; // err
|
||||||
|
// [[fallthrough]];
|
||||||
|
// }
|
||||||
|
// switch (a) {
|
||||||
|
// case 1: {
|
||||||
|
// b = 2;
|
||||||
|
// [[fallthrough]];
|
||||||
|
// } // err
|
||||||
|
// }
|
||||||
|
// switch (a) {
|
||||||
|
// case 1: {
|
||||||
|
// b = 2;
|
||||||
|
// } // err
|
||||||
|
// [[fallthrough]];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testBadFallthroughInLastStatement_514685() throws Exception {
|
||||||
|
String code = getAboveComment();
|
||||||
|
loadCodeAndRunCpp(code);
|
||||||
|
checkErrorComments();
|
||||||
|
}
|
||||||
|
|
||||||
private void setLast(boolean val) {
|
private void setLast(boolean val) {
|
||||||
IProblemPreference pref = getPreference(CaseBreakChecker.ER_ID, CaseBreakChecker.PARAM_LAST_CASE);
|
IProblemPreference pref = getPreference(CaseBreakChecker.ER_ID, CaseBreakChecker.PARAM_LAST_CASE);
|
||||||
pref.setValue(val);
|
pref.setValue(val);
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.codan.core.tests;
|
package org.eclipse.cdt.codan.core.tests;
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.core.internal.checkers.AbstractClassInstantiationCheckerTest;
|
import org.eclipse.cdt.codan.core.internal.checkers.AbstractClassInstantiationCheckerTest;
|
||||||
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;
|
||||||
|
@ -33,12 +29,17 @@ import org.eclipse.cdt.codan.core.internal.checkers.SuggestedParenthesisCheckerT
|
||||||
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.AssignmentInConditionQuickFixTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.AssignmentInConditionQuickFixTest;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixBreakTest;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixCommentTest;
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixCommentTest;
|
||||||
|
import org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixFallthroughAttributeTest;
|
||||||
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;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
public class AutomatedIntegrationSuite extends TestSuite {
|
public class AutomatedIntegrationSuite extends TestSuite {
|
||||||
public AutomatedIntegrationSuite() {
|
public AutomatedIntegrationSuite() {
|
||||||
}
|
}
|
||||||
|
@ -81,8 +82,9 @@ 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);
|
suite.addTestSuite(CaseBreakQuickFixBreakTest.class);
|
||||||
suite.addTestSuite(CaseBreakQuickFixCommentTest.class);
|
suite.addTestSuite(CaseBreakQuickFixCommentTest.class);
|
||||||
|
suite.addTestSuite(CaseBreakQuickFixFallthroughAttributeTest.class);
|
||||||
suite.addTestSuite(AssignmentInConditionQuickFixTest.class);
|
suite.addTestSuite(AssignmentInConditionQuickFixTest.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
|
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
|
||||||
|
|
||||||
public class CaseBreakQuickFixTest extends QuickFixTestCase {
|
public class CaseBreakQuickFixBreakTest extends QuickFixTestCase {
|
||||||
@SuppressWarnings("restriction")
|
@SuppressWarnings("restriction")
|
||||||
@Override
|
@Override
|
||||||
protected AbstractCodanCMarkerResolution createQuickFix() {
|
protected AbstractCodanCMarkerResolution createQuickFix() {
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||||
|
* 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
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
|
||||||
|
|
||||||
|
public class CaseBreakQuickFixFallthroughAttributeTest extends QuickFixTestCase {
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
@Override
|
||||||
|
protected AbstractCodanCMarkerResolution createQuickFix() {
|
||||||
|
return new CaseBreakQuickFixFallthroughAttribute();
|
||||||
|
}
|
||||||
|
|
||||||
|
//void hello() {}
|
||||||
|
//void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1:
|
||||||
|
// hello();
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
public void testSimpleCase_514685() throws Exception {
|
||||||
|
loadcode(getAboveComment(), true);
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("[[fallthrough]];\tcase 2:", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//void hello() {}
|
||||||
|
//void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1:
|
||||||
|
// hello();
|
||||||
|
// hello();
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
public void testMultipleStatementsCase_514685() throws Exception {
|
||||||
|
loadcode(getAboveComment(), true);
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("[[fallthrough]];\tcase 2:", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//void hello() {}
|
||||||
|
//void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1: {
|
||||||
|
// hello();
|
||||||
|
// }
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
public void testCompositeCase_514685() throws Exception {
|
||||||
|
loadcode(getAboveComment(), true);
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("[[fallthrough]];\t}\tcase 2:", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//void hello() {}
|
||||||
|
//void func() {
|
||||||
|
// int a;
|
||||||
|
// switch(a) {
|
||||||
|
// case 1: {
|
||||||
|
// {
|
||||||
|
// hello();
|
||||||
|
// {
|
||||||
|
// hello();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// case 2:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
public void testNestedCompositeCase_514685() throws Exception {
|
||||||
|
loadcode(getAboveComment(), true);
|
||||||
|
String result = runQuickFixOneFile();
|
||||||
|
assertContainedIn("[[fallthrough]];\t}\tcase 2:", result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||||
|
* 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
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.core.parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noextend This class is not intended to be subclassed by clients.
|
||||||
|
* @noinstantiate This class is not intended to be instantiated by clients.
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class StandardAttributes {
|
||||||
|
public static final String CARRIES_DEPENDENCY = "carries_dependency";
|
||||||
|
public static final String DEPRECATED = "deprecated";
|
||||||
|
public static final String FALLTHROUGH = "fallthrough";
|
||||||
|
public static final String MAYBE_UNUSED = "maybe_unused";
|
||||||
|
public static final String NODISCARD = "nodiscard";
|
||||||
|
public static final String NORETURN = "noreturn";
|
||||||
|
|
||||||
|
public static final char[] cCARRIES_DEPENDENCY = "carries_dependency".toCharArray();
|
||||||
|
public static final char[] cDEPRECATED = "deprecated".toCharArray();
|
||||||
|
public static final char[] cFALLTHROUGH = "fallthrough".toCharArray();
|
||||||
|
public static final char[] cMAYBE_UNUSED = "maybe_unused".toCharArray();
|
||||||
|
public static final char[] cNODISCARD = "nodiscard".toCharArray();
|
||||||
|
public static final char[] cNORETURN = "noreturn".toCharArray();
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ package org.eclipse.cdt.core.parser.util;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
|
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
|
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTToken;
|
import org.eclipse.cdt.core.dom.ast.IASTToken;
|
||||||
|
import org.eclipse.cdt.core.parser.StandardAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of static methods for dealing with attributes.
|
* Collection of static methods for dealing with attributes.
|
||||||
|
@ -21,7 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTToken;
|
||||||
* @since 5.4
|
* @since 5.4
|
||||||
*/
|
*/
|
||||||
public class AttributeUtil {
|
public class AttributeUtil {
|
||||||
private static final String[] ATTRIBUTE_NORETURN = new String[] { "__noreturn__", "noreturn" }; //$NON-NLS-1$//$NON-NLS-2$
|
private static final String[] ATTRIBUTE_NORETURN = new String[] { "__noreturn__", StandardAttributes.NORETURN }; //$NON-NLS-1$
|
||||||
|
|
||||||
// Not instantiatable.
|
// Not instantiatable.
|
||||||
private AttributeUtil() {}
|
private AttributeUtil() {}
|
||||||
|
|
Loading…
Add table
Reference in a new issue