diff --git a/change_notes/2026-05-21-fix-fp-rule-5-13-4.md b/change_notes/2026-05-21-fix-fp-rule-5-13-4.md new file mode 100644 index 0000000000..e85b073d47 --- /dev/null +++ b/change_notes/2026-05-21-fix-fp-rule-5-13-4.md @@ -0,0 +1,5 @@ +- `RULE-5-13-4`, `M2-13-3` - `UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql`, `MissingUSuffix.ql`: + - Remove FPs in user-defined literals and template instantiations. +- `M2-13-3` - `cpp/autosar/missing-u-suffix`: + - Remove FPs in user-defined literals and template instantiations. + diff --git a/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql b/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql index c739035596..5d8782b3cc 100644 --- a/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql +++ b/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql @@ -17,7 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.UserDefinedLiteral as udl -from udl::UserDefinedLiteral udl +from udl::UserDefinedLiteralDeclaration udl where not isExcluded(udl, NamingPackage::userDefinedLiteralOperatorSuffixViolationQuery()) and not udl.hasCompliantSuffix() diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql index b41a57f900..d41cd28b4b 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql @@ -18,7 +18,7 @@ import codingstandards.cpp.UserDefinedLiteral as udl import codingstandards.cpp.SideEffect import codingstandards.cpp.sideeffect.DefaultEffects -from udl::UserDefinedLiteral udl, SideEffect e +from udl::UserDefinedLiteralDeclaration udl, SideEffect e where not isExcluded(udl, SideEffects2Package::userDefinedLiteralsOperatorsShallNotHaveSideEffectsQuery()) and diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql index 4593065e01..a4e652269e 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql @@ -19,7 +19,7 @@ import codingstandards.cpp.autosar import codingstandards.cpp.UserDefinedLiteral as udl import codingstandards.cpp.SideEffect -from udl::UserDefinedLiteral udl, Expr retExpr +from udl::UserDefinedLiteralDeclaration udl, Expr retExpr where not isExcluded(udl, SideEffects2Package::userDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParametersQuery()) and diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql index 81036f6f57..f8e2d0827b 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql @@ -22,7 +22,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.UserDefinedLiteral as udl -from udl::UserDefinedLiteral udl +from udl::UserDefinedLiteralDeclaration udl where not isExcluded(udl, NamingPackage::useOfReservedLiteralSuffixIdentifierQuery()) and not udl.hasCompliantSuffix() diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index 8e0c089f4d..67d4f06e35 100644 --- a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll +++ b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll @@ -5,9 +5,15 @@ */ module Cpp14Literal { private import cpp as StandardLibrary + private import codingstandards.cpp.UserDefinedLiteral /** An numeric literal. */ - abstract class NumericLiteral extends StandardLibrary::Literal { } + abstract class NumericLiteral extends StandardLibrary::Literal { + NumericLiteral() { + // exclude user-defined literals as they define custom suffixes + not this instanceof UserDefinedLiteral + } + } /** Convenience for implementing class `UnrecognizedNumericLiteral` */ abstract private class RecognizedNumericLiteral extends StandardLibrary::Literal { } diff --git a/cpp/common/src/codingstandards/cpp/UserDefinedLiteral.qll b/cpp/common/src/codingstandards/cpp/UserDefinedLiteral.qll index f9bf5d2dc8..6c34044b8e 100644 --- a/cpp/common/src/codingstandards/cpp/UserDefinedLiteral.qll +++ b/cpp/common/src/codingstandards/cpp/UserDefinedLiteral.qll @@ -4,8 +4,17 @@ import cpp -class UserDefinedLiteral extends Function { - UserDefinedLiteral() { +/** + * A user defined literal operator is a function that defines the behavior of a user defined literal. + * It is declared using the `operator ""` syntax. + * ``` + * constexpr long operator""_km(unsigned long value) { + * ... + * } + * ``` + */ +class UserDefinedLiteralDeclaration extends Function { + UserDefinedLiteralDeclaration() { // We use the '?' in this regexp because CodeQL CLI 2.4.6 and earlier reported these operators // using a single ", i.e `operator "`. This has been fixed in 2.5.9 (at the latest), but I // don't know if upgraded older databases will still have the broken version in. I've therefore @@ -16,3 +25,18 @@ class UserDefinedLiteral extends Function { /** Holds if `this` has a compliant suffix. */ predicate hasCompliantSuffix() { this.getName().regexpMatch("operator \"\"?_\\p{Alpha}+") } } + +/** + * A user defined literal is a literal that is passed as an argument to a call to a user defined literal operator. + * ``` + * 1000_km; + * ``` + */ +class UserDefinedLiteral extends Literal { + UserDefinedLiteral() { + exists(FunctionCall fc | + this = fc.getArgument(0) and + fc.getTarget() instanceof UserDefinedLiteralDeclaration + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll index a9535d9bfc..8f07ebb58b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll @@ -26,6 +26,8 @@ query predicate problems(Cpp14Literal::NumericLiteral nl, string message) { nl.getType().getUnspecifiedType().(IntegralType).isUnsigned() and // The literal already has a `u` or `U` suffix. not nl.getValueText().regexpMatch(".*[lL]*[uU][lL]*") and + // exclude literals derived from template instantiations + not nl.isFromTemplateInstantiation(_) and message = literalKind + " literal is an unsigned integer but does not include a 'U' suffix." ) } diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp index fcbd51b3de..b168bafcca 100644 --- a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp @@ -543,4 +543,20 @@ void test_macro() { COMPLIANT_VAL; // COMPLIANT NON_COMPLIANT_VAL; // NON_COMPLIANT[FALSE_NEGATIVE] - cannot determine suffix // in macro expansions -} \ No newline at end of file +} + +constexpr unsigned long long operator""_km(unsigned long long value) { + return value; +} + +void test_user_defined_literal_exclusion() { + 0x80000000_km; // COMPLIANT - user-defined literal argument should be excluded +} + +template unsigned long long instantiated_literal_exclusion() { + return T{}; // COMPLIANT - template instantiation should be excluded +} + +void test_instantiated_literal_exclusion() { + instantiated_literal_exclusion(); +}