1
0
Fork 0
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:
Marco Stornelli 2020-04-06 17:29:40 +02:00
parent 77790012cc
commit dd88f8ffca
2 changed files with 92 additions and 6 deletions

View file

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

View file

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