Skip to content

Commit f450e53

Browse files
Merge remote-tracking branch 'origin/main' into michaelrfairhurst/declarations8-rule-6-2-3-do-not-duplicate-source-code
2 parents 8566bb2 + cee8713 commit f450e53

File tree

18 files changed

+816
-259
lines changed

18 files changed

+816
-259
lines changed

cpp/common/src/codingstandards/cpp/Extensions.qll

Lines changed: 227 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,231 @@ import cpp
66
abstract class CompilerExtension extends Locatable { }
77

88
/**
9-
* Common base class for modeling compiler extensions in CPP.
9+
* A usage of a compiler extension in C++ code, such as non-standard attributes or built-in function
10+
* calls.
1011
*/
11-
abstract class CPPCompilerExtension extends CompilerExtension { }
12+
abstract class CPPCompilerExtension extends CompilerExtension {
13+
abstract string getMessage();
14+
}
15+
16+
/**
17+
* An `Attribute` that may be a `GnuAttribute` or `Declspec`, or `MicrosoftAttribute`, etc.
18+
*
19+
* There are language extensions such as GNU `__attribute__`, Microsoft `__declspec` or
20+
* `[attribute]` syntax.
21+
*/
22+
class CPPAttributeExtension extends CPPCompilerExtension, Attribute {
23+
CPPAttributeExtension() { not this instanceof StdAttribute and not this instanceof AlignAs }
24+
25+
override string getMessage() {
26+
result =
27+
"Use of attribute '" + getName() +
28+
"' is a compiler extension and is not portable to other compilers."
29+
}
30+
}
31+
32+
/**
33+
* A `StdAttribute` within a compiler specific namespace such as `[[gnu::weak]]`.
34+
*/
35+
class CPPNamespacedStdAttributeExtension extends CPPCompilerExtension, StdAttribute {
36+
CPPNamespacedStdAttributeExtension() { exists(this.getNamespace()) and not getNamespace() = "" }
37+
38+
override string getMessage() {
39+
result =
40+
"Use of attribute '" + getName() + "' in namespace '" + getNamespace() +
41+
"' is a compiler extension and is not portable to other compilers."
42+
}
43+
}
44+
45+
/**
46+
* A `StdAttribute` with a name not recognized as part of the C++17 standard.
47+
*
48+
* Only the listed names are valid C++17. Namespaced attributes are handled by
49+
* `CPPNamespacedStdAttributeExtension` and not considered here.
50+
*/
51+
class CPPUnrecognizedAttributeExtension extends CPPCompilerExtension, StdAttribute {
52+
CPPUnrecognizedAttributeExtension() {
53+
not this instanceof CPPNamespacedStdAttributeExtension and
54+
not getName() in [
55+
"maybe_unused", "nodiscard", "noreturn", "deprecated", "carries_dependency", "fallthrough"
56+
]
57+
}
58+
59+
override string getMessage() {
60+
result = "Use of unrecognized or non-C++17 attribute '" + getName() + "'."
61+
}
62+
}
63+
64+
/**
65+
* A `FunctionCall` of a compiler-specific builtin function.
66+
*
67+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
68+
*/
69+
class CPPBuiltinFunctionExtension extends CPPCompilerExtension, FunctionCall {
70+
CPPBuiltinFunctionExtension() {
71+
getTarget().getName().indexOf("__builtin_") = 0 or
72+
getTarget().getName().indexOf("__sync_") = 0 or
73+
getTarget().getName().indexOf("__atomic_") = 0
74+
}
75+
76+
override string getMessage() {
77+
result =
78+
"Call to builtin function '" + getTarget().getName() +
79+
"' is a compiler extension and is not portable to other compilers."
80+
}
81+
}
82+
83+
/**
84+
* A `StmtExpr`, which uses `({ <stmts> })` syntax, which is a GNU extension.
85+
*
86+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
87+
*/
88+
class CPPStmtExprExtension extends CPPCompilerExtension, StmtExpr {
89+
override string getMessage() {
90+
result =
91+
"Statement expressions are a compiler extension and are not portable to other compilers."
92+
}
93+
}
94+
95+
/**
96+
* A `ConditionalExpr` using GNU-style omitted middle operand such as `x ?: y`.
97+
*
98+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html
99+
*/
100+
class CPPTerseTernaryExtension extends CPPCompilerExtension, ConditionalExpr {
101+
CPPTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() }
102+
103+
override string getMessage() {
104+
result =
105+
"Ternaries with omitted middle operands are a compiler extension and are not portable to " +
106+
"other compilers."
107+
}
108+
}
109+
110+
/**
111+
* A non-standard `Type` that is only available as a compiler extension, such as `__int128`,
112+
* `_Decimal32`, `_Decimal64`, `_Decimal128`, or `__float128`.
113+
*
114+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
115+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html
116+
*/
117+
class CPPExtensionType extends Type {
118+
CPPExtensionType() {
119+
this instanceof Int128Type or
120+
this instanceof Decimal128Type or
121+
this instanceof Decimal32Type or
122+
this instanceof Decimal64Type or
123+
this instanceof Float128Type
124+
}
125+
}
126+
127+
/**
128+
* A `DeclarationEntry` using an extended type such as `__int128`, `_Decimal32`, `_Decimal64`,
129+
* `_Decimal128`, or `__float128`.
130+
*
131+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
132+
*/
133+
class CPPExtensionTypeUsage extends CPPCompilerExtension, DeclarationEntry {
134+
CPPExtensionType extendedType;
135+
136+
CPPExtensionTypeUsage() { extendedType = getType() }
137+
138+
override string getMessage() {
139+
result =
140+
"Declaration of variable '" + getName() + "' as type '" + extendedType.getName() +
141+
"' requires a compiler extension and is not portable to other compilers."
142+
}
143+
}
144+
145+
/**
146+
* A `DeclarationEntry` using a zero-length array, which is a non-standard way to declare a flexible
147+
* array member.
148+
*
149+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
150+
*/
151+
class CPPZeroLengthArraysExtension extends CPPCompilerExtension, DeclarationEntry {
152+
ArrayType array;
153+
154+
CPPZeroLengthArraysExtension() {
155+
array = getType() and
156+
array.getArraySize() = 0
157+
}
158+
159+
override string getMessage() {
160+
result =
161+
"Declaration of variable '" + getName() + "' as a zero-length array (of '" +
162+
array.getBaseType() +
163+
"') requires a compiler extension and is not portable to other compilers."
164+
}
165+
}
166+
167+
/**
168+
* A `Field` with a variable-length array type in a struct member (not C++17 compliant).
169+
*
170+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
171+
*/
172+
class CPPVariableLengthArraysExtension extends CPPCompilerExtension, VlaDeclStmt {
173+
override string getMessage() {
174+
result =
175+
"Variable length array (used in '" + this +
176+
"') are a compiler extension and are not portable to other compilers."
177+
}
178+
}
179+
180+
/**
181+
* A `PreprocessorIfdef` using a builtin preprocessor feature such as `__has_builtin`,
182+
* `__has_include`, etc., which are non-standard clang extensions.
183+
*
184+
* Reference: https://clang.llvm.org/docs/LanguageExtensions.html
185+
*/
186+
class CPPConditionalDefineExtension extends CPPCompilerExtension, PreprocessorIfdef {
187+
string feature;
188+
189+
CPPConditionalDefineExtension() {
190+
feature =
191+
[
192+
"__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension",
193+
"__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include",
194+
"__has_include_next", "__has_warning", "__has_cpp_attribute"
195+
] and
196+
exists(toString().indexOf(feature))
197+
}
198+
199+
override string getMessage() {
200+
result =
201+
"Call to builtin preprocessor feature '" + feature +
202+
"' is a compiler extension and is not portable to other compilers."
203+
}
204+
}
205+
206+
/**
207+
* A `PreprocessorDirective` that is a non-standard compiler extension, such as `#pragma`, `#error`,
208+
* or `#warning`.
209+
*/
210+
class CPPPreprocessorDirectiveExtension extends CPPCompilerExtension, PreprocessorDirective {
211+
string kind;
212+
213+
CPPPreprocessorDirectiveExtension() {
214+
this instanceof PreprocessorPragma and kind = "#pragma " + getHead()
215+
or
216+
this instanceof PreprocessorError and kind = "#error"
217+
or
218+
this instanceof PreprocessorWarning and kind = "#warning"
219+
}
220+
221+
override string getMessage() {
222+
result = "Use of non-standard preprocessor directive '" + kind + "' is a compiler extension."
223+
}
224+
}
225+
226+
/**
227+
* A `BuiltInOperation` which describes certain non-standard syntax such as type trait operations,
228+
* for example GNU `__is_abstract(T)`, `__is_same(T, U)`, etc.
229+
*
230+
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
231+
*/
232+
class CPPBuiltinOperationExtension extends CPPCompilerExtension, BuiltInOperation {
233+
override string getMessage() {
234+
result = "Use of built-in operation '" + toString() + "' is a compiler extension."
235+
}
236+
}

0 commit comments

Comments
 (0)