diff --git a/change_notes/2026-02-10-share-autosar-0-1-2.md b/change_notes/2026-02-10-share-autosar-0-1-2.md new file mode 100644 index 0000000000..3cc20799c7 --- /dev/null +++ b/change_notes/2026-02-10-share-autosar-0-1-2.md @@ -0,0 +1,2 @@ + - `A0-1-2` - `UnusedReturnValue.ql`: + - Refactors the rule implementation into a shared library for usage in MISRA C++ ruleset. No externally visible changes expected. \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-1-2/UnusedReturnValue.ql b/cpp/autosar/src/rules/A0-1-2/UnusedReturnValue.ql index 891a44ed2a..5016650a4b 100644 --- a/cpp/autosar/src/rules/A0-1-2/UnusedReturnValue.ql +++ b/cpp/autosar/src/rules/A0-1-2/UnusedReturnValue.ql @@ -16,35 +16,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Operator -import cpp +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared -/* - * This query performs a simple syntactic check to ensure that the return value of the function is - * not completely ignored. This matches the examples given in the rule, although the text itself is - * not entirely clear. This means it will not find cases where something is done with the return - * value, but it is not meaningfully read. For example: `int ret_val = f();`, with no subsequent - * access of `ret_val`. However, such a case _would_ be flagged by A0-1-1 - Useless assignment. - */ +module UnusedReturnValueConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result = DeadCodePackage::unusedReturnValueQuery() } +} -from FunctionCall fc, Function f -where - not isExcluded(fc, DeadCodePackage::unusedReturnValueQuery()) and - // Find function calls in `ExprStmt`s, which indicate the return value is ignored - fc.getParent() instanceof ExprStmt and - // Ignore calls to void functions, which don't return values - not fc.getUnderlyingType() instanceof VoidType and - // Get the function target - f = fc.getTarget() and - // Overloaded (i.e. user defined) operators should behave in the same way as built-in operators, - // so the rule does not require the use of the return value - not f instanceof Operator and - // Exclude cases where the function call is generated within a macro, as the user of the macro is - // not necessarily able to address those results - not fc.isAffectedByMacro() and - // Rule allows disabling this rule where a static_cast or a C-style cast to void is applied - not exists(Cast cast | cast instanceof StaticCast or cast instanceof CStyleCast | - fc.getExplicitlyConverted() = cast and - cast.getActualType() instanceof VoidType - ) -select fc, "Return value from call to $@ is unused.", f, f.getName() +import UnusedReturnValueShared diff --git a/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.expected b/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.expected deleted file mode 100644 index 480b6d75a3..0000000000 --- a/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:12:3:12:3 | call to f | Return value from call to $@ is unused. | test.cpp:3:5:3:5 | f | f | \ No newline at end of file diff --git a/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.qlref b/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.qlref deleted file mode 100644 index 247484a28e..0000000000 --- a/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A0-1-2/UnusedReturnValue.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.testref b/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.testref new file mode 100644 index 0000000000..244dae8c0e --- /dev/null +++ b/cpp/autosar/test/rules/A0-1-2/UnusedReturnValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode6.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode6.qll new file mode 100644 index 0000000000..4ce962cdce --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode6.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype DeadCode6Query = TUnusedReturnValueMisraCppQuery() + +predicate isDeadCode6QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unusedReturnValueMisraCpp` query + DeadCode6Package::unusedReturnValueMisraCppQuery() and + queryId = + // `@id` for the `unusedReturnValueMisraCpp` query + "cpp/misra/unused-return-value-misra-cpp" and + ruleId = "RULE-0-1-2" and + category = "required" +} + +module DeadCode6Package { + Query unusedReturnValueMisraCppQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedReturnValueMisraCpp` query + TQueryCPP(TDeadCode6PackageQuery(TUnusedReturnValueMisraCppQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index cad86d2285..10f4029904 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -19,6 +19,7 @@ import Conversions2 import DeadCode import DeadCode3 import DeadCode4 +import DeadCode6 import Declarations import ExceptionSafety import Exceptions1 @@ -91,6 +92,7 @@ newtype TCPPQuery = TDeadCodePackageQuery(DeadCodeQuery q) or TDeadCode3PackageQuery(DeadCode3Query q) or TDeadCode4PackageQuery(DeadCode4Query q) or + TDeadCode6PackageQuery(DeadCode6Query q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or @@ -163,6 +165,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeadCodeQueryMetadata(query, queryId, ruleId, category) or isDeadCode3QueryMetadata(query, queryId, ruleId, category) or isDeadCode4QueryMetadata(query, queryId, ruleId, category) or + isDeadCode6QueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/unusedreturnvalueshared/UnusedReturnValueShared.qll b/cpp/common/src/codingstandards/cpp/rules/unusedreturnvalueshared/UnusedReturnValueShared.qll new file mode 100644 index 0000000000..5a9b4445c0 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/unusedreturnvalueshared/UnusedReturnValueShared.qll @@ -0,0 +1,47 @@ +/** + * Provides a configurable module UnusedReturnValue with a `problems` predicate + * for the following issue: + * The value returned by a function having a non-void return type that is not an + * overloaded operator shall be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +signature module UnusedReturnValueSharedConfigSig { + Query getQuery(); +} + +module UnusedReturnValueShared { + /* + * This query performs a simple syntactic check to ensure that the return value of the function is + * not completely ignored. This matches the examples given in the rule, although the text itself is + * not entirely clear. This means it will not find cases where something is done with the return + * value, but it is not meaningfully read. For example: `int ret_val = f();`, with no subsequent + * access of `ret_val`. However, such a case _would_ be flagged by A0-1-1 - Useless assignment. + */ + + query predicate problems(FunctionCall fc, string message, Function f, string funcName) { + not isExcluded(fc, Config::getQuery()) and + message = "Return value from call to $@ is unused." and + funcName = f.getName() and + // Find function calls in `ExprStmt`s, which indicate the return value is ignored + fc.getParent() instanceof ExprStmt and + // Ignore calls to void functions, which don't return values + not fc.getUnderlyingType() instanceof VoidType and + // Get the function target + f = fc.getTarget() and + // Overloaded (i.e. user defined) operators should behave in the same way as built-in operators, + // so the rule does not require the use of the return value + not f instanceof Operator and + // Exclude cases where the function call is generated within a macro, as the user of the macro is + // not necessarily able to address those results + not fc.isAffectedByMacro() and + // Rule allows disabling this rule where a static_cast or a C-style cast to void is applied + not exists(Cast cast | cast instanceof StaticCast or cast instanceof CStyleCast | + fc.getExplicitlyConverted() = cast and + cast.getActualType() instanceof VoidType + ) + } +} diff --git a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql index 469a7f7f73..a398116bac 100644 --- a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql @@ -17,31 +17,11 @@ import cpp import codingstandards.cpp.CodingStandards import codingstandards.cpp.exclusions.cpp.RuleMetadata +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ -/* - * This query performs a simple syntactic check to ensure that the return value of the function is - * not completely ignored. This matches the examples given in the rule, although the text itself is - * not entirely clear. This means it will not find cases where something is done with the return - * value, but it is not meaningfully read. For example: `int ret_val = f();`, with no subsequent - * access of `ret_val`. However, such a case _would_ be flagged by A0-1-1 - Useless assignment. - */ +module UnusedReturnValueConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result = DeadCodePackage::unusedReturnValueQuery() } +} -from FunctionCall fc, Function f -where - not isExcluded(fc, DeadCodePackage::unusedReturnValueQuery()) and - // Find function calls in `ExprStmt`s, which indicate the return value is ignored - fc.getParent() instanceof ExprStmt and - // Ignore calls to void functions, which don't return values - not fc.getType() instanceof VoidType and - // Get the function target - f = fc.getTarget() and - // Overloaded (i.e. user defined) operators should behave in the same way as built-in operators, - // so the rule does not require the use of the return value - not f instanceof Operator and - // Exclude cases where the function call is generated within a macro, as the user of the macro is - // not necessarily able to address thoes results - not fc.isAffectedByMacro() and - // Rule allows disabling this rule where a static_cast is applied - not fc.getExplicitlyConverted().(StaticCast).getActualType() instanceof VoidType -select fc, "Return value from call to $@ is unused.", f, f.getName() +import UnusedReturnValueShared diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql index 469a7f7f73..a398116bac 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql @@ -17,31 +17,11 @@ import cpp import codingstandards.cpp.CodingStandards import codingstandards.cpp.exclusions.cpp.RuleMetadata +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ -/* - * This query performs a simple syntactic check to ensure that the return value of the function is - * not completely ignored. This matches the examples given in the rule, although the text itself is - * not entirely clear. This means it will not find cases where something is done with the return - * value, but it is not meaningfully read. For example: `int ret_val = f();`, with no subsequent - * access of `ret_val`. However, such a case _would_ be flagged by A0-1-1 - Useless assignment. - */ +module UnusedReturnValueConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result = DeadCodePackage::unusedReturnValueQuery() } +} -from FunctionCall fc, Function f -where - not isExcluded(fc, DeadCodePackage::unusedReturnValueQuery()) and - // Find function calls in `ExprStmt`s, which indicate the return value is ignored - fc.getParent() instanceof ExprStmt and - // Ignore calls to void functions, which don't return values - not fc.getType() instanceof VoidType and - // Get the function target - f = fc.getTarget() and - // Overloaded (i.e. user defined) operators should behave in the same way as built-in operators, - // so the rule does not require the use of the return value - not f instanceof Operator and - // Exclude cases where the function call is generated within a macro, as the user of the macro is - // not necessarily able to address thoes results - not fc.isAffectedByMacro() and - // Rule allows disabling this rule where a static_cast is applied - not fc.getExplicitlyConverted().(StaticCast).getActualType() instanceof VoidType -select fc, "Return value from call to $@ is unused.", f, f.getName() +import UnusedReturnValueShared diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql index 469a7f7f73..a398116bac 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql @@ -17,31 +17,11 @@ import cpp import codingstandards.cpp.CodingStandards import codingstandards.cpp.exclusions.cpp.RuleMetadata +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ -/* - * This query performs a simple syntactic check to ensure that the return value of the function is - * not completely ignored. This matches the examples given in the rule, although the text itself is - * not entirely clear. This means it will not find cases where something is done with the return - * value, but it is not meaningfully read. For example: `int ret_val = f();`, with no subsequent - * access of `ret_val`. However, such a case _would_ be flagged by A0-1-1 - Useless assignment. - */ +module UnusedReturnValueConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result = DeadCodePackage::unusedReturnValueQuery() } +} -from FunctionCall fc, Function f -where - not isExcluded(fc, DeadCodePackage::unusedReturnValueQuery()) and - // Find function calls in `ExprStmt`s, which indicate the return value is ignored - fc.getParent() instanceof ExprStmt and - // Ignore calls to void functions, which don't return values - not fc.getType() instanceof VoidType and - // Get the function target - f = fc.getTarget() and - // Overloaded (i.e. user defined) operators should behave in the same way as built-in operators, - // so the rule does not require the use of the return value - not f instanceof Operator and - // Exclude cases where the function call is generated within a macro, as the user of the macro is - // not necessarily able to address thoes results - not fc.isAffectedByMacro() and - // Rule allows disabling this rule where a static_cast is applied - not fc.getExplicitlyConverted().(StaticCast).getActualType() instanceof VoidType -select fc, "Return value from call to $@ is unused.", f, f.getName() +import UnusedReturnValueShared diff --git a/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.expected b/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.expected new file mode 100644 index 0000000000..96955df6e2 --- /dev/null +++ b/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.expected @@ -0,0 +1 @@ +| test.cpp:15:3:15:3 | call to f | Return value from call to $@ is unused. | test.cpp:3:5:3:5 | f | f | diff --git a/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.ql b/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.ql new file mode 100644 index 0000000000..894821756a --- /dev/null +++ b/cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.ql @@ -0,0 +1,8 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared + +module TestFileConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +import UnusedReturnValueShared diff --git a/cpp/autosar/test/rules/A0-1-2/test.cpp b/cpp/common/test/rules/unusedreturnvalueshared/test.cpp similarity index 86% rename from cpp/autosar/test/rules/A0-1-2/test.cpp rename to cpp/common/test/rules/unusedreturnvalueshared/test.cpp index 2be7122128..a00e45840f 100644 --- a/cpp/autosar/test/rules/A0-1-2/test.cpp +++ b/cpp/common/test/rules/unusedreturnvalueshared/test.cpp @@ -5,6 +5,9 @@ void g(int x); class A { public: + A() { + g(2); // Make constructor non-trivial so its call is always extracted. + } A operator+(const A &other); }; @@ -21,6 +24,7 @@ void test_return_val() { a1 + a2; // COMPLIANT - `+` is a call to operator+, but is permitted by the // rule + A a3{}; // COMPLIANT - not function call syntax. (void)f(); // COMPLIANT - explicitly ignoring the return value by C-style cast // to void. std::ignore = f(); // COMPLIANT - explicitly ignoring the return value by diff --git a/cpp/misra/src/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.ql b/cpp/misra/src/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.ql new file mode 100644 index 0000000000..6f82d98e38 --- /dev/null +++ b/cpp/misra/src/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/unused-return-value-misra-cpp + * @name RULE-0-1-2: The value returned by a function shall be used + * @description The result of a non-void function shall be used if called with function call syntax. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-0-1-2 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.unusedreturnvalueshared.UnusedReturnValueShared + +module UnusedReturnValueMisraCppConfig implements UnusedReturnValueSharedConfigSig { + Query getQuery() { result = DeadCode6Package::unusedReturnValueMisraCppQuery() } +} + +import UnusedReturnValueShared diff --git a/cpp/misra/test/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.testref b/cpp/misra/test/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.testref new file mode 100644 index 0000000000..244dae8c0e --- /dev/null +++ b/cpp/misra/test/rules/RULE-0-1-2/UnusedReturnValueMisraCpp.testref @@ -0,0 +1 @@ +cpp/common/test/rules/unusedreturnvalueshared/UnusedReturnValueShared.ql \ No newline at end of file diff --git a/rule_packages/cpp/DeadCode.json b/rule_packages/cpp/DeadCode.json index 4746f86dee..1245a8b11d 100644 --- a/rule_packages/cpp/DeadCode.json +++ b/rule_packages/cpp/DeadCode.json @@ -40,6 +40,7 @@ "precision": "very-high", "severity": "warning", "short_name": "UnusedReturnValue", + "shared_implementation_short_name": "UnusedReturnValueShared", "tags": [ "readability", "maintainability" diff --git a/rule_packages/cpp/DeadCode6.json b/rule_packages/cpp/DeadCode6.json new file mode 100644 index 0000000000..4189853c7a --- /dev/null +++ b/rule_packages/cpp/DeadCode6.json @@ -0,0 +1,26 @@ +{ + "MISRA-C++-2023": { + "RULE-0-1-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The result of a non-void function shall be used if called with function call syntax.", + "kind": "problem", + "name": "The value returned by a function shall be used", + "precision": "very-high", + "severity": "error", + "short_name": "UnusedReturnValueMisraCpp", + "shared_implementation_short_name": "UnusedReturnValueShared", + "tags": [ + "scope/single-translation-unit", + "correctness" + ] + } + ], + "title": "The value returned by a function shall be used" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index dcc5ee5c5f..08fa09a573 100644 --- a/rules.csv +++ b/rules.csv @@ -826,7 +826,7 @@ c,MISRA-C-2012,RULE-23-8,Yes,Required,,,A default association shall appear as ei cpp,MISRA-C++-2023,RULE-0-0-1,Yes,Required,Decidable,Single Translation Unit,A function shall not contain unreachable statements,M0-1-1,DeadCode3,Medium, cpp,MISRA-C++-2023,RULE-0-0-2,Yes,Advisory,Undecidable,System,Controlling expressions should not be invariant,M0-1-2,DeadCode4,Easy, cpp,MISRA-C++-2023,RULE-0-1-1,Yes,Advisory,Undecidable,System,A value should not be unnecessarily written to a local object,A0-1-1,DeadCode2,Medium, -cpp,MISRA-C++-2023,RULE-0-1-2,Yes,Required,Decidable,Single Translation Unit,The value returned by a function shall be used,A0-1-2,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-1-2,Yes,Required,Decidable,Single Translation Unit,The value returned by a function shall be used,A0-1-2,DeadCode6,Easy, cpp,MISRA-C++-2023,RULE-0-2-1,Yes,Advisory,Decidable,Single Translation Unit,Variables with limited visibility should be used at least once,M0-1-3,DeadCode2,Easy, cpp,MISRA-C++-2023,RULE-0-2-2,Yes,Required,Decidable,Single Translation Unit,A named function parameter shall be used at least once,"A0-1-4, A0-1-5",DeadCode2,Easy, cpp,MISRA-C++-2023,RULE-0-2-3,Yes,Advisory,Decidable,Single Translation Unit,Types with limited visibility should be used at least once,A0-1-6,DeadCode2,Easy,