Skip to content

Commit 6b24e50

Browse files
committed
RULE-8-2-2 - NoCStyleOrFunctionalCasts
Detects C-style casts and functional notation casts that should be replaced with explicit cast operators. Prevents unsafe type conversions that lack clear intent and proper type checking constraints. [a]
1 parent 10bb7e4 commit 6b24e50

File tree

4 files changed

+199
-0
lines changed

4 files changed

+199
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @id cpp/misra/no-c-style-or-functional-casts
3+
* @name RULE-8-2-2: C-style casts and functional notation casts shall not be used
4+
* @description Using C-style casts or functional notation casts allows unsafe type conversions and
5+
* makes code harder to maintain compared to using named casts like const_cast,
6+
* dynamic_cast, static_cast and reinterpret_cast.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-8-2-2
11+
* scope/single-translation-unit
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
import codingstandards.cpp.CStyleCasts
19+
import codingstandards.cpp.AlertReporting
20+
21+
class MISRACPPProhibitedCStyleCasts extends ExplicitUserDefinedCStyleCast {
22+
MISRACPPProhibitedCStyleCasts() {
23+
// MISRA C++ permits casts to void types
24+
not getType() instanceof VoidType
25+
}
26+
}
27+
28+
from Element reportingElement, MISRACPPProhibitedCStyleCasts c
29+
where
30+
not isExcluded(c, Conversions2Package::noCStyleOrFunctionalCastsQuery()) and
31+
reportingElement = MacroUnwrapper<MISRACPPProhibitedCStyleCasts>::unwrapElement(c) and
32+
exists(reportingElement.getFile().getRelativePath()) // within user code - validated during testing
33+
select reportingElement, "Use of explicit c-style cast to " + c.getType().getName() + "."
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| test.cpp:8:22:8:37 | (uint32_t)... | Use of explicit c-style cast to uint32_t. |
2+
| test.cpp:9:22:9:32 | (unsigned int)... | Use of explicit c-style cast to unsigned int. |
3+
| test.cpp:70:1:70:31 | #define ADD_ONE(x) ((int)x) + 1 | Use of explicit c-style cast to int. |
4+
| test.cpp:83:19:83:26 | (int)... | Use of explicit c-style cast to int. |
5+
| test.cpp:84:27:84:34 | (int)... | Use of explicit c-style cast to int. |
6+
| test.cpp:112:10:112:13 | (int)... | Use of explicit c-style cast to int. |
7+
| test.cpp:147:12:147:26 | (unsigned int)... | Use of explicit c-style cast to unsigned int. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include <cstdint>
2+
#include <string>
3+
#include <utility>
4+
int foo() { return 1; }
5+
// A copy of A5-2-2 test.cpp, but with different cases compliant/non-compliant
6+
void test_c_style_cast() {
7+
double f = 3.14;
8+
std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast
9+
std::uint32_t n2 = unsigned(f); // NON_COMPLIANT - functional notation
10+
11+
std::uint8_t n3 = 1;
12+
std::uint8_t n4 = 1;
13+
std::uint8_t n5 = n3 + n4; // ignored, implicit casts
14+
15+
(void)foo(); // COMPLIANT - permitted by MISRA C++
16+
}
17+
18+
class A {
19+
public:
20+
virtual void f1() {}
21+
};
22+
23+
class B : A {
24+
public:
25+
virtual void f1() {}
26+
};
27+
28+
class C {
29+
void f1() {}
30+
};
31+
32+
void test_cpp_style_cast() {
33+
// These cases may contravene other rules, but are marked as COMPLIANT for
34+
// this rule
35+
A a1;
36+
const A *a2 = &a1;
37+
A *a3 = const_cast<A *>(a2); // COMPLIANT
38+
B *b = dynamic_cast<B *>(a3); // COMPLIANT
39+
C *c = reinterpret_cast<C *>(a3); // COMPLIANT
40+
std::int16_t n8 = 0;
41+
std::int32_t n9 = static_cast<std::int32_t>(n8); // COMPLIANT
42+
static_cast<void>(foo()); // COMPLIANT
43+
}
44+
45+
class A5_2_2a {
46+
public:
47+
template <typename... As>
48+
static void Foo(const std::string &name, As &&...rest) {
49+
Fun(Log(std::forward<As>(
50+
rest)...)); // COMPLIANT - previously reported as a false positive
51+
}
52+
53+
template <typename... As> static std::string Log(As &&...tail) {
54+
return std::string();
55+
}
56+
57+
static void Fun(const std::string &message) {}
58+
};
59+
60+
class A5_2_2 final {
61+
public:
62+
void f(const std::string &s) const { A5_2_2a::Foo("name", "x", "y", "z"); }
63+
};
64+
65+
void a5_2_2_test() {
66+
A5_2_2 a;
67+
a.f("");
68+
}
69+
70+
#define ADD_ONE(x) ((int)x) + 1 // NON_COMPLIANT
71+
#define NESTED_ADD_ONE(x) ADD_ONE(x) // Not reported - reported at ADD_ONE
72+
#define NO_CAST_ADD_ONE(x) x + 1 // COMPLIANT
73+
74+
#include "macro_c_style_casts.h"
75+
76+
void test_macro_cast() {
77+
ADD_ONE(1); // Reported at macro definition site
78+
NESTED_ADD_ONE(1); // reported at macro definition site
79+
LIBRARY_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined in a
80+
// library, and is not modifiable by the user
81+
LIBRARY_NESTED_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined
82+
// in a library, and is not modifiable by the user
83+
NO_CAST_ADD_ONE((int)1.0); // NON_COMPLIANT - cast in argument to macro
84+
LIBRARY_NO_CAST_ADD_TWO((int)1.0); // NON_COMPLIANT - library macro with
85+
// c-style cast in argument, written by
86+
// user so should be reported
87+
}
88+
89+
class D {
90+
public:
91+
D(int x) : fx(x), fy(0) {}
92+
D(int x, int y) : fx(x), fy(y) {}
93+
94+
private:
95+
int fx;
96+
int fy;
97+
};
98+
99+
D testNonFunctionalCast() {
100+
return (D)1; // COMPLIANT
101+
}
102+
103+
D testFunctionalCast() {
104+
return D(1); // COMPLIANT
105+
}
106+
107+
D testFunctionalCastMulti() {
108+
return D(1, 2); // COMPLIANT
109+
}
110+
111+
template <typename T> T testFunctionalCastTemplate() {
112+
return T(1); // NON_COMPLIANT - used with an int
113+
}
114+
115+
template <typename T> T testFunctionalCastTemplateMulti() {
116+
return T(1, 2); // COMPLIANT
117+
}
118+
119+
void testFunctionalCastTemplateUse() {
120+
testFunctionalCastTemplate<D>();
121+
testFunctionalCastTemplate<int>();
122+
testFunctionalCastTemplateMulti<D>();
123+
}
124+
125+
template <typename T> class E {
126+
public:
127+
class F {
128+
public:
129+
F(int x) : fx(x), fy(0) {}
130+
F(int x, int y) : fx(x), fy(y) {}
131+
132+
private:
133+
int fx;
134+
int fy;
135+
};
136+
137+
F f() {
138+
return F(1); // COMPLIANT
139+
}
140+
141+
D d() {
142+
return D(1); // COMPLIANT
143+
}
144+
145+
int i() {
146+
double f = 3.14;
147+
return (unsigned int)f; // NON_COMPLIANT
148+
}
149+
};
150+
151+
class G {};
152+
153+
void testE() {
154+
E<G> e;
155+
e.f();
156+
e.d();
157+
e.i();
158+
}

0 commit comments

Comments
 (0)