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:
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"
|
||||
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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
|
@ -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.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() {}
|
||||
|
|
Loading…
Add table
Reference in a new issue