From dd88f8ffca1ec021b1a839b6ab7711f72be2f107 Mon Sep 17 00:00:00 2001 From: Marco Stornelli Date: Mon, 6 Apr 2020 17:29:40 +0200 Subject: [PATCH] Bug 534420 - Added check for nodiscard for classes and enums Change-Id: I3932f4d23f18f96f8d1c15c18d7d4d991154aca1 --- .../internal/checkers/NoDiscardChecker.java | 39 ++++++++++-- .../checkers/NoDiscardCheckerTest.java | 59 +++++++++++++++++++ 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/NoDiscardChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/NoDiscardChecker.java index 2b92152e1cc..4c56d0ddcf6 100644 --- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/NoDiscardChecker.java +++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/NoDiscardChecker.java @@ -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.IBinding; 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.ICPPASTExpression; 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.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.semantics.CPPTemplates; 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.SemanticUtil; public class NoDiscardChecker extends AbstractAstFunctionChecker { 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 { 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()) { 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(); @@ -138,8 +149,24 @@ public class NoDiscardChecker extends AbstractAstFunctionChecker { } } else if (eval instanceof EvalFunctionCall) { ICPPFunction evalFunc = ((EvalFunctionCall) eval).resolveFunctionBinding(); - if (evalFunc != null && evalFunc.isNoDiscard()) { + if (evalFunc == null) + return false; + if (evalFunc.isNoDiscard()) { 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; diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/NoDiscardCheckerTest.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/NoDiscardCheckerTest.java index 140e27ab99a..4b420d1f833 100644 --- a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/NoDiscardCheckerTest.java +++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/NoDiscardCheckerTest.java @@ -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.internal.checkers.NoDiscardChecker; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; /** * Test for {@link NoDiscardChecker} class @@ -384,4 +385,62 @@ public class NoDiscardCheckerTest extends CheckerTestCase { loadCodeAndRun(getAboveComment()); 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 + //typename T::E foo() {return static_cast(0);} + //template + //struct trait { typedef typename F E; } + //void f1() { + // foo>(); + //} + 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); + } }