Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Banned2.qll
Original file line number Diff line number Diff line change
@@ -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()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import codingstandards.cpp.exclusions.RuleMetadata
//** Import packages for this language **/
import Allocations
import Banned1
import Banned2
import BannedAPIs
import BannedFunctions
import BannedLibraries
Expand Down Expand Up @@ -92,6 +93,7 @@ import VirtualFunctions
newtype TCPPQuery =
TAllocationsPackageQuery(AllocationsQuery q) or
TBanned1PackageQuery(Banned1Query q) or
TBanned2PackageQuery(Banned2Query q) or
TBannedAPIsPackageQuery(BannedAPIsQuery q) or
TBannedFunctionsPackageQuery(BannedFunctionsQuery q) or
TBannedLibrariesPackageQuery(BannedLibrariesQuery q) or
Expand Down Expand Up @@ -180,6 +182,7 @@ 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
isBannedAPIsQueryMetadata(query, queryId, ruleId, category) or
isBannedFunctionsQueryMetadata(query, queryId, ruleId, category) or
isBannedLibrariesQueryMetadata(query, queryId, ruleId, category) or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @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 MemberUnscopedEnum extends Enum {
MemberUnscopedEnum() {
not this instanceof ScopedEnum and
exists(Class klass | klass = this.getEnclosingElement())
}
}

from Enum enum
where
not isExcluded(enum, Banned2Package::unscopedEnumerationsShouldNotBeDeclaredQuery()) and
not (enum instanceof ScopedEnum or enum instanceof MemberUnscopedEnum)
select enum, "This enumeration is an unscoped enum not enclosed in a class or a struct."
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No expected results have yet been specified
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-10-2-2/UnscopedEnumerationsShouldNotBeDeclared.ql
152 changes: 152 additions & 0 deletions cpp/misra/test/rules/RULE-10-2-2/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#include <cstdint>

/* ========== 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;
}
25 changes: 25 additions & 0 deletions rule_packages/cpp/Banned2.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
Loading