1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +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:
Rolf Bislin 2017-05-02 09:49:27 +02:00 committed by Thomas Corbat
parent 0f27b20848
commit a583190f52
15 changed files with 542 additions and 89 deletions

View file

@ -75,5 +75,9 @@
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixComment"
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
</resolution>
<resolution
class="org.eclipse.cdt.codan.internal.checkers.ui.quickfix.CaseBreakQuickFixFallthroughAttribute"
problemId="org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem">
</resolution>
</extension>
</plugin>

View file

@ -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;
}
}

View file

@ -10,27 +10,15 @@
*******************************************************************************/
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 {
public class CaseBreakQuickFixBreak extends AbstractCaseBreakQuickFix {
@Override
public boolean isApplicable(IMarker marker) {
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0) - 1;
@ -44,75 +32,14 @@ public class CaseBreakQuickFixBreak extends AbstractAstRewriteQuickFix {
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
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 != null && beforeBreak.getParent() instanceof IASTCompoundStatement) {
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());
}
IASTBreakStatement breakStatement = ast.getASTNodeFactory().newBreakStatement();
addNewNodeAtMarkedCaseEnd(breakStatement, ast, marker);
} catch (CoreException 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;
}
}

View file

@ -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;
}
}

View file

@ -15,6 +15,7 @@ import org.eclipse.osgi.util.NLS;
public class QuickFixMessages extends NLS {
public static String CaseBreakQuickFixBreak_Label;
public static String CaseBreakQuickFixComment_Label;
public static String CaseBreakQuickFixFallthroughAttribute_Label;
public static String QuickFixCreateClass_CreateNewClass;
public static String QuickFixCreateField_create_field;
public static String QuickFixCreateLocalVariable_create_local_variable;

View file

@ -10,6 +10,7 @@
###############################################################################
CaseBreakQuickFixBreak_Label=Add break statement
CaseBreakQuickFixComment_Label=Add suppressing comment
CaseBreakQuickFixFallthroughAttribute_Label=Add [[fallthrough]] attribute
QuickFixCreateClass_CreateNewClass=Create new class
QuickFixCreateField_create_field=Create field
QuickFixCreateLocalVariable_create_local_variable=Create local variable

View file

@ -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.IASTSwitchStatement;
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 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 PARAM_ENABLE_FALLTHROUGH_QUICKFIX = "enable_fallthrough_quickfix_param"; //$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 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) {
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
// 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
@ -168,6 +174,30 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
}
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) {
@ -231,6 +261,7 @@ public class CaseBreakChecker extends AbstractIndexAstChecker implements IChecke
DEFAULT_NO_BREAK_COMMENT);
addPreference(problem, PARAM_LAST_CASE, CheckersMessages.CaseBreakChecker_LastCaseDescription, Boolean.FALSE);
addPreference(problem, PARAM_EMPTY_CASE, CheckersMessages.CaseBreakChecker_EmptyCaseDescription, Boolean.FALSE);
addPreference(problem, PARAM_ENABLE_FALLTHROUGH_QUICKFIX, CheckersMessages.CaseBreakChecker_EnableFallthroughQuickfixDescription, Boolean.FALSE);
}
@Override

View file

@ -19,6 +19,7 @@ public class CheckersMessages extends NLS {
public static String CaseBreakChecker_DefaultNoBreakCommentDescription;
public static String CaseBreakChecker_EmptyCaseDescription;
public static String CaseBreakChecker_LastCaseDescription;
public static String CaseBreakChecker_EnableFallthroughQuickfixDescription;
public static String CatchByReference_ReportForUnknownType;
public static String ClassMembersInitializationChecker_SkipConstructorsWithFCalls;
public static String NamingConventionFunctionChecker_LabelNamePattern;

View file

@ -11,6 +11,7 @@
CaseBreakChecker_DefaultNoBreakCommentDescription=Comment text to suppress the problem:
CaseBreakChecker_EmptyCaseDescription=Check also empty 'case' statement (except if last)
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
CatchByReference_ReportForUnknownType=Report a problem if type cannot be resolved
NamingConventionFunctionChecker_LabelNamePattern=Name Pattern

View file

@ -166,6 +166,18 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
// switch (a) {
// case 1:
@ -195,6 +207,19 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
// int a, b;
// switch (a) {
@ -204,11 +229,27 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
// b = 2;
// break;
// }
// }
public void testEmptyCaseOKcomment() throws Exception {
loadCodeAndRun(getAboveComment());
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) {
// int a, b;
// switch (a) {
@ -223,6 +264,21 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
// int a, b;
// switch (a) {
@ -254,6 +310,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
// int a, b;
// switch (a) {
@ -286,15 +372,22 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
// b = 2;
// /* no break */
// case 4:
// b = 2; // err
// b = 2;
// [[fallthrough]];
// case 5:
// b = 2; // err
// case 6:
// b = 2;
// break;
// case 6:
// case 7:
// b = 2;
// /* no break */
// b = 2; //err
// case 7:
// case 8:
// b = 2;
// [[fallthrough]];
// b = 2; //err
// case 9:
// b = 2;//err
// }
//
@ -310,7 +403,7 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
public void testGeneral1() throws Exception {
setEmpty(true);
setLast(true);
loadCodeAndRun(getAboveComment());
loadCodeAndRunCpp(getAboveComment());
checkErrorComments();
}
@ -344,6 +437,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
// int a, b;
// switch (a) {
@ -370,13 +493,23 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
// } // err
// case 5:
// switch( b ) {
// case 2:
// [[fallthrough]]; // err
// } // err
// case 6:
// switch( b ) {
// case 2: // err
// }
// /* no break */
// case 7:
// switch( b ) {
// case 2: // err
// } // err
// [[fallthrough]];
// }
// }
public void testNestedSwitches() throws Exception {
loadCodeAndRun(getAboveComment());
loadCodeAndRunCpp(getAboveComment());
checkErrorComments();
}
@ -429,6 +562,61 @@ public class CaseBreakCheckerTest extends CheckerTestCase {
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) {
IProblemPreference pref = getPreference(CaseBreakChecker.ER_ID, CaseBreakChecker.PARAM_LAST_CASE);
pref.setValue(val);

View file

@ -11,10 +11,6 @@
*******************************************************************************/
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.AssignmentInConditionCheckerTest;
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.UnusedSymbolInFileScopeCheckerTest;
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.CaseBreakQuickFixFallthroughAttributeTest;
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.SuggestedParenthesisQuickFixTest;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class AutomatedIntegrationSuite extends TestSuite {
public AutomatedIntegrationSuite() {
}
@ -81,8 +82,9 @@ public class AutomatedIntegrationSuite extends TestSuite {
suite.addTestSuite(CreateLocalVariableQuickFixTest.class);
suite.addTestSuite(SuggestedParenthesisQuickFixTest.class);
suite.addTestSuite(CatchByReferenceQuickFixTest.class);
suite.addTestSuite(CaseBreakQuickFixTest.class);
suite.addTestSuite(CaseBreakQuickFixBreakTest.class);
suite.addTestSuite(CaseBreakQuickFixCommentTest.class);
suite.addTestSuite(CaseBreakQuickFixFallthroughAttributeTest.class);
suite.addTestSuite(AssignmentInConditionQuickFixTest.class);
return suite;
}

View file

@ -12,7 +12,7 @@ package org.eclipse.cdt.codan.internal.checkers.ui.quickfix;
import org.eclipse.cdt.codan.ui.AbstractCodanCMarkerResolution;
public class CaseBreakQuickFixTest extends QuickFixTestCase {
public class CaseBreakQuickFixBreakTest extends QuickFixTestCase {
@SuppressWarnings("restriction")
@Override
protected AbstractCodanCMarkerResolution createQuickFix() {

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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.IASTAttributeOwner;
import org.eclipse.cdt.core.dom.ast.IASTToken;
import org.eclipse.cdt.core.parser.StandardAttributes;
/**
* Collection of static methods for dealing with attributes.
@ -21,7 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTToken;
* @since 5.4
*/
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.
private AttributeUtil() {}