mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-21 21:52:10 +02:00
Bug 534420 - Added check for nodiscard for classes and enums
Change-Id: I3932f4d23f18f96f8d1c15c18d7d4d991154aca1
This commit is contained in:
parent
77790012cc
commit
dd88f8ffca
2 changed files with 92 additions and 6 deletions
|
@ -28,14 +28,20 @@ import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IFunction;
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionCall;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionCall;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalTypeId;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalTypeId;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||||
|
|
||||||
public class NoDiscardChecker extends AbstractAstFunctionChecker {
|
public class NoDiscardChecker extends AbstractAstFunctionChecker {
|
||||||
public static final String ER_ID = "org.eclipse.cdt.codan.internal.checkers.NoDiscardProblem"; //$NON-NLS-1$
|
public static final String ER_ID = "org.eclipse.cdt.codan.internal.checkers.NoDiscardProblem"; //$NON-NLS-1$
|
||||||
|
@ -101,13 +107,18 @@ public class NoDiscardChecker extends AbstractAstFunctionChecker {
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
IBinding binding = name.resolveBinding();
|
|
||||||
|
|
||||||
|
if (expr instanceof ICPPASTExpression) {
|
||||||
|
if (checkEvaluation((ICPPASTExpression) expr)) {
|
||||||
|
return Optional.of(name);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For C, the only thing we need to check is IFunction
|
||||||
|
IBinding binding = name.resolveBinding();
|
||||||
if (binding instanceof IFunction && ((IFunction) binding).isNoDiscard()) {
|
if (binding instanceof IFunction && ((IFunction) binding).isNoDiscard()) {
|
||||||
return Optional.of(name);
|
return Optional.of(name);
|
||||||
} else if ((binding instanceof ICPPClassType || binding instanceof ICPPVariable)
|
|
||||||
&& expr instanceof ICPPASTExpression && checkEvaluation((ICPPASTExpression) expr)) {
|
|
||||||
return Optional.of(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
@ -138,8 +149,24 @@ public class NoDiscardChecker extends AbstractAstFunctionChecker {
|
||||||
}
|
}
|
||||||
} else if (eval instanceof EvalFunctionCall) {
|
} else if (eval instanceof EvalFunctionCall) {
|
||||||
ICPPFunction evalFunc = ((EvalFunctionCall) eval).resolveFunctionBinding();
|
ICPPFunction evalFunc = ((EvalFunctionCall) eval).resolveFunctionBinding();
|
||||||
if (evalFunc != null && evalFunc.isNoDiscard()) {
|
if (evalFunc == null)
|
||||||
|
return false;
|
||||||
|
if (evalFunc.isNoDiscard()) {
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
ICPPFunctionType fType = evalFunc.getType();
|
||||||
|
IType retType = SemanticUtil.getNestedType(fType.getReturnType(), SemanticUtil.TDEF);
|
||||||
|
if (CPPTemplates.isDependentType(retType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (retType instanceof ICPPReferenceType || retType instanceof IPointerType)
|
||||||
|
return false;
|
||||||
|
retType = SemanticUtil.getUltimateType(retType, true);
|
||||||
|
if (retType instanceof ICPPClassType) {
|
||||||
|
return ((ICPPClassType) retType).isNoDiscard();
|
||||||
|
} else if (retType instanceof ICPPEnumeration) {
|
||||||
|
return ((ICPPEnumeration) retType).isNoDiscard();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -12,6 +12,7 @@ package org.eclipse.cdt.codan.core.internal.checkers;
|
||||||
|
|
||||||
import org.eclipse.cdt.codan.core.tests.CheckerTestCase;
|
import org.eclipse.cdt.codan.core.tests.CheckerTestCase;
|
||||||
import org.eclipse.cdt.codan.internal.checkers.NoDiscardChecker;
|
import org.eclipse.cdt.codan.internal.checkers.NoDiscardChecker;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link NoDiscardChecker} class
|
* Test for {@link NoDiscardChecker} class
|
||||||
|
@ -384,4 +385,62 @@ public class NoDiscardCheckerTest extends CheckerTestCase {
|
||||||
loadCodeAndRun(getAboveComment());
|
loadCodeAndRun(getAboveComment());
|
||||||
checkErrorLine(6, ER_ID);
|
checkErrorLine(6, ER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//struct [[nodiscard]] error_info { };
|
||||||
|
//error_info enable_missile_safety_mode();
|
||||||
|
//void launch_missiles();
|
||||||
|
//void test_missiles() {
|
||||||
|
// enable_missile_safety_mode();
|
||||||
|
// launch_missiles();
|
||||||
|
//}
|
||||||
|
public void testClassNoDiscardType() throws Exception {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLine(5, ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct [[nodiscard]] error_type {};
|
||||||
|
//error_info& foo();
|
||||||
|
//void f1() {
|
||||||
|
// foo();
|
||||||
|
//}
|
||||||
|
public void testClassNoDiscardTypesByRef() throws Exception {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrorsOfKind(ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct [[nodiscard]] error_type { error_type(int) {} };
|
||||||
|
//template<class T>
|
||||||
|
//typename T::E foo() {return static_cast<typename T::E>(0);}
|
||||||
|
//template<class F>
|
||||||
|
//struct trait { typedef typename F E; }
|
||||||
|
//void f1() {
|
||||||
|
// foo<trait<error_type>>();
|
||||||
|
//}
|
||||||
|
public void testClassNoDiscardTypesTemplate() throws Exception {
|
||||||
|
CPPASTNameBase.sAllowNameComputation = true;
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrorsOfKind(ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//enum [[nodiscard]] error_type { FAILURE };
|
||||||
|
//error_type enable_missile_safety_mode();
|
||||||
|
//void launch_missiles();
|
||||||
|
//void test_missiles() {
|
||||||
|
// enable_missile_safety_mode();
|
||||||
|
// launch_missiles();
|
||||||
|
//}
|
||||||
|
public void testEnumNoDiscardType() throws Exception {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkErrorLine(5, ER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//enum [[nodiscard]] error_type { FAILURE };
|
||||||
|
//error_type& foo();
|
||||||
|
//void f1() {
|
||||||
|
// foo();
|
||||||
|
//}
|
||||||
|
public void testEnumNoDiscardTypesByRef() throws Exception {
|
||||||
|
loadCodeAndRun(getAboveComment());
|
||||||
|
checkNoErrorsOfKind(ER_ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue