Skip to content

Implement Conversions2 rule package #946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 75 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
1d2aa2e
RULE-7-0-1 - NoConversionFromBool
lcartey Jun 10, 2025
5b810c3
Rule 7.0.1: Address review issues
lcartey Jun 10, 2025
62d5dcc
RULE-7-0-2 - NoImplicitBoolConversion
lcartey Jun 11, 2025
f92a2c9
Rule 7.0.2: Extend test case, support member function pointers
lcartey Jun 11, 2025
b62394a
Add Conversions exclusions file
lcartey Jun 12, 2025
a2c9912
RULE-7-0-6 - NumericAssignmentTypeMismatch
lcartey Jun 17, 2025
229705f
Rule 7.0.6: Update test with better variable names
lcartey Jun 17, 2025
f870023
Rule 7.0.6: Fix id-expression detection
lcartey Jun 17, 2025
0ed1689
Rule 7.0.6: Support reference types
lcartey Jun 17, 2025
778b344
Rule 7.0.6: Ignore compound expressions
lcartey Jun 17, 2025
acfb253
Rule 7.0.6: Additional function return test cases
lcartey Jun 17, 2025
9dbc39f
Rule 7.0.6: Clarify pass-by-value on parameters
lcartey Jun 17, 2025
b310e14
Rule 7.0.6: Add user defined operator tests
lcartey Jun 17, 2025
af2ff95
MISRA C++ 2023: Create StandardConversions library
lcartey Jun 17, 2025
ea7d168
MISRA C++ StandardConversions - improve detection of bitfield types
lcartey Jun 17, 2025
5843258
Rule 7.0.6: Improve bitfield support
lcartey Jun 18, 2025
01b517d
StandardConversions: Improve detection of numeric type category
lcartey Jun 18, 2025
06eddfa
Rule 7.0.6: Add a test case for non-numeric (not covered)
lcartey Jun 18, 2025
a65c4cc
StandardConversions: Handle aggregate initialization
lcartey Jun 18, 2025
04613cd
Add a library for determining constant expressions
lcartey Jun 19, 2025
4be1395
Rule 7.0.6: Use BigInt for constant expressions
lcartey Jun 19, 2025
e87892e
Rule 7.0.6: add tests for cv-qualified types
lcartey Jun 19, 2025
916fb3d
Rule 7.0.6: Support pointer to member cases
lcartey Jun 19, 2025
2ec2814
Rule 7.0.6: Support functions with default parameters
lcartey Jun 19, 2025
e659944
Rule 7.0.6: Ignore deleted overloads
lcartey Jun 19, 2025
c0fe44d
Rule 7.0.6: Refactor overload independent code
lcartey Jun 19, 2025
06ffbfb
Rule 7.0.6: Move aggregate tests to new file
lcartey Jun 19, 2025
fc63db1
Rule 7.0.6: Move operator tests to separate file
lcartey Jun 19, 2025
f68658a
Rule 7.0.6: Support constructor field initializers
lcartey Jun 19, 2025
3fdaa98
Rule 7.0.6: Handle explicit conversions
lcartey Jun 19, 2025
063a5cc
Rule 7.0.6: Improve tests for templates
lcartey Jun 20, 2025
96d5c1b
MISRA C++ 2023: Rename StandardConversions library
lcartey Jun 20, 2025
7c5fb87
Rule 7.0.6: Address performance issues
lcartey Jun 20, 2025
6ddab35
Create Call library
lcartey Jun 20, 2025
983f256
Extend ios stubs for C++
lcartey Jun 25, 2025
bb9f5a1
RULE-7-11-3 - FunctionPointerConversionContext
lcartey Jun 25, 2025
2e75310
C++: Improve char_traits stubs
lcartey Jun 25, 2025
4bf8d51
Improve C++ stubs for locales
lcartey Jun 6, 2025
4d5e35f
Extend C++ stubs for locale
lcartey Jun 6, 2025
f2b5410
C++: Add optional stubs
lcartey Jun 25, 2025
74946cf
Rule 7.0.3: NoCharacterNumericalValue.ql
lcartey Jun 25, 2025
a2d7ee3
RULE-7-0-5 - NoSignednessChangeFromPromotion
lcartey Jun 26, 2025
c25057d
Add sizeOfInt() predicate
lcartey Jun 27, 2025
3a8dab1
Rule 7.0.5: Refactor to enable non-Conversions
lcartey Jun 27, 2025
3cf9eac
Improve detection of integer promotions and usual arithmetic conversions
lcartey Jun 27, 2025
f50baa9
Format test case
lcartey Jun 27, 2025
a7ce6f5
Rule 7.0.5: Expand test cases
lcartey Jun 27, 2025
9aed463
Ruley 7.0.5: Support lvalue conversions on assign operations
lcartey Jun 27, 2025
aac2dc2
Refactor to use NumericType
lcartey Jun 27, 2025
92c7dac
Rule 7.0.5: Add pointer tests (should be ignored)
lcartey Jun 27, 2025
4be88a3
Rule 7.0.5: Add failing test case
lcartey Jun 27, 2025
f1502d6
Rule 7.0.5: Add test cases for enum conversions
lcartey Jul 1, 2025
89485d5
Conversions: Swap some queries around
lcartey Jul 1, 2025
6845cdc
RULE-7-0-4 - InappropriateBitwiseOrShiftOperands
lcartey Jul 4, 2025
db58704
Test large and negative constants, use BigInt
lcartey Jul 4, 2025
3d2616a
Rule 7.0.4: Add support for shift-assignment operators
lcartey Jul 7, 2025
05cfc2b
Rule 7.0.5: Add an implementation_scope
lcartey Jul 7, 2025
ce43bb9
M5-2-2: Make into shared query
lcartey Aug 15, 2025
bd54fa6
Add Conversions2 package
lcartey Aug 15, 2025
2510f2f
Rule 8.2.1: Implement as a shared query
lcartey Aug 15, 2025
afa6c7f
PointerToAVirtualBaseClass: Handle reference types and type defs
lcartey Aug 15, 2025
0ff6f35
A5-2-2: Refactor query to extract shared components
lcartey Aug 15, 2025
10bb7e4
Fix AlertReporting for nested macros
lcartey Aug 17, 2025
6b24e50
RULE-8-2-2 - NoCStyleOrFunctionalCasts
lcartey Aug 17, 2025
11ca8b3
RULE-8-2-6 - IntToPointerCastProhibited
lcartey Aug 17, 2025
414e8a7
Add intptr_t and uintptr_t stubs
lcartey Aug 17, 2025
03a6499
RULE-8-2-7 - NoPointerToIntegralCast
lcartey Aug 17, 2025
5687a7b
RULE-8-2-8 - PointerToIntegralCast
lcartey Aug 17, 2025
8f67e38
RULE-9-2-1 - NoStandaloneTypeCastExpression
lcartey Aug 18, 2025
251bf1a
Update mutex to include scoped_lock stubs
lcartey Aug 18, 2025
f9a6844
Rule 8.2.6: Query improvements
lcartey Aug 18, 2025
a065203
Rule 8.2.7: Simplify CodeQL
lcartey Aug 18, 2025
83e57be
Rule 8.2.8: Improve CodeQL query
lcartey Aug 18, 2025
5e7e836
Rule 9.2.1: Add proviso for if statement initializers
lcartey Aug 18, 2025
24a8098
Add change note for AlertReporting behaviour
lcartey Aug 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions change_notes/2025-08-15-m5-2-2-virtual-base.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`:
- Report casts where the from or to types are typedefs to virtual base classes or derived classes.
- Report casts to a reference type which is a derived type.
3 changes: 3 additions & 0 deletions change_notes/2025-08-18-fix-alert-reporting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `RULE-1-2`, `RULE-23-3`, `RULE-23-5`, `RULE-23-6`:
- Results that occur in nested macro invocations are now reported in the macro that defines the contravening code, rather than the macro which is first expanded.
- Results the occur in arguments to macro invocations are now reported in at the macro invocation site, instead of the macro definition site.
13 changes: 3 additions & 10 deletions cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.Macro
import codingstandards.cpp.CStyleCasts

/**
* Gets the macro (if any) that generated the given `CStyleCast`.
Expand Down Expand Up @@ -61,18 +62,10 @@ Macro getGeneratedFrom(CStyleCast c) {
* argument type is compatible with a single-argument constructor.
*/

from CStyleCast c, string extraMessage, Locatable l, string supplementary
from ExplicitUserDefinedCStyleCast c, string extraMessage, Locatable l, string supplementary
where
not isExcluded(c, BannedSyntaxPackage::traditionalCStyleCastsUsedQuery()) and
not c.isImplicit() and
not c.getType() instanceof UnknownType and
// For casts in templates that occur on types related to a template parameter, the copy of th
// cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all
// the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case
// of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on
// uninstantiated templates, and instead rely on reporting results within instantiations.
not c.isFromUninstantiatedTemplate(_) and
// Exclude casts created from macro invocations of macros defined by third parties
// Not generated from a library macro
not getGeneratedFrom(c) instanceof LibraryMacro and
// If the cast was generated from a user-provided macro, then report the macro that generated the
// cast, as the macro itself may have generated the cast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@

import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer

from Cast cast, VirtualBaseClass castFrom, Class castTo
where
not isExcluded(cast, PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()) and
not cast instanceof DynamicCast and
castFrom = cast.getExpr().getType().(PointerType).getBaseType() and
cast.getType().(PointerType).getBaseType() = castTo and
castTo = castFrom.getADerivedClass+()
select cast,
"A pointer to virtual base class $@ is not cast to a pointer of derived class $@ using a dynamic_cast.",
castFrom, castFrom.getName(), castTo, castTo.getName()
class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery {
PointerToAVirtualBaseClassCastToAPointerQuery() {
this = PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()
}
}
2 changes: 1 addition & 1 deletion cpp/autosar/test/rules/A5-2-2/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <string>
#include <utility>
int foo() { return 1; }

// A copy of 8.2,2 test.cpp, but with different cases compliant/non-compliant
void test_c_style_cast() {
double f = 3.14;
std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast
Expand Down

This file was deleted.

18 changes: 0 additions & 18 deletions cpp/autosar/test/rules/M5-2-2/test.cpp

This file was deleted.

8 changes: 7 additions & 1 deletion cpp/common/src/codingstandards/cpp/AlertReporting.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@ module MacroUnwrapper<ResultType ResultElement> {
* Gets a macro invocation that applies to the result element.
*/
private MacroInvocation getAMacroInvocation(ResultElement re) {
result.getAnExpandedElement() = re
result.getAnAffectedElement() = re
}

/**
* Gets the primary macro invocation that generated the result element.
*
* Does not hold for cases where the result element is located at a macro argument site.
*/
MacroInvocation getPrimaryMacroInvocation(ResultElement re) {
exists(MacroInvocation mi |
mi = getAMacroInvocation(re) and
// Only report cases where the element is not located at the macro expansion site
// This means we'll report results in macro arguments in the macro argument
// location, not within the macro itself
mi.getLocation().getStartColumn() = re.getLocation().getStartColumn() and
// No other more specific macro that expands to element
not exists(MacroInvocation otherMi |
otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi
Expand Down
18 changes: 18 additions & 0 deletions cpp/common/src/codingstandards/cpp/CStyleCasts.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import cpp
import codingstandards.cpp.Macro

/**
* A C-style cast that is explicitly user written and has a known target type.
*/
class ExplicitUserDefinedCStyleCast extends CStyleCast {
ExplicitUserDefinedCStyleCast() {
not this.isImplicit() and
not this.getType() instanceof UnknownType and
// For casts in templates that occur on types related to a template parameter, the copy of th
// cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all
// the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case
// of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on
// uninstantiated templates, and instead rely on reporting results within instantiations.
not this.isFromUninstantiatedTemplate(_)
}
}
18 changes: 18 additions & 0 deletions cpp/common/src/codingstandards/cpp/Call.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import cpp
import codingstandards.cpp.types.Type

/**
* Gets the `FunctionType` of an expression call.
*/
FunctionType getExprCallFunctionType(ExprCall call) {
// A standard expression call
// Returns a FunctionPointerIshType
result = call.(ExprCall).getExpr().getType()
or
// An expression call using the pointer to member operator (.* or ->*)
// This special handling is required because we don't have a CodeQL class representing the call
// to a pointer to member function, but the right hand side is extracted as the -1 child of the
// call.
// Returns a RoutineType
result = call.(ExprCall).getChild(-1).getType().(PointerToMemberType).getBaseType()
}
97 changes: 97 additions & 0 deletions cpp/common/src/codingstandards/cpp/ConstantExpressions.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import cpp

final private class FinalExpr = Expr;

/**
* An integer constant expression as defined by the C++17 standard.
*/
class IntegerConstantExpr extends FinalExpr {
IntegerConstantExpr() {
// An integer constant expression is a constant expression that has an
// integral type.
this.isConstant() and
exists(Type unspecifiedType | unspecifiedType = this.getUnspecifiedType() |
unspecifiedType instanceof IntegralType
or
// Unscoped enum type
unspecifiedType instanceof Enum and
not unspecifiedType instanceof ScopedEnum
)
}

/**
* Gets the value of this integer constant expression.
*
* This is only defined for expressions that are constant expressions, and
* that have a value that can be represented as a `BigInt`.
*/
QlBuiltins::BigInt getConstantValue() {
if exists(getPreConversionConstantValue())
then result = getPreConversionConstantValue()
else result = this.getValue().toBigInt()
}

/**
* Gets the pre-conversion constant value of this integer constant expression, if it is different
* from `getValue()`.
*
* This is required because `Expr.getValue()` returns the _converted constant expression value_
* for non-literal constant expressions, which is the expression value after conversions have been
* applied, but for validating conversions we need the _pre-conversion constant expression value_.
*/
private QlBuiltins::BigInt getPreConversionConstantValue() {
// Access of a variable that has a constant initializer
result =
this.(VariableAccess)
.getTarget()
.getInitializer()
.getExpr()
.getFullyConverted()
.getValue()
.toBigInt()
or
result = this.(EnumConstantAccess).getTarget().getValue().toBigInt()
or
result = -this.(UnaryMinusExpr).getOperand().getFullyConverted().getValue().toBigInt()
or
result = this.(UnaryPlusExpr).getOperand().getFullyConverted().getValue().toBigInt()
or
result = this.(NotExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot()
or
exists(BinaryOperation op, QlBuiltins::BigInt left, QlBuiltins::BigInt right |
op = this and
left = op.getLeftOperand().getFullyConverted().getValue().toBigInt() and
right = op.getRightOperand().getFullyConverted().getValue().toBigInt()
|
op instanceof AddExpr and
result = left + right
or
op instanceof SubExpr and
result = left - right
or
op instanceof MulExpr and
result = left * right
or
op instanceof DivExpr and
result = left / right
or
op instanceof RemExpr and
result = left % right
or
op instanceof BitwiseAndExpr and
result = left.bitAnd(right)
or
op instanceof BitwiseOrExpr and
result = left.bitOr(right)
or
op instanceof BitwiseXorExpr and
result = left.bitXor(right)
or
op instanceof RShiftExpr and
result = left.bitShiftRightSigned(right.toInt())
or
op instanceof LShiftExpr and
result = left.bitShiftLeft(right.toInt())
)
}
}
129 changes: 129 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype ConversionsQuery =
TNoConversionFromBoolQuery() or
TNoImplicitBoolConversionQuery() or
TNoCharacterNumericalValueQuery() or
TInappropriateBitwiseOrShiftOperandsQuery() or
TNoSignednessChangeFromPromotionQuery() or
TNumericAssignmentTypeMismatchQuery() or
TFunctionPointerConversionContextQuery()

predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `noConversionFromBool` query
ConversionsPackage::noConversionFromBoolQuery() and
queryId =
// `@id` for the `noConversionFromBool` query
"cpp/misra/no-conversion-from-bool" and
ruleId = "RULE-7-0-1" and
category = "required"
or
query =
// `Query` instance for the `noImplicitBoolConversion` query
ConversionsPackage::noImplicitBoolConversionQuery() and
queryId =
// `@id` for the `noImplicitBoolConversion` query
"cpp/misra/no-implicit-bool-conversion" and
ruleId = "RULE-7-0-2" and
category = "required"
or
query =
// `Query` instance for the `noCharacterNumericalValue` query
ConversionsPackage::noCharacterNumericalValueQuery() and
queryId =
// `@id` for the `noCharacterNumericalValue` query
"cpp/misra/no-character-numerical-value" and
ruleId = "RULE-7-0-3" and
category = "required"
or
query =
// `Query` instance for the `inappropriateBitwiseOrShiftOperands` query
ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery() and
queryId =
// `@id` for the `inappropriateBitwiseOrShiftOperands` query
"cpp/misra/inappropriate-bitwise-or-shift-operands" and
ruleId = "RULE-7-0-4" and
category = "required"
or
query =
// `Query` instance for the `noSignednessChangeFromPromotion` query
ConversionsPackage::noSignednessChangeFromPromotionQuery() and
queryId =
// `@id` for the `noSignednessChangeFromPromotion` query
"cpp/misra/no-signedness-change-from-promotion" and
ruleId = "RULE-7-0-5" and
category = "required"
or
query =
// `Query` instance for the `numericAssignmentTypeMismatch` query
ConversionsPackage::numericAssignmentTypeMismatchQuery() and
queryId =
// `@id` for the `numericAssignmentTypeMismatch` query
"cpp/misra/numeric-assignment-type-mismatch" and
ruleId = "RULE-7-0-6" and
category = "required"
or
query =
// `Query` instance for the `functionPointerConversionContext` query
ConversionsPackage::functionPointerConversionContextQuery() and
queryId =
// `@id` for the `functionPointerConversionContext` query
"cpp/misra/function-pointer-conversion-context" and
ruleId = "RULE-7-11-3" and
category = "required"
}

module ConversionsPackage {
Query noConversionFromBoolQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noConversionFromBool` query
TQueryCPP(TConversionsPackageQuery(TNoConversionFromBoolQuery()))
}

Query noImplicitBoolConversionQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noImplicitBoolConversion` query
TQueryCPP(TConversionsPackageQuery(TNoImplicitBoolConversionQuery()))
}

Query noCharacterNumericalValueQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noCharacterNumericalValue` query
TQueryCPP(TConversionsPackageQuery(TNoCharacterNumericalValueQuery()))
}

Query inappropriateBitwiseOrShiftOperandsQuery() {
//autogenerate `Query` type
result =
// `Query` type for `inappropriateBitwiseOrShiftOperands` query
TQueryCPP(TConversionsPackageQuery(TInappropriateBitwiseOrShiftOperandsQuery()))
}

Query noSignednessChangeFromPromotionQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noSignednessChangeFromPromotion` query
TQueryCPP(TConversionsPackageQuery(TNoSignednessChangeFromPromotionQuery()))
}

Query numericAssignmentTypeMismatchQuery() {
//autogenerate `Query` type
result =
// `Query` type for `numericAssignmentTypeMismatch` query
TQueryCPP(TConversionsPackageQuery(TNumericAssignmentTypeMismatchQuery()))
}

Query functionPointerConversionContextQuery() {
//autogenerate `Query` type
result =
// `Query` type for `functionPointerConversionContext` query
TQueryCPP(TConversionsPackageQuery(TFunctionPointerConversionContextQuery()))
}
}
Loading