diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned2.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned2.qll new file mode 100644 index 000000000..849571304 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Banned2Query = TUnscopedEnumerationsShouldNotBeDeclaredQuery() + +predicate isBanned2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unscopedEnumerationsShouldNotBeDeclared` query + Banned2Package::unscopedEnumerationsShouldNotBeDeclaredQuery() and + queryId = + // `@id` for the `unscopedEnumerationsShouldNotBeDeclared` query + "cpp/misra/unscoped-enumerations-should-not-be-declared" and + ruleId = "RULE-10-2-2" and + category = "advisory" +} + +module Banned2Package { + Query unscopedEnumerationsShouldNotBeDeclaredQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unscopedEnumerationsShouldNotBeDeclared` query + TQueryCPP(TBanned2PackageQuery(TUnscopedEnumerationsShouldNotBeDeclaredQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned3.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned3.qll new file mode 100644 index 000000000..44fc76965 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned3.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Banned3Query = TUnscopedEnumWithoutFixedUnderlyingTypeUsedQuery() + +predicate isBanned3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unscopedEnumWithoutFixedUnderlyingTypeUsed` query + Banned3Package::unscopedEnumWithoutFixedUnderlyingTypeUsedQuery() and + queryId = + // `@id` for the `unscopedEnumWithoutFixedUnderlyingTypeUsed` query + "cpp/misra/unscoped-enum-without-fixed-underlying-type-used" and + ruleId = "RULE-10-2-3" and + category = "required" +} + +module Banned3Package { + Query unscopedEnumWithoutFixedUnderlyingTypeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unscopedEnumWithoutFixedUnderlyingTypeUsed` query + TQueryCPP(TBanned3PackageQuery(TUnscopedEnumWithoutFixedUnderlyingTypeUsedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned4.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned4.qll new file mode 100644 index 000000000..cee6d2ed2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned4.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Banned4Query = TUnnamedNamespacesInHeaderFilesQuery() + +predicate isBanned4QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unnamedNamespacesInHeaderFiles` query + Banned4Package::unnamedNamespacesInHeaderFilesQuery() and + queryId = + // `@id` for the `unnamedNamespacesInHeaderFiles` query + "cpp/misra/unnamed-namespaces-in-header-files" and + ruleId = "RULE-10-3-1" and + category = "advisory" +} + +module Banned4Package { + Query unnamedNamespacesInHeaderFilesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unnamedNamespacesInHeaderFiles` query + TQueryCPP(TBanned4PackageQuery(TUnnamedNamespacesInHeaderFilesQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 5fba4afa5..ae9af3323 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -4,6 +4,9 @@ import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import Allocations import Banned1 +import Banned2 +import Banned3 +import Banned4 import BannedAPIs import BannedFunctions import BannedLibraries @@ -94,6 +97,9 @@ import VirtualFunctions newtype TCPPQuery = TAllocationsPackageQuery(AllocationsQuery q) or TBanned1PackageQuery(Banned1Query q) or + TBanned2PackageQuery(Banned2Query q) or + TBanned3PackageQuery(Banned3Query q) or + TBanned4PackageQuery(Banned4Query q) or TBannedAPIsPackageQuery(BannedAPIsQuery q) or TBannedFunctionsPackageQuery(BannedFunctionsQuery q) or TBannedLibrariesPackageQuery(BannedLibrariesQuery q) or @@ -184,6 +190,9 @@ newtype TCPPQuery = predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { isAllocationsQueryMetadata(query, queryId, ruleId, category) or isBanned1QueryMetadata(query, queryId, ruleId, category) or + isBanned2QueryMetadata(query, queryId, ruleId, category) or + isBanned3QueryMetadata(query, queryId, ruleId, category) or + isBanned4QueryMetadata(query, queryId, ruleId, category) or isBannedAPIsQueryMetadata(query, queryId, ruleId, category) or isBannedFunctionsQueryMetadata(query, queryId, ruleId, category) or isBannedLibrariesQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.ql b/cpp/misra/src/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.ql new file mode 100644 index 000000000..820588000 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.ql @@ -0,0 +1,28 @@ +/** + * @id cpp/misra/unscoped-enumerations-should-not-be-declared + * @name RULE-10-2-2: Unscoped enumerations should not be declared + * @description An unscoped enumeration should not be used outside of a class/struct scope; use + * 'enum class' instead to prevent name clashes and implicit conversions to integral + * types. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-2-2 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +class NestedUnscopedEnum extends Enum, NestedEnum { + NestedUnscopedEnum() { not this instanceof ScopedEnum } +} + +from Enum enum +where + not isExcluded(enum, Banned2Package::unscopedEnumerationsShouldNotBeDeclaredQuery()) and + not (enum instanceof ScopedEnum or enum instanceof NestedUnscopedEnum) +select enum, "This enumeration is an unscoped enum not enclosed in a class or a struct." diff --git a/cpp/misra/src/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.ql b/cpp/misra/src/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.ql new file mode 100644 index 000000000..bc0176b28 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.ql @@ -0,0 +1,238 @@ +/** + * @id cpp/misra/unscoped-enum-without-fixed-underlying-type-used + * @name RULE-10-2-3: The numeric value of an unscoped enumeration with no fixed underlying type shall not be used + * @description Treating unscoped enumeration without a fixed underlying type as an integral type is + * not portable and might cause unintended behaviors. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-2-3 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +private predicate isUnscopedEnum(Enum enum) { not enum instanceof ScopedEnum } + +private predicate withoutFixedUnderlyingType(Enum enum) { not enum.hasExplicitUnderlyingType() } + +private predicate isUnscopedEnumWithoutFixedUnderlyingType(Enum enum) { + isUnscopedEnum(enum) and withoutFixedUnderlyingType(enum) +} + +class ArithmeticBitwiseLogicalBinaryOperation extends BinaryOperation { + ArithmeticBitwiseLogicalBinaryOperation() { + this instanceof BinaryArithmeticOperation or + this instanceof BinaryBitwiseOperation or + this instanceof BinaryLogicalOperation + } +} + +/** + * ``` C++ + * static_cast(u) == static_cast(s); // COMPLIANT: comparing ints + * ``` + * ^^^ To solve this, we use `getExplicitlyConverted`: + * `binOp.getLeftOperand().getExplicitlyConverted()` gives `int`. + */ +predicate arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum( + ArithmeticBitwiseLogicalBinaryOperation binOp, Enum enum +) { + /* + * We want to strip explicit casts and not implicit ones. Without the + * stripping of explicit casts, our query would raise a false alarm on + * cases such as below. + * + * ``` C++ + * static_cast(u) + 1 // COMPLIANT + * ``` + */ + + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + ( + enum = binOp.getLeftOperand().getExplicitlyConverted().getUnderlyingType() or + enum = binOp.getRightOperand().getExplicitlyConverted().getUnderlyingType() + ) +} + +class RelationalEqualityBinaryOperation extends BinaryOperation { + RelationalEqualityBinaryOperation() { + this instanceof RelationalOperation or + this instanceof EqualityOperation + } +} + +predicate relationalEqualityOperationUsesUnscopedUnfixedEnum( + RelationalEqualityBinaryOperation binOp, Enum enum +) { + exists(Type leftOperandType, Type rightOperandType | + /* + * We want to strip explicit casts and not implicit ones. Without the + * stripping of explicit casts, our query would raise a false alarm on + * cases such as below. + * + * ``` C++ + * static_cast(u) == 1 // COMPLIANT + * ``` + */ + + leftOperandType = binOp.getLeftOperand().getExplicitlyConverted().getUnderlyingType() and + rightOperandType = binOp.getRightOperand().getExplicitlyConverted().getUnderlyingType() + | + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + ( + enum = leftOperandType or + enum = rightOperandType + ) and + leftOperandType != rightOperandType + ) +} + +class ArithmeticBitwiseCompoundAssignment extends AssignOperation { + ArithmeticBitwiseCompoundAssignment() { + this instanceof AssignArithmeticOperation or + this instanceof AssignBitwiseOperation + } +} + +predicate compoundAssignmentUsesUnscopedUnfixedEnum( + ArithmeticBitwiseCompoundAssignment compoundAssignment, Enum enum +) { + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + enum = compoundAssignment.getAnOperand().getUnderlyingType() +} + +/** + * Gets the minimum number of bits required to hold all values of enum `e`. + */ +int enumMinBits(Enum e, boolean signed) { + exists(QlBuiltins::BigInt minVal, QlBuiltins::BigInt maxVal | + minVal = min(EnumConstant c | c.getDeclaringEnum() = e | c.getValue().toBigInt()) and + maxVal = max(EnumConstant c | c.getDeclaringEnum() = e | c.getValue().toBigInt()) + | + // 8 bits: signed [-128, 127] or unsigned [0, 255] + if minVal >= "-128".toBigInt() and maxVal <= "127".toBigInt() + then result = 8 and signed = true + else + if minVal >= "0".toBigInt() and maxVal <= "255".toBigInt() + then ( + result = 8 and signed = false + ) else + // 16 bits: signed [-32768, 32767] or unsigned [0, 65535] + if minVal >= "-32768".toBigInt() and maxVal <= "32767".toBigInt() + then ( + result = 16 and signed = true + ) else + if minVal >= "0".toBigInt() and maxVal <= "65535".toBigInt() + then ( + result = 16 and signed = false + ) else + // 32 bits: signed [-2147483648, 2147483647] or unsigned [0, 4294967295] + if minVal >= "-2147483648".toBigInt() and maxVal <= "2147483647".toBigInt() + then ( + result = 32 and signed = true + ) else + if minVal >= "0".toBigInt() and maxVal <= "4294967295".toBigInt() + then ( + result = 32 and signed = false + ) else ( + // 64 bits: everything else + result = 64 and signed = true + ) + ) +} + +/** + * Holds if the enum `e` can fit in an integral type `type`. + */ +predicate enumFitsInType(Enum e, IntegralType type) { + exists(int minBits, boolean signed | minBits = enumMinBits(e, signed) | + /* If it has exactly the minimum number of bits, then check its signedness. */ + type.getSize() * 8 = minBits and + ( + signed = true and type.isSigned() + or + signed = false and type.isUnsigned() + ) + or + /* If it exceeds the minimum number of bits, signedness doesn't matter. */ + type.getSize() * 8 > minBits + ) +} + +predicate assignmentSourceIsUnscopedUnfixedEnum(AssignExpr assign, Enum enum, Type targetType) { + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + enum = assign.getRValue().getUnderlyingType() and + targetType = assign.getLValue().getUnderlyingType() and + not enumFitsInType(enum, targetType) and + not enum = targetType +} + +predicate staticCastSourceIsUnscopedUnfixedEnumVariant(StaticCast cast, Enum enum, Type targetType) { + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + enum = cast.getExpr().getUnderlyingType() and + targetType = cast.getUnderlyingType() and + not enumFitsInType(enum, targetType) and + not enum = targetType +} + +predicate switchConditionIsAnUnfixedEnumVariant(SwitchStmt switch, Enum enum, SwitchCase invalidCase) { + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + enum = switch.getExpr().getType() and + invalidCase = switch.getASwitchCase() and + not invalidCase.getExpr().getUnderlyingType() = enum +} + +/** + * Holds if a `static_cast` expression has an unscoped enum without fixed + * underlying type as the target type. + */ +predicate staticCastTargetIsUnscopedUnfixedEnumVariant(StaticCast cast, Enum enum) { + isUnscopedEnumWithoutFixedUnderlyingType(enum) and + enum = cast.getType() and + not cast.getExpr().getType() = enum +} + +from Element x, Enum enum, string message +where + not isExcluded(x, Banned3Package::unscopedEnumWithoutFixedUnderlyingTypeUsedQuery()) and + ( + arithmeticBitwiseLogicalOperationUsesUnscopedUnfixedEnum(x, enum) and + message = + "Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type." + or + relationalEqualityOperationUsesUnscopedUnfixedEnum(x, enum) and + message = + "Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type." + or + compoundAssignmentUsesUnscopedUnfixedEnum(x, enum) and + message = "Compound assignment uses unscoped enum $@ without fixed underlying type." + or + exists(Type targetType | + assignmentSourceIsUnscopedUnfixedEnum(x, enum, targetType) and + message = + "Assignment from unscoped enum $@ without fixed underlying type to '" + targetType.getName() + + "' which may not be large enough." + ) + or + exists(Type targetType | + staticCastSourceIsUnscopedUnfixedEnumVariant(x, enum, targetType) and + message = + "Static cast from unscoped enum $@ without fixed underlying type to '" + + targetType.getName() + "' which may not be large enough." + ) + or + exists(SwitchStmt switch | + switchConditionIsAnUnfixedEnumVariant(switch, enum, x) and + message = + "Switch on unscoped enum $@ without fixed underlying type has case not of the same enum type." + ) + or + staticCastTargetIsUnscopedUnfixedEnumVariant(x, enum) and + message = "Static cast to unscoped enum $@ without fixed underlying type." + ) +select x, message, enum, enum.getName() diff --git a/cpp/misra/src/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.ql b/cpp/misra/src/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.ql new file mode 100644 index 000000000..146458493 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/unnamed-namespaces-in-header-files + * @name RULE-10-3-1: There should be no unnamed namespaces in header files + * @description Anonymous namespaces in header files create separate entities in each translation + * unit, which may not be consistent with developer expectations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-3-1 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from NamespaceDeclarationEntry namespaceDeclarationEntry, HeaderFile headerFile +where + not isExcluded(namespaceDeclarationEntry, Banned4Package::unnamedNamespacesInHeaderFilesQuery()) and + namespaceDeclarationEntry.getNamespace().isAnonymous() and + headerFile = namespaceDeclarationEntry.getFile() +select namespaceDeclarationEntry, "Anonymous namespace declared in header file $@.", headerFile, + headerFile.getBaseName() diff --git a/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.expected b/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.expected new file mode 100644 index 000000000..f5ed3eb39 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.expected @@ -0,0 +1,20 @@ +| test.cpp:8:6:8:14 | E_Global1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:9:6:9:6 | (unnamed enum) | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:16:8:16:9 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:17:8:17:8 | (unnamed enum) | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:23:10:23:11 | E3 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:24:10:24:11 | E4 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:31:8:31:14 | E_Anon1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:32:8:32:8 | (unnamed enum) | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:41:10:41:11 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:76:8:76:9 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:89:8:89:9 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:90:8:90:8 | (unnamed enum) | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:101:10:101:11 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:102:10:102:11 | E2 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:105:12:105:13 | E3 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:125:8:125:9 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:126:8:126:8 | (unnamed enum) | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:133:10:133:11 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:136:12:136:13 | E2 | This enumeration is an unscoped enum not enclosed in a class or a struct. | +| test.cpp:145:10:145:11 | E1 | This enumeration is an unscoped enum not enclosed in a class or a struct. | diff --git a/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.qlref b/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.qlref new file mode 100644 index 000000000..672d297ba --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.qlref @@ -0,0 +1 @@ +rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-2-2/test.cpp b/cpp/misra/test/rules/RULE-10-2-2/test.cpp new file mode 100644 index 000000000..89cf1263d --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-2/test.cpp @@ -0,0 +1,152 @@ +#include + +/* ========== 1. Global scope fixtures ========== */ +static int32_t G1 = 1; +static int32_t G2 = 2; + +/* ========== 2. Global scope enums ========== */ +enum E_Global1 : int32_t { V1, V2, V3 }; // NON_COMPLIANT: unscoped at global scope +enum { GlobalAnon1, GlobalAnon2 }; // NON_COMPLIANT: unscoped anonymous at global scope +enum class E_Global2 : int32_t { V1, V2 }; // COMPLIANT: scoped enum + +/* ========== 3. Nested namespaces ========== */ +namespace N1 { + static int32_t N1_V1 = 1; + + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in namespace + hides ::G1 + enum { N1_Anon1, N1_Anon2 }; // NON_COMPLIANT: unscoped anonymous in namespace + enum class E2 : int32_t { G1 }; // COMPLIANT: scoped enum + + namespace N2 { + static int32_t N2_V1 = 1; + + enum E3 : int32_t { N1_V1 }; // NON_COMPLIANT: unscoped in namespace + hides N1::N1_V1 + enum E4 : int32_t { G2 }; // NON_COMPLIANT: unscoped in namespace + hides ::G2 + enum class E5 : int32_t { N1_V1, G2 }; // COMPLIANT: scoped enum + } +} + +/* ========== 4. Anonymous namespace ========== */ +namespace { + enum E_Anon1 : int32_t { V1, V2 }; // NON_COMPLIANT: unscoped in anonymous namespace + enum { AnonAnon1, AnonAnon2 }; // NON_COMPLIANT: unscoped anonymous in anonymous namespace + enum class E_Anon2 : int32_t { V1 }; // COMPLIANT: scoped enum +} + +/* ========== 5. Anonymous namespace inside named namespace ========== */ +namespace N3 { + static int32_t N3_V1 = 1; + + namespace { + enum E1 : int32_t { N3_V1 }; // NON_COMPLIANT: unscoped + hides N3::N3_V1 + enum class E2 : int32_t { N3_V1 }; // COMPLIANT: scoped enum + } +} + +/* ========== 6. Nested classes ========== */ +class C1 { + static int32_t C1_V1; + + enum E1 { G1 }; // COMPLIANT: unscoped in class (exception) + hides ::G1 + enum { C1_Anon1, C1_Anon2 }; // COMPLIANT: unscoped anonymous in class (exception) + enum class E2 { G1 }; // COMPLIANT: scoped enum + + class C2 { + enum E3 { C1_V1 }; // COMPLIANT: unscoped in nested class (exception) + enum E4 { G2 }; // COMPLIANT: unscoped in nested class (exception) + hides ::G2 + + struct S1 { + enum E5 { C1_V1 }; // COMPLIANT: unscoped in struct (exception) + enum class E6 { C1_V1 }; // COMPLIANT: scoped enum + }; + }; +}; + +/* ========== 7. Struct at global scope ========== */ +struct S_Global { + enum E1 { G1 }; // COMPLIANT: unscoped in struct (exception) + enum { S_Anon1, S_Anon2 }; // COMPLIANT: unscoped anonymous in struct (exception) + enum class E2 { G1 }; // COMPLIANT: scoped enum +}; + +/* ========== 8. Class inside namespace ========== */ +namespace N4 { + static int32_t N4_V1 = 1; + + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in namespace + + class C1 { + enum E2 { N4_V1 }; // COMPLIANT: unscoped in class (exception) + hides N4::N4_V1 + enum E3 { G2 }; // COMPLIANT: unscoped in class (exception) + hides ::G2 + enum class E4 { N4_V1, G2 }; // COMPLIANT: scoped enum + }; +} + +/* ========== 9. Function body ========== */ +void f1() { + int F1_V1 = 1; + + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in function + hides ::G1 + enum { F1_Anon1, F1_Anon2 }; // NON_COMPLIANT: unscoped anonymous in function + enum class E2 : int32_t { G1 }; // COMPLIANT: scoped enum +} + +/* ========== 10. Nested blocks ========== */ +void f2() { + int F2_V1 = 1; + + { + int F2_V2 = 2; + + enum E1 : int32_t { F2_V1 }; // NON_COMPLIANT: unscoped in block + hides outer F2_V1 + enum E2 : int32_t { G2 }; // NON_COMPLIANT: unscoped in block + hides ::G2 + + { + enum E3 : int32_t { F2_V2 }; // NON_COMPLIANT: unscoped in nested block + hides outer F2_V2 + enum class E4 : int32_t { F2_V1, F2_V2, G1 }; // COMPLIANT: scoped enum + } + } +} + +/* ========== 11. Local class in function ========== */ +void f3() { + int F3_V1 = 1; + + class LocalC1 { + enum E1 { F3_V1 }; // COMPLIANT: unscoped in local class (exception) + enum E2 { G1 }; // COMPLIANT: unscoped in local class (exception) + hides ::G1 + enum { Local_Anon1 }; // COMPLIANT: unscoped anonymous in local class (exception) + enum class E3 { F3_V1, G1 }; // COMPLIANT: scoped enum + }; +} + +/* ========== 12. Lambda body ========== */ +auto lambda1 = []() { + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in lambda body + enum { Lambda_Anon1 }; // NON_COMPLIANT: unscoped anonymous in lambda body + enum class E2 : int32_t { G1 }; // COMPLIANT: scoped enum +}; + +/* ========== 13. Nested lambdas ========== */ +namespace N5 { + auto lambda2 = []() { + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in lambda body + + auto nested_lambda = []() { + enum E2 : int32_t { G2 }; // NON_COMPLIANT: unscoped in nested lambda body + enum class E3 : int32_t { G1, G2 }; // COMPLIANT: scoped enum + }; + }; +} + +/* ========== 14. Lambda inside class ========== */ +class C3 { + static inline auto member_lambda = []() { + enum E1 : int32_t { G1 }; // NON_COMPLIANT: unscoped in lambda body (not class scope!) + enum class E2 : int32_t { G1 }; // COMPLIANT: scoped enum + }; +}; + +int main() { + return 0; +} diff --git a/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.expected b/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.expected new file mode 100644 index 000000000..c03ec0e53 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.expected @@ -0,0 +1,85 @@ +| test.cpp:35:3:35:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:36:3:36:7 | ... - ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:37:3:37:7 | ... * ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:38:3:38:7 | ... / ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:39:3:39:7 | ... % ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:51:3:51:8 | ... \| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:52:3:52:8 | ... & ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:53:3:53:8 | ... ^ ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:65:3:65:8 | ... << ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:66:3:66:8 | ... >> ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:78:3:78:8 | ... && ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:79:3:79:9 | ... \|\| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:91:3:91:8 | ... += ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:92:3:92:8 | ... -= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:93:3:93:8 | ... *= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:94:3:94:8 | ... /= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:95:3:95:8 | ... \|= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:96:3:96:8 | ... &= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:97:3:97:8 | ... ^= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:98:3:98:9 | ... <<= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:99:3:99:9 | ... >>= ... | Compound assignment uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:120:3:120:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:121:3:121:7 | ... < ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:122:3:122:8 | ... != ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:150:3:150:9 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:11:6:11:18 | UnfixedMedium | UnfixedMedium | +| test.cpp:156:3:156:10 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:157:3:157:11 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed short' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:158:3:158:11 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed int' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:163:3:163:10 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:164:3:164:11 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed short' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:165:3:165:11 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'signed int' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:166:3:166:11 | ... = ... | Assignment from unscoped enum $@ without fixed underlying type to 'unsigned int' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:195:3:195:9 | case ...: | Switch on unscoped enum $@ without fixed underlying type has case not of the same enum type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:202:3:202:10 | case ...: | Switch on unscoped enum $@ without fixed underlying type has case not of the same enum type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:235:3:235:30 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:11:6:11:18 | UnfixedMedium | UnfixedMedium | +| test.cpp:236:3:236:23 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'char' which may not be large enough. | test.cpp:11:6:11:18 | UnfixedMedium | UnfixedMedium | +| test.cpp:242:3:242:31 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:243:3:243:32 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed short' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:244:3:244:32 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed int' which may not be large enough. | test.cpp:14:6:14:18 | UnfixedLargeU | UnfixedLargeU | +| test.cpp:249:3:249:31 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed char' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:250:3:250:32 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed short' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:251:3:251:32 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'signed int' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:252:3:253:10 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'unsigned int' which may not be large enough. | test.cpp:17:6:17:18 | UnfixedLargeS | UnfixedLargeS | +| test.cpp:257:3:257:26 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'Unfixed2' which may not be large enough. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:257:3:257:26 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:258:3:258:23 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'Fixed' which may not be large enough. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:259:3:259:24 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'Scoped' which may not be large enough. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:271:3:271:25 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:282:3:282:25 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:283:3:283:25 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:284:3:284:26 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:285:3:285:27 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:298:3:298:23 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'Fixed' which may not be large enough. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:311:3:311:24 | static_cast... | Static cast from unscoped enum $@ without fixed underlying type to 'Scoped' which may not be large enough. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:324:3:324:25 | static_cast... | Static cast to unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:335:3:335:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:336:3:336:7 | ... < ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:337:3:337:8 | ... != ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:343:3:343:26 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:357:3:357:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:358:3:358:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:359:3:359:7 | ... - ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:363:3:363:8 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:372:3:372:7 | ... \| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:373:3:373:7 | ... & ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:374:3:374:7 | ... ^ ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:375:3:375:7 | ... \| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:386:3:386:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:386:3:386:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:387:3:387:7 | ... < ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:387:3:387:7 | ... < ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:388:3:388:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:388:3:388:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:389:3:389:7 | ... \| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:389:3:389:7 | ... \| ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:394:3:394:10 | case ...: | Switch on unscoped enum $@ without fixed underlying type has case not of the same enum type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:427:3:427:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:428:3:428:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:429:3:429:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:430:3:430:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:431:3:431:7 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:7:6:7:13 | Unfixed2 | Unfixed2 | +| test.cpp:433:3:433:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:434:3:434:8 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:6:6:6:12 | Unfixed | Unfixed | +| test.cpp:461:5:461:9 | ... + ... | Arithmetic, bitwise, or logical operation uses unscoped enum $@ without fixed underlying type. | test.cpp:456:8:456:20 | MemberUnfixed | MemberUnfixed | +| test.cpp:462:5:462:10 | ... == ... | Relational or equality operation compares unscoped enum $@ without fixed underlying type to a different type. | test.cpp:456:8:456:20 | MemberUnfixed | MemberUnfixed | diff --git a/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.qlref b/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.qlref new file mode 100644 index 000000000..5d4ae9985 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.qlref @@ -0,0 +1 @@ +rules/RULE-10-2-3/UnscopedEnumWithoutFixedUnderlyingTypeUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-2-3/test.cpp b/cpp/misra/test/rules/RULE-10-2-3/test.cpp new file mode 100644 index 000000000..f4660dc87 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-3/test.cpp @@ -0,0 +1,467 @@ +#include + +/* ========== 1. Fixtures ========== */ + +// Unscoped, no fixed type - narrowest possible: char +enum Unfixed { U0, U1, U2 }; +enum Unfixed2 { V0 = 10, V1, V2 }; + +// Unscoped, no fixed type - narrowest possible: std::int16_t (needs > 127 +// signed) +enum UnfixedMedium { UM0 = -1, UM1 = 1000 }; + +// Unscoped, no fixed type - narrowest possible: std::uint32_t +enum UnfixedLargeU { ULU0 = 0x7FFFFFFF, ULU1 }; + +// Unscoped, no fixed type - narrowest possible: std::int64_t +enum UnfixedLargeS { ULS0 = -1, ULS1 = 0x80000000 }; + +// Unscoped, with fixed type +enum Fixed : std::int32_t { F0 = 20, F1, F2 }; +enum Fixed2 : std::int32_t { G0 = 30, G1, G2 }; + +// Scoped enum (defaults to int) +enum class Scoped { S0, S1, S2 }; + +// Scoped, with fixed type +enum class ScopedFixed : std::int32_t { SF0, SF1, SF2 }; + +/* ========== 2. Arithmetic operators ========== */ + +void arithmetic() { + Unfixed u = U0; + Fixed f = F0; + + u + 1; // NON_COMPLIANT: arithmetic on unfixed unscoped enum + u - 1; // NON_COMPLIANT: arithmetic on unfixed unscoped enum + u * 2; // NON_COMPLIANT: arithmetic on unfixed unscoped enum + u / 2; // NON_COMPLIANT: arithmetic on unfixed unscoped enum + u % 2; // NON_COMPLIANT: arithmetic on unfixed unscoped enum + + f + 1; // COMPLIANT: fixed underlying type + f - 1; // COMPLIANT: fixed underlying type +} + +/* ========== 3. Bitwise operators ========== */ + +void bitwise() { + Unfixed u = U0; + Fixed f = F0; + + u | U1; // NON_COMPLIANT: bitwise on unfixed unscoped enum + u & U1; // NON_COMPLIANT: bitwise on unfixed unscoped enum + u ^ U1; // NON_COMPLIANT: bitwise on unfixed unscoped enum + + f | F1; // COMPLIANT: fixed underlying type + f & F1; // COMPLIANT: fixed underlying type +} + +/* ========== 4. Shift operators ========== */ + +void shift() { + Unfixed u = U0; + Fixed f = F0; + + u << 1; // NON_COMPLIANT: shift on unfixed unscoped enum + u >> 1; // NON_COMPLIANT: shift on unfixed unscoped enum + + f << 1; // COMPLIANT: fixed underlying type + f >> 1; // COMPLIANT: fixed underlying type +} + +/* ========== 5. Logical operators ========== */ + +void logical() { + Unfixed u = U0; + Fixed f = F0; + + u &&U1; // NON_COMPLIANT: logical on unfixed unscoped enum + u || U1; // NON_COMPLIANT: logical on unfixed unscoped enum + + f &&F1; // COMPLIANT: fixed underlying type +} + +/* ========== 6. Compound assignment operators ========== */ + +void compound_assignment() { + Unfixed u = U0; + Fixed f = F0; + int i = 0; + + i += u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i -= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i *= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i /= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i |= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i &= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i ^= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i <<= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + i >>= u; // NON_COMPLIANT: compound assignment with unfixed unscoped enum + + i += f; // COMPLIANT: fixed underlying type + i |= f; // COMPLIANT: fixed underlying type +} + +/* ========== 7. Relational and equality operators ========== */ + +void relational() { + Unfixed u = U0; + Unfixed u2 = U1; + Fixed f = F0; + Fixed f2 = F1; + + u == u2; // COMPLIANT: same enum type + u != u2; // COMPLIANT: same enum type + u < u2; // COMPLIANT: same enum type + u > u2; // COMPLIANT: same enum type + u <= u2; // COMPLIANT: same enum type + u >= u2; // COMPLIANT: same enum type + + u == 0; // NON_COMPLIANT: comparing unfixed enum to int + u < 5; // NON_COMPLIANT: comparing unfixed enum to int + u != 1; // NON_COMPLIANT: comparing unfixed enum to int + + f == 0; // COMPLIANT: fixed underlying type + f < 5; // COMPLIANT: fixed underlying type +} + +/* ========== 8. Assignment ========== */ + +void assignment() { + Unfixed u = U0; // Narrowest: char + UnfixedMedium um = UM0; // Narrowest: std::int16_t + UnfixedLargeU ulu = ULU0; // Narrowest: std::uint32_t + UnfixedLargeS uls = ULS0; // Narrowest: std::int64_t + Fixed f = F0; + + std::int8_t i8; + std::int16_t i16; + std::int32_t i32; + std::uint32_t u32; + std::int64_t i64; + + // Unfixed { U0, U1, U2 } - narrowest: char + i8 = u; // COMPLIANT: std::int8_t >= char + i16 = u; // COMPLIANT: std::int16_t >= char + i32 = u; // COMPLIANT: std::int32_t >= char + i64 = u; // COMPLIANT: std::int64_t >= char + + // UnfixedMedium { UM0 = -1, UM1 = 1000 } - narrowest: std::int16_t + i8 = um; // NON_COMPLIANT: std::int8_t < std::int16_t + i16 = um; // COMPLIANT: std::int16_t >= std::int16_t + i32 = um; // COMPLIANT: std::int32_t >= std::int16_t + i64 = um; // COMPLIANT: std::int64_t >= std::int16_t + + // UnfixedLargeU { ULU0 = 0x7FFFFFFF, ULU1 } - narrowest: std::uint32_t + i8 = ulu; // NON_COMPLIANT: std::int8_t < std::uint32_t + i16 = ulu; // NON_COMPLIANT: std::int16_t < std::uint32_t + i32 = ulu; // NON_COMPLIANT: std::int32_t < std::uint32_t (signed vs unsigned) + u32 = ulu; // COMPLIANT: std::uint32_t >= std::uint32_t + i64 = ulu; // COMPLIANT: std::int64_t >= std::uint32_t + + // UnfixedLargeS { ULS0 = -1, ULS1 = 0x80000000 } - narrowest: std::int64_t + i8 = uls; // NON_COMPLIANT: std::int8_t < std::int64_t + i16 = uls; // NON_COMPLIANT: std::int16_t < std::int64_t + i32 = uls; // NON_COMPLIANT: std::int32_t < std::int64_t + u32 = uls; // NON_COMPLIANT: std::uint32_t < std::int64_t + i64 = uls; // COMPLIANT: std::int64_t >= std::int64_t + + // Fixed underlying type - rule doesn't apply + i8 = f; // COMPLIANT: fixed underlying type + i32 = f; // COMPLIANT: fixed underlying type + + Unfixed u2; + u2 = u; // COMPLIANT: same enum type +} + +/* ========== 9. Switch statements ========== */ + +void switch_statements() { + Unfixed u = U0; + Fixed f = F0; + + switch (u) { + case U0: + break; + case U1: + break; + case U2: + break; // COMPLIANT: all cases are enumerators of same type + } + + switch (u) { + case U0: + break; + case 5: + break; // NON_COMPLIANT: mixed enumerator and integer literal + } + + switch (u) { + case U0: + break; + case F0: + break; // NON_COMPLIANT: mixed enumerators from different enums + } + + switch (f) { + case F0: + break; + case 5: + break; // COMPLIANT: fixed underlying type + } +} + +/* ========== 10. static_cast FROM unfixed enum ========== */ + +void static_cast_from_unfixed() { + Unfixed u = U0; // Narrowest: char + UnfixedMedium um = UM0; // Narrowest: std::int16_t + UnfixedLargeU ulu = ULU0; // Narrowest: std::uint32_t + UnfixedLargeS uls = ULS0; // Narrowest: std::int64_t + + // Target is same enumeration type + static_cast(u); // COMPLIANT: same enum type + + // Unfixed { U0, U1, U2 } - narrowest: char + static_cast(u); // COMPLIANT: std::int8_t >= char + static_cast(u); // COMPLIANT: std::int16_t >= char + static_cast(u); // COMPLIANT: std::int32_t >= char + static_cast(u); // COMPLIANT: std::int64_t >= char + static_cast(u); // COMPLIANT: int >= char + static_cast(u); // COMPLIANT: long >= char + static_cast(u); // COMPLIANT: unsigned int >= char + + // UnfixedMedium { UM0 = -1, UM1 = 1000 } - narrowest: std::int16_t + static_cast(um); // NON_COMPLIANT: std::int8_t < std::int16_t + static_cast(um); // NON_COMPLIANT: char < std::int16_t + static_cast(um); // COMPLIANT: std::int16_t >= std::int16_t + static_cast(um); // COMPLIANT: std::int32_t >= std::int16_t + static_cast(um); // COMPLIANT: std::int64_t >= std::int16_t + + // UnfixedLargeU { ULU0 = 0x7FFFFFFF, ULU1 } - narrowest: std::uint32_t + static_cast(ulu); // NON_COMPLIANT: std::int8_t < std::uint32_t + static_cast(ulu); // NON_COMPLIANT: std::int16_t < std::uint32_t + static_cast(ulu); // NON_COMPLIANT: std::int32_t < std::uint32_t + static_cast(ulu); // COMPLIANT: std::uint32_t >= std::uint32_t + static_cast(ulu); // COMPLIANT: std::int64_t >= std::uint32_t + + // UnfixedLargeS { ULS0 = -1, ULS1 = 0x80000000 } - narrowest: std::int64_t + static_cast(uls); // NON_COMPLIANT: std::int8_t < std::int64_t + static_cast(uls); // NON_COMPLIANT: std::int16_t < std::int64_t + static_cast(uls); // NON_COMPLIANT: std::int32_t < std::int64_t + static_cast( + uls); // NON_COMPLIANT: std::uint32_t < std::int64_t + static_cast(uls); // COMPLIANT: std::int64_t >= std::int64_t + + // Target is different enumeration type + static_cast(u); // NON_COMPLIANT: different enum type + static_cast(u); // NON_COMPLIANT: different enum type + static_cast(u); // NON_COMPLIANT: different enum type +} + +/* ========== 11. static_cast FROM fixed enum ========== */ + +void static_cast_from_fixed() { + Fixed f = F0; + + // All compliant because source has fixed underlying type + static_cast(f); // COMPLIANT: fixed underlying type + static_cast(f); // COMPLIANT: fixed underlying type + static_cast(f); // COMPLIANT: fixed underlying type + static_cast(f); // NON_COMPLIANT: target is unfixed enum +} + +/* ========== 12. static_cast TO unfixed enum ========== */ + +void static_cast_to_unfixed() { + int i = 0; + std::int8_t i8 = 0; + std::int64_t i64 = 0; + + // Any static_cast from non-enum to unfixed enum is non-compliant + static_cast(0); // NON_COMPLIANT: unfixed enum as target + static_cast(i); // NON_COMPLIANT: unfixed enum as target + static_cast(i8); // NON_COMPLIANT: unfixed enum as target + static_cast(i64); // NON_COMPLIANT: unfixed enum as target +} + +/* ========== 13. static_cast TO fixed enum ========== */ + +void static_cast_to_fixed() { + int i = 0; + Unfixed u = U0; + + // Fixed enum as target is compliant + static_cast(0); // COMPLIANT: fixed enum as target + static_cast(i); // COMPLIANT: fixed enum as target + static_cast(F0); // COMPLIANT: fixed enum as target + static_cast(u); // NON_COMPLIANT: source is unfixed enum, target is + // different type +} + +/* ========== 14. static_cast TO scoped enum ========== */ + +void static_cast_to_scoped() { + int i = 0; + Unfixed u = U0; + + // Scoped enums have fixed underlying type (defaults to int) + static_cast(0); // COMPLIANT: scoped enum has fixed type + static_cast(i); // COMPLIANT: scoped enum has fixed type + static_cast(u); // NON_COMPLIANT: source is unfixed enum, target is + // different type +} + +/* ========== 15. static_cast FROM scoped enum ========== */ + +void static_cast_from_scoped() { + Scoped s = Scoped::S0; + + // Scoped enums have fixed underlying type + static_cast(s); // COMPLIANT: scoped enum has fixed type + static_cast(s); // COMPLIANT: scoped enum has fixed type + static_cast(s); // COMPLIANT: same type, fixed + static_cast(s); // NON_COMPLIANT: target is unfixed enum +} + +/* ========== 16. Cross-enum relational operators ========== */ + +void cross_enum_relational() { + Unfixed u = U0; + Fixed f = F0; + Scoped s = Scoped::S0; + + // Unfixed vs Fixed (both unscoped, different types) + u == f; // NON_COMPLIANT: different enum types, unfixed operand + u < f; // NON_COMPLIANT: different enum types, unfixed operand + u != f; // NON_COMPLIANT: different enum types, unfixed operand + + // Fixed vs Fixed (same type) + f == F1; // COMPLIANT: same enum type, fixed + + // Unfixed vs Scoped - with cast + u == static_cast(s); // NON_COMPLIANT: unfixed enum compared to int + static_cast(u) == static_cast(s); // COMPLIANT: comparing ints + + // Fixed vs Scoped - with cast + f == static_cast(s); // COMPLIANT: fixed enum compared to int +} + +/* ========== 17. Cross-enum arithmetic operators ========== */ + +void cross_enum_arithmetic() { + Unfixed u = U0; + Fixed f = F0; + Scoped s = Scoped::S0; + + u + f; // NON_COMPLIANT: arithmetic with unfixed operand + f + u; // NON_COMPLIANT: arithmetic with unfixed operand + u - f; // NON_COMPLIANT: arithmetic with unfixed operand + + f + static_cast(s); // COMPLIANT: fixed enum + int + + u + U1; // NON_COMPLIANT: arithmetic on unfixed +} + +/* ========== 18. Cross-enum bitwise operators ========== */ + +void cross_enum_bitwise() { + Unfixed u = U0; + Fixed f = F0; + + u | f; // NON_COMPLIANT: bitwise with unfixed operand + u & f; // NON_COMPLIANT: bitwise with unfixed operand + u ^ f; // NON_COMPLIANT: bitwise with unfixed operand + f | u; // NON_COMPLIANT: bitwise with unfixed operand + + f | F1; // COMPLIANT: both fixed, same type +} + +/* ========== 19. Two different unfixed enums ========== */ + +void two_unfixed() { + Unfixed u = U0; + Unfixed2 v = V0; + + u == v; // NON_COMPLIANT: different enum types, both unfixed + u < v; // NON_COMPLIANT: different enum types, both unfixed + u + v; // NON_COMPLIANT: arithmetic on unfixed + u | v; // NON_COMPLIANT: bitwise on unfixed + + switch (u) { + case U0: + break; + case V0: + break; // NON_COMPLIANT: case from different unfixed enum + } +} + +/* ========== 20. Two different fixed enums ========== */ + +void two_fixed() { + Fixed f = F0; + Fixed2 g = G0; + + f == g; // COMPLIANT: both have fixed underlying type + f < g; // COMPLIANT: both have fixed underlying type + f + g; // COMPLIANT: both have fixed underlying type + f | g; // COMPLIANT: both have fixed underlying type + + switch (f) { + case F0: + break; + case G0: + break; // COMPLIANT: both have fixed underlying type + } +} + +/* ========== 21. Mixed fixed and unfixed ========== */ + +void mixed_fixed_unfixed() { + Unfixed u = U0; + Fixed f = F0; + Unfixed2 v = V0; + Fixed2 g = G0; + + // The presence of ANY unfixed operand makes it non-compliant + u + f; // NON_COMPLIANT: u is unfixed + f + u; // NON_COMPLIANT: u is unfixed + u + g; // NON_COMPLIANT: u is unfixed + v + f; // NON_COMPLIANT: v is unfixed + v + g; // NON_COMPLIANT: v is unfixed + + u == f; // NON_COMPLIANT: u is unfixed, different types + f == u; // NON_COMPLIANT: u is unfixed, different types + + f + g; // COMPLIANT: both fixed + f == g; // COMPLIANT: both fixed +} + +/* ========== 22. Scoped enum operations ========== */ + +void scoped_enum_ops() { + Scoped s = Scoped::S0; + + // These don't compile without explicit cast, so they're safe by design + // s + 1; // Would not compile + // s == 0; // Would not compile + + static_cast(s); // COMPLIANT: scoped enum + static_cast(1); // COMPLIANT: scoped enum +} + +/* ========== 23. Member unfixed enum ========== */ + +class C1 { + enum MemberUnfixed { M0, M1, M2 }; + + void member_ops() { + MemberUnfixed m = M0; + + m + 1; // NON_COMPLIANT: arithmetic on unfixed enum (even if member) + m == 0; // NON_COMPLIANT: comparing unfixed enum to int (even if member) + m == M1; // COMPLIANT: same enum type + } +}; + +int main() { return 0; } diff --git a/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.expected b/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.expected new file mode 100644 index 000000000..2b76a4154 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.expected @@ -0,0 +1,3 @@ +| test.hpp:5:1:5:9 | (unnamed namespace) | Anonymous namespace declared in header file $@. | test.hpp:0:0:0:0 | test.hpp | test.hpp | +| test.hpp:32:1:32:9 | Outer::(unnamed namespace) | Anonymous namespace declared in header file $@. | test.hpp:0:0:0:0 | test.hpp | test.hpp | +| test.hpp:41:1:41:9 | (unnamed namespace) | Anonymous namespace declared in header file $@. | test.hpp:0:0:0:0 | test.hpp | test.hpp | diff --git a/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.qlref b/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.qlref new file mode 100644 index 000000000..b8e94fdbf --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.qlref @@ -0,0 +1 @@ +rules/RULE-10-3-1/UnnamedNamespacesInHeaderFiles.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-3-1/test.hpp b/cpp/misra/test/rules/RULE-10-3-1/test.hpp new file mode 100644 index 000000000..9154eba28 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-3-1/test.hpp @@ -0,0 +1,44 @@ +#include + +/* ========== 1. Non-compliant: anonymous namespace in header ========== */ + +namespace { // NON_COMPLIANT: anonymous namespace in header file +inline std::int32_t x = 0; + +void helper() {} + +class InternalClass {}; +} // namespace + +/* ========== 2. Compliant: named namespace in header ========== */ + +namespace MyNamespace { // COMPLIANT: named namespace +inline std::int32_t y = 0; + +void publicHelper(); + +class PublicClass {}; +} // namespace MyNamespace + +/* ========== 3. Compliant: no namespace ========== */ + +inline std::int32_t z = 0; // COMPLIANT: no anonymous namespace + +void declaredFunction(); + +/* ========== 4. Non-compliant: nested anonymous namespace ========== */ + +namespace Outer { +namespace { // NON_COMPLIANT: anonymous namespace in header file +inline std::int32_t nested = 0; +} +} // namespace Outer + +/* ========== 5. Non-compliant: anonymous namespace with extern "C" ========== + */ + +extern "C" { +namespace { // NON_COMPLIANT: anonymous namespace in header file +inline std::int32_t cStyleVar = 0; +} +} diff --git a/cpp/misra/test/rules/RULE-10-3-1/test1.cpp b/cpp/misra/test/rules/RULE-10-3-1/test1.cpp new file mode 100644 index 000000000..15ab5df64 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-3-1/test1.cpp @@ -0,0 +1,21 @@ +#include "test.hpp" + +/* + * This file demonstrates that anonymous namespace variables + * in headers create translation-unit-local copies. + */ + +void setValues() { + x = 42; // Sets file1.cpp's copy of x + MyNamespace::y = 42; // Sets the shared y + z = 42; // Sets the shared z + Outer::nested = 42; // Sets file1.cpp's copy of nested +} + +std::int32_t getX_File1() { + return x; // Returns file1.cpp's copy of x +} + +std::int32_t getNested_File1() { + return Outer::nested; // Returns file1.cpp's copy of nested +} diff --git a/cpp/misra/test/rules/RULE-10-3-1/test2.cpp b/cpp/misra/test/rules/RULE-10-3-1/test2.cpp new file mode 100644 index 000000000..ec97f3cb6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-3-1/test2.cpp @@ -0,0 +1,50 @@ +#include "test.hpp" +#include + +/* + * This file demonstrates the mismatch in expectations. + * After calling setValues() from file1.cpp: + * - x is 0 here (different copy) + * - MyNamespace::y is 42 (shared) + * - z is 42 (shared) + * - Outer::nested is 0 here (different copy) + */ + +extern void setValues(); +extern std::int32_t getX_File1(); +extern std::int32_t getNested_File1(); + +void checkMismatch() { + setValues(); + + /* + * These demonstrate the MISMATCH - anonymous namespace creates separate + * copies. + */ + assert(x == 0); // file2.cpp's x was never set! + assert(getX_File1() == 42); // file1.cpp's x was set + + assert(Outer::nested == 0); // file2.cpp's nested was never set! + assert(getNested_File1() == 42); // file1.cpp's nested was set + + /* These demonstrate EXPECTED behavior - named namespace and global are shared + */ + assert(MyNamespace::y == 42); // Shared across TUs + assert(z == 42); // Shared across TUs +} + +/* ========== 6. Compliant: anonymous namespace in .cpp file ========== */ + +namespace { // COMPLIANT: anonymous namespace in source file is fine +std::int32_t localVar = 0; + +void localHelper() { + localVar = 100; // Only visible in this TU, as expected +} +} // namespace + +int main() { + checkMismatch(); + localHelper(); + return 0; +} diff --git a/rule_packages/cpp/Banned2.json b/rule_packages/cpp/Banned2.json new file mode 100644 index 000000000..c5f4caaaa --- /dev/null +++ b/rule_packages/cpp/Banned2.json @@ -0,0 +1,25 @@ +{ + "MISRA-C++-2023": { + "RULE-10-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "An unscoped enumeration should not be used outside of a class/struct scope; use 'enum class' instead to prevent name clashes and implicit conversions to integral types.", + "kind": "problem", + "name": "Unscoped enumerations should not be declared", + "precision": "very-high", + "severity": "error", + "short_name": "UnscopedEnumerationsShouldNotBeDeclared", + "tags": [ + "scope/single-translation-unit", + "correctness" + ] + } + ], + "title": "Unscoped enumerations should not be declared" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Banned3.json b/rule_packages/cpp/Banned3.json new file mode 100644 index 000000000..5e281da93 --- /dev/null +++ b/rule_packages/cpp/Banned3.json @@ -0,0 +1,25 @@ +{ + "MISRA-C++-2023": { + "RULE-10-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Treating unscoped enumeration without a fixed underlying type as an integral type is not portable and might cause unintended behaviors.", + "kind": "problem", + "name": "The numeric value of an unscoped enumeration with no fixed underlying type shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UnscopedEnumWithoutFixedUnderlyingTypeUsed", + "tags": [ + "scope/single-translation-unit", + "correctness" + ] + } + ], + "title": "The numeric value of an unscoped enumeration with no fixed underlying type shall not be used" + } + } +} diff --git a/rule_packages/cpp/Banned4.json b/rule_packages/cpp/Banned4.json new file mode 100644 index 000000000..1ed9e8bf8 --- /dev/null +++ b/rule_packages/cpp/Banned4.json @@ -0,0 +1,25 @@ +{ + "MISRA-C++-2023": { + "RULE-10-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Anonymous namespaces in header files create separate entities in each translation unit, which may not be consistent with developer expectations.", + "kind": "problem", + "name": "There should be no unnamed namespaces in header files", + "precision": "very-high", + "severity": "error", + "short_name": "UnnamedNamespacesInHeaderFiles", + "tags": [ + "scope/single-translation-unit", + "correctness" + ] + } + ], + "title": "There should be no unnamed namespaces in header files" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index b537ab411..f90c93868 100644 --- a/rules.csv +++ b/rules.csv @@ -918,9 +918,9 @@ cpp,MISRA-C++-2023,RULE-10-0-1,Yes,Advisory,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-10-1-1,Yes,Advisory,Decidable,Single Translation Unit,The target type of a pointer or lvalue reference parameter should be const-qualified appropriately,RULE-8-13,Declarations2,Hard, cpp,MISRA-C++-2023,RULE-10-1-2,Yes,Required,Decidable,Single Translation Unit,The volatile qualifier shall be used appropriately,,Declarations2,Easy, cpp,MISRA-C++-2023,RULE-10-2-1,Yes,Required,Decidable,Single Translation Unit,An enumeration shall be defined with an explicit underlying type,A7-2-2,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-10-2-2,Yes,Advisory,Decidable,Single Translation Unit,Unscoped enumerations should not be declared,A7-2-3,Banned,Easy, -cpp,MISRA-C++-2023,RULE-10-2-3,Yes,Required,Decidable,Single Translation Unit,The numeric value of an unscoped enumeration with no fixed underlying type shall not be used,A4-5-1,Banned,Easy, -cpp,MISRA-C++-2023,RULE-10-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be no unnamed namespaces in header files,"DCL59-CPP, M7-3-3",Banned,Easy, +cpp,MISRA-C++-2023,RULE-10-2-2,Yes,Advisory,Decidable,Single Translation Unit,Unscoped enumerations should not be declared,A7-2-3,Banned2,Easy, +cpp,MISRA-C++-2023,RULE-10-2-3,Yes,Required,Decidable,Single Translation Unit,The numeric value of an unscoped enumeration with no fixed underlying type shall not be used,A4-5-1,Banned3,Easy, +cpp,MISRA-C++-2023,RULE-10-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be no unnamed namespaces in header files,"DCL59-CPP, M7-3-3",Banned4,Easy, cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,The asm declaration shall not be used,A7-4-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-11-3-1,Yes,Advisory,Decidable,Single Translation Unit,Variables of array type should not be declared,,Declarations2,Easy, cpp,MISRA-C++-2023,RULE-11-3-2,Yes,Advisory,Decidable,Single Translation Unit,The declaration of an object should contain no more than two levels of pointer indirection,A5-0-3,ImportMisra23,Import,