Skip to content
Draft
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
be7f810
Add module for names from the C/C++ library
lcartey Mar 8, 2024
1554d78
Add mad generator for the C Standard Library
lcartey Mar 8, 2024
057c684
Add mad generator for the C++ Standard Library
lcartey Mar 8, 2024
bf715b1
Fix output locations
lcartey Mar 8, 2024
af00c9f
Update models file
lcartey Mar 8, 2024
ea7e3b5
C: Support pointer return types in library generator
lcartey Mar 12, 2024
e21f6d3
Add missing update
lcartey Mar 12, 2024
cae5660
Add manual member variable models for C11 and C99.
lcartey Mar 12, 2024
189d66f
Expose libraryMemberVariableModels
lcartey Mar 13, 2024
fcbe4e7
Adopt StandardLibraryNames in the C DeclaredAReservedIdentifier query
lcartey Mar 13, 2024
5f738b3
Update message, add additional tests
lcartey Mar 13, 2024
221c0c1
Refine detection of reserved identifiers
lcartey Mar 13, 2024
ca51fda
Correctly reflect tag and typedef name spaces
lcartey Mar 13, 2024
122a020
Exclude identifiers generated from library macros
lcartey Mar 13, 2024
172378f
Only include macro names when the relevant header is included
lcartey Mar 13, 2024
b91d527
Improve performance on large databases
lcartey Mar 13, 2024
1fd72e2
Migrate STR32-C to new naming library
lcartey Mar 14, 2024
f5210ac
Extract ReservedNames library.
lcartey Mar 14, 2024
92cfb2f
Exclude NDEBUG, regenerate
lcartey Mar 14, 2024
6998ed0
Migrate Rule 21.2 to the ReservedNames library
lcartey Mar 14, 2024
927640b
Unshared Rule 21.2, and implement with MISRA rules
lcartey Mar 14, 2024
a821de9
Replace Naming with StandardLibraryNames
lcartey Mar 14, 2024
7c94c8c
Migrate A17-1-1 to use StandardLibraryNames
lcartey Mar 15, 2024
c3977f2
Migrate M17-0-2 to StandardLibraryNames.
lcartey Mar 15, 2024
b2ea30a
C++: More accurately report declaring header
lcartey Mar 25, 2024
d18ada0
C++: Remove unnamed and specialization types
lcartey Mar 25, 2024
a9a4613
C++: Exclude operator bool from the reserved names
lcartey Mar 25, 2024
bbd56e0
C++: Exclude member names unless the declaring type is visible
lcartey Mar 26, 2024
384b245
C++: Exclude name-header mappings for specializations
lcartey Mar 26, 2024
6ca9153
Add a predicate for identifying any name in a standard
lcartey Mar 28, 2024
cb5ddf5
Support C++ in reserved names
lcartey Mar 28, 2024
740c76d
Migrate A17-0-1 to use ReservedName
lcartey Mar 28, 2024
7a1eeb2
M17-0-3: Migrate to StandardNaming
lcartey Aug 28, 2025
deb849b
A17-0-1: Accept output
lcartey Aug 28, 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
Prev Previous commit
Next Next commit
Support C++ in reserved names
  • Loading branch information
lcartey committed Aug 27, 2025
commit cb5ddf56303fc128d833d9e43aa9fa3f20345785
227 changes: 227 additions & 0 deletions cpp/common/src/codingstandards/cpp/ReservedNames.qll
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import codingstandards.cpp.CKeywords
import codingstandards.cpp.Linkage
import codingstandards.cpp.Macro
import codingstandards.cpp.StandardLibraryNames
import codingstandards.cpp.StdNamespace

module ReservedNames {
module C11 {
Expand Down Expand Up @@ -297,4 +298,230 @@ module ReservedNames {
)
}
}

module Cpp14 {
private import codingstandards.cpp.Lex

module TargetedCppLibrary = CppStandardLibrary::Cpp14;

module TargetedCLibrary = CStandardLibrary::C99;

predicate isMacroUsingReservedIdentifier(PreprocessorDirective pd, string reason) {
exists(string name, string identifierDescription |
pd.(Macro).getName() = name and identifierDescription = "#define"
or
pd.(PreprocessorUndef).getName() = name and
identifierDescription = "#undef"
|
// [macro.names] precludes the use of any name declared in any standard library header
exists(string header, string standard |
TargetedCLibrary::hasName(header, name) and
standard = TargetedCLibrary::getName()
or
TargetedCppLibrary::hasName(header, name) and
standard = TargetedCppLibrary::getName()
|
// Includes at least one standard library header
pd.getFile().getAnIncludedFile*().getBaseName() =
[TargetedCLibrary::getAHeader(), TargetedCppLibrary::getAHeader()] and
reason =
"'" + identifierDescription + " " + name + "' uses a reserved name from the " + standard
+ " standard library header <" + header + ">."
)
or
// [macro.names] precludes the use of keywords, special identifiers or reserved attribute tokens
exists(string kind |
name = Lex::Cpp14::keyword() and kind = " keyword"
or
name = Lex::Cpp14::specialIdentfier() and kind = "special identifier"
or
name = Lex::Cpp14::reservedAttributeToken() and kind = "reserved attribute token"
|
reason =
"'" + identifierDescription + " " + name + "' uses a name lexically identical to a " +
kind + "."
)
or
// [global.names] Reserves unconditionally all names containing __ or prefixed with _[A-Z].
// In addition _ prefixed names are reserved to the implementation in the global namespace.
// As macros are not limited in effect to a given namespace, we also consider all names
// starting with _ as reserved when considering macros, as well as those with __ in the name.
name.regexpMatch("(_.*|.*__.*)") and
reason =
"'" + identifierDescription + " " + name + "' uses a name reserved for the " +
TargetedCppLibrary::getName() + " implementation."
)
}

class GlobalFunction extends TopLevelFunction {
GlobalFunction() { getNamespace() instanceof GlobalNamespace }
}

private Macro getGeneratedFrom(Element e) {
isCppIdentifier(e, _, _, _) and
exists(MacroInvocation mi |
mi = result.getAnInvocation() and
mi.getAGeneratedElement() = e and
not exists(MacroInvocation child |
child.getParentInvocation() = mi and
child.getAGeneratedElement() = e
)
)
}

newtype IdentifierScope =
StdNamespaceScope() or
GlobalNamespaceScope() or
OtherNamespaceScope()

/**
* An declaration whose name can be reserved.
*/
private predicate isCppIdentifier(
Declaration m, string name, string identifierDescription, IdentifierScope scope
) {
m.(GlobalFunction).getName() = name and
identifierDescription = "Function" and
scope = GlobalNamespaceScope()
or
m.(GlobalVariable).getName() = name and
identifierDescription = "Variable" and
scope = GlobalNamespaceScope()
or
m.(UserType).getName() = name and
m.(UserType).getNamespace() instanceof GlobalNamespace and
identifierDescription = "Type" and
scope = GlobalNamespaceScope()
or
hasExternalLinkage(m) and
m.(Declaration).getName() = name and
identifierDescription = "Declaration with external linkage" and
exists(Namespace n | n = m.(Declaration).getNamespace() |
if n instanceof StdNS
then scope = StdNamespaceScope()
else
if n instanceof GlobalNamespace
then scope = GlobalNamespaceScope()
else scope = OtherNamespaceScope()
)
}

predicate isAReservedIdentifier(Declaration m, string message) {
exists(string name, string identifierDescription, IdentifierScope scope, string reason |
isCppIdentifier(m, name, identifierDescription, scope) and
// Exclude cases generated from library macros, because the user does not control them
not getGeneratedFrom(m) instanceof LibraryMacro and
message = identifierDescription + " '" + name + "' " + reason + "."
|
// [global.names] reserves unconditionally all names containing __ or prefixed with _[A-Z].
// In addition _ prefixed names are reserved to the implementation in the global namespace.
name.regexpMatch("(_[A-Z].*|.*__.*)") and
reason =
" uses a name reserved for the " + TargetedCppLibrary::getName() + " implementation."
or
// [global.names] reserves all _ prefixed names to the implementation in the global namespace.
name.regexpMatch("_([^A-Z_].*)?") and
scope = GlobalNamespaceScope() and
reason =
" uses a name reserved for the " + TargetedCppLibrary::getName() + " implementation."
or
// [extern.names]/1:
// Each name declared as an object with external linkage in a header is reserved to the implementation to
// designate that library object with external linkage,182 both in namespace std and in the global namespace.
exists(string header |
header =
max(string candidate_header |
TargetedCppLibrary::hasObjectName(candidate_header, _, name, _, "external")
)
or
header = "errno" and
name = "cerrno"
|
not scope = OtherNamespaceScope() and
reason =
"declares a reserved object name from the " + TargetedCppLibrary::getName() +
" standard library header <" + header + ">"
)
or
// [extern.names]/2:
// Each global function signature declared with external linkage in a header is reserved to the implementation
// to designate that function signature with external linkage.
exists(string header |
header =
max(string candidate_header |
// Global functions are in the global namespace ("") and have no declaring type
TargetedCppLibrary::hasFunctionName(candidate_header, "", "", name, _, _, "external")
)
or
header = "csetjmp" and
name = "setjmp"
or
header = "cstdarg" and
name = "va_end"
|
// Only report against elements with external linkage
hasExternalLinkage(m) and
reason =
"declares a name which is reserved for a function from the " +
TargetedCppLibrary::getName() + " standard library header <" + header + ">"
)
or
// [extern.names]/3:
// Each name from the Standard C library declared with external linkage is reserved to the implementation
// for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
exists(string header |
header =
max(string candidate_header |
TargetedCLibrary::hasObjectName(candidate_header, _, name, _, "external")
)
|
// Only global and std
not scope = OtherNamespaceScope() and
reason =
"declares a name which is reserved for the " + TargetedCLibrary::getName() +
" standard library header <" + header + ">"
)
or
exists(string header |
// [extern.names]/4:
// Each function signature from the Standard C library declared with external linkage is reserved to the
// implementation for use as a function signature with both extern "C" and extern "C++" linkage, 184 or as
// a name of namespace scope in the global namespace.
header =
max(string candidate_header |
TargetedCLibrary::hasFunctionName(candidate_header, _, _, name, _, _, "external")
) and
reason =
"declares a name which is reserved for a function from the " +
TargetedCLibrary::getName() + " standard library header <" + header + ">"
or
header = ["cuchar", "cwchar", "cwctype"] and
TargetedCppLibrary::hasFunctionName(header, _, "", name, _, _, "external") and
reason =
"declares a name which is reserved for a function from the " +
TargetedCppLibrary::getName() + " standard library header <" + header + ">"
|
// Only reserved as a name in the global scope
scope = GlobalNamespaceScope()
or
// Not a function, but has external linkage
hasExternalLinkage(m) and
not m instanceof Function
)
or
exists(string header |
// [extern.types]:
// For each type T from the Standard C library,185 the types ::T and std::T are reserved to the implementation
// and, when defined, ::T shall be identical to std::T.
header =
max(string candidate_header | TargetedCLibrary::hasTypeName(candidate_header, _, name)) and
// Only restricted in std and global namespace
not scope = OtherNamespaceScope() and
reason =
"declares a name which is reserved for a type from the " + TargetedCLibrary::getName() +
" standard library header <" + header + ">"
)
)
}
}
}