diff options
Diffstat (limited to 'codan')
13 files changed, 510 insertions, 88 deletions
diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml b/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml index e8e8104b717..9a20fafef4d 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml +++ b/codan/org.eclipse.cdt.codan.checkers.ui/plugin.xml @@ -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> diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractCaseBreakQuickFix.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractCaseBreakQuickFix.java new file mode 100644 index 00000000000..158545758c5 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/AbstractCaseBreakQuickFix.java @@ -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; + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreak.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreak.java index 5eecd182c28..d71fcb15713 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreak.java +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreak.java @@ -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;
}
}
diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttribute.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttribute.java new file mode 100644 index 00000000000..84e373fc9df --- /dev/null +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttribute.java @@ -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; + } +} diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.java b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.java index b0fb468cf8c..9daaa139337 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.java +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.java @@ -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; diff --git a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.properties b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.properties index 421fbd9cdc5..7ca12d59bf9 100644 --- a/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.properties +++ b/codan/org.eclipse.cdt.codan.checkers.ui/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/QuickFixMessages.properties @@ -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 diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CaseBreakChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CaseBreakChecker.java index ddaecb40e9e..c87a33737d9 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CaseBreakChecker.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CaseBreakChecker.java @@ -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 diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java index 8a4ad7e6877..6768898c977 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.java @@ -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; diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties index bc5a2fe5ce8..d76c6c75a29 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/CheckersMessages.properties @@ -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 diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/CaseBreakCheckerTest.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/CaseBreakCheckerTest.java index 3f5f808b8fa..b8c5e878d62 100644 --- a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/CaseBreakCheckerTest.java +++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/CaseBreakCheckerTest.java @@ -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: @@ -199,11 +211,25 @@ public class CaseBreakCheckerTest extends CheckerTestCase { // 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) { + // case 1: // /* no break */ // case 2: // b = 2; // break; // } + // } public void testEmptyCaseOKcomment() throws Exception { loadCodeAndRun(getAboveComment()); checkNoErrorsOfKind(ER_ID); @@ -213,6 +239,21 @@ public class CaseBreakCheckerTest extends CheckerTestCase { // 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) { + // case 1: // b = 2; // /* no break */ // bye(); @@ -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) { @@ -257,6 +313,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase { // 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) { // case 1: //err // // lolo // case 2: //err @@ -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(); } @@ -347,6 +440,36 @@ public class CaseBreakCheckerTest extends CheckerTestCase { // 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) { // case 0: // switch( b ) { // case 2: // err @@ -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); diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/tests/AutomatedIntegrationSuite.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/tests/AutomatedIntegrationSuite.java index 7233b65c959..70089d5a627 100644 --- a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/tests/AutomatedIntegrationSuite.java +++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/tests/AutomatedIntegrationSuite.java @@ -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; } diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixTest.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreakTest.java index bafe92bc2ae..b14884a6e0a 100644 --- a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixTest.java +++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixBreakTest.java @@ -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() {
diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttributeTest.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttributeTest.java new file mode 100644 index 00000000000..23b63dd7551 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/internal/checkers/ui/quickfix/CaseBreakQuickFixFallthroughAttributeTest.java @@ -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); + } +} |