Skip to content

Commit cb5ddf5

Browse files
committed
Support C++ in reserved names
1 parent 6ca9153 commit cb5ddf5

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed

cpp/common/src/codingstandards/cpp/ReservedNames.qll

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import codingstandards.cpp.CKeywords
66
import codingstandards.cpp.Linkage
77
import codingstandards.cpp.Macro
88
import codingstandards.cpp.StandardLibraryNames
9+
import codingstandards.cpp.StdNamespace
910

1011
module ReservedNames {
1112
module C11 {
@@ -297,4 +298,230 @@ module ReservedNames {
297298
)
298299
}
299300
}
301+
302+
module Cpp14 {
303+
private import codingstandards.cpp.Lex
304+
305+
module TargetedCppLibrary = CppStandardLibrary::Cpp14;
306+
307+
module TargetedCLibrary = CStandardLibrary::C99;
308+
309+
predicate isMacroUsingReservedIdentifier(PreprocessorDirective pd, string reason) {
310+
exists(string name, string identifierDescription |
311+
pd.(Macro).getName() = name and identifierDescription = "#define"
312+
or
313+
pd.(PreprocessorUndef).getName() = name and
314+
identifierDescription = "#undef"
315+
|
316+
// [macro.names] precludes the use of any name declared in any standard library header
317+
exists(string header, string standard |
318+
TargetedCLibrary::hasName(header, name) and
319+
standard = TargetedCLibrary::getName()
320+
or
321+
TargetedCppLibrary::hasName(header, name) and
322+
standard = TargetedCppLibrary::getName()
323+
|
324+
// Includes at least one standard library header
325+
pd.getFile().getAnIncludedFile*().getBaseName() =
326+
[TargetedCLibrary::getAHeader(), TargetedCppLibrary::getAHeader()] and
327+
reason =
328+
"'" + identifierDescription + " " + name + "' uses a reserved name from the " + standard
329+
+ " standard library header <" + header + ">."
330+
)
331+
or
332+
// [macro.names] precludes the use of keywords, special identifiers or reserved attribute tokens
333+
exists(string kind |
334+
name = Lex::Cpp14::keyword() and kind = " keyword"
335+
or
336+
name = Lex::Cpp14::specialIdentfier() and kind = "special identifier"
337+
or
338+
name = Lex::Cpp14::reservedAttributeToken() and kind = "reserved attribute token"
339+
|
340+
reason =
341+
"'" + identifierDescription + " " + name + "' uses a name lexically identical to a " +
342+
kind + "."
343+
)
344+
or
345+
// [global.names] Reserves unconditionally all names containing __ or prefixed with _[A-Z].
346+
// In addition _ prefixed names are reserved to the implementation in the global namespace.
347+
// As macros are not limited in effect to a given namespace, we also consider all names
348+
// starting with _ as reserved when considering macros, as well as those with __ in the name.
349+
name.regexpMatch("(_.*|.*__.*)") and
350+
reason =
351+
"'" + identifierDescription + " " + name + "' uses a name reserved for the " +
352+
TargetedCppLibrary::getName() + " implementation."
353+
)
354+
}
355+
356+
class GlobalFunction extends TopLevelFunction {
357+
GlobalFunction() { getNamespace() instanceof GlobalNamespace }
358+
}
359+
360+
private Macro getGeneratedFrom(Element e) {
361+
isCppIdentifier(e, _, _, _) and
362+
exists(MacroInvocation mi |
363+
mi = result.getAnInvocation() and
364+
mi.getAGeneratedElement() = e and
365+
not exists(MacroInvocation child |
366+
child.getParentInvocation() = mi and
367+
child.getAGeneratedElement() = e
368+
)
369+
)
370+
}
371+
372+
newtype IdentifierScope =
373+
StdNamespaceScope() or
374+
GlobalNamespaceScope() or
375+
OtherNamespaceScope()
376+
377+
/**
378+
* An declaration whose name can be reserved.
379+
*/
380+
private predicate isCppIdentifier(
381+
Declaration m, string name, string identifierDescription, IdentifierScope scope
382+
) {
383+
m.(GlobalFunction).getName() = name and
384+
identifierDescription = "Function" and
385+
scope = GlobalNamespaceScope()
386+
or
387+
m.(GlobalVariable).getName() = name and
388+
identifierDescription = "Variable" and
389+
scope = GlobalNamespaceScope()
390+
or
391+
m.(UserType).getName() = name and
392+
m.(UserType).getNamespace() instanceof GlobalNamespace and
393+
identifierDescription = "Type" and
394+
scope = GlobalNamespaceScope()
395+
or
396+
hasExternalLinkage(m) and
397+
m.(Declaration).getName() = name and
398+
identifierDescription = "Declaration with external linkage" and
399+
exists(Namespace n | n = m.(Declaration).getNamespace() |
400+
if n instanceof StdNS
401+
then scope = StdNamespaceScope()
402+
else
403+
if n instanceof GlobalNamespace
404+
then scope = GlobalNamespaceScope()
405+
else scope = OtherNamespaceScope()
406+
)
407+
}
408+
409+
predicate isAReservedIdentifier(Declaration m, string message) {
410+
exists(string name, string identifierDescription, IdentifierScope scope, string reason |
411+
isCppIdentifier(m, name, identifierDescription, scope) and
412+
// Exclude cases generated from library macros, because the user does not control them
413+
not getGeneratedFrom(m) instanceof LibraryMacro and
414+
message = identifierDescription + " '" + name + "' " + reason + "."
415+
|
416+
// [global.names] reserves unconditionally all names containing __ or prefixed with _[A-Z].
417+
// In addition _ prefixed names are reserved to the implementation in the global namespace.
418+
name.regexpMatch("(_[A-Z].*|.*__.*)") and
419+
reason =
420+
" uses a name reserved for the " + TargetedCppLibrary::getName() + " implementation."
421+
or
422+
// [global.names] reserves all _ prefixed names to the implementation in the global namespace.
423+
name.regexpMatch("_([^A-Z_].*)?") and
424+
scope = GlobalNamespaceScope() and
425+
reason =
426+
" uses a name reserved for the " + TargetedCppLibrary::getName() + " implementation."
427+
or
428+
// [extern.names]/1:
429+
// Each name declared as an object with external linkage in a header is reserved to the implementation to
430+
// designate that library object with external linkage,182 both in namespace std and in the global namespace.
431+
exists(string header |
432+
header =
433+
max(string candidate_header |
434+
TargetedCppLibrary::hasObjectName(candidate_header, _, name, _, "external")
435+
)
436+
or
437+
header = "errno" and
438+
name = "cerrno"
439+
|
440+
not scope = OtherNamespaceScope() and
441+
reason =
442+
"declares a reserved object name from the " + TargetedCppLibrary::getName() +
443+
" standard library header <" + header + ">"
444+
)
445+
or
446+
// [extern.names]/2:
447+
// Each global function signature declared with external linkage in a header is reserved to the implementation
448+
// to designate that function signature with external linkage.
449+
exists(string header |
450+
header =
451+
max(string candidate_header |
452+
// Global functions are in the global namespace ("") and have no declaring type
453+
TargetedCppLibrary::hasFunctionName(candidate_header, "", "", name, _, _, "external")
454+
)
455+
or
456+
header = "csetjmp" and
457+
name = "setjmp"
458+
or
459+
header = "cstdarg" and
460+
name = "va_end"
461+
|
462+
// Only report against elements with external linkage
463+
hasExternalLinkage(m) and
464+
reason =
465+
"declares a name which is reserved for a function from the " +
466+
TargetedCppLibrary::getName() + " standard library header <" + header + ">"
467+
)
468+
or
469+
// [extern.names]/3:
470+
// Each name from the Standard C library declared with external linkage is reserved to the implementation
471+
// for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
472+
exists(string header |
473+
header =
474+
max(string candidate_header |
475+
TargetedCLibrary::hasObjectName(candidate_header, _, name, _, "external")
476+
)
477+
|
478+
// Only global and std
479+
not scope = OtherNamespaceScope() and
480+
reason =
481+
"declares a name which is reserved for the " + TargetedCLibrary::getName() +
482+
" standard library header <" + header + ">"
483+
)
484+
or
485+
exists(string header |
486+
// [extern.names]/4:
487+
// Each function signature from the Standard C library declared with external linkage is reserved to the
488+
// implementation for use as a function signature with both extern "C" and extern "C++" linkage, 184 or as
489+
// a name of namespace scope in the global namespace.
490+
header =
491+
max(string candidate_header |
492+
TargetedCLibrary::hasFunctionName(candidate_header, _, _, name, _, _, "external")
493+
) and
494+
reason =
495+
"declares a name which is reserved for a function from the " +
496+
TargetedCLibrary::getName() + " standard library header <" + header + ">"
497+
or
498+
header = ["cuchar", "cwchar", "cwctype"] and
499+
TargetedCppLibrary::hasFunctionName(header, _, "", name, _, _, "external") and
500+
reason =
501+
"declares a name which is reserved for a function from the " +
502+
TargetedCppLibrary::getName() + " standard library header <" + header + ">"
503+
|
504+
// Only reserved as a name in the global scope
505+
scope = GlobalNamespaceScope()
506+
or
507+
// Not a function, but has external linkage
508+
hasExternalLinkage(m) and
509+
not m instanceof Function
510+
)
511+
or
512+
exists(string header |
513+
// [extern.types]:
514+
// For each type T from the Standard C library,185 the types ::T and std::T are reserved to the implementation
515+
// and, when defined, ::T shall be identical to std::T.
516+
header =
517+
max(string candidate_header | TargetedCLibrary::hasTypeName(candidate_header, _, name)) and
518+
// Only restricted in std and global namespace
519+
not scope = OtherNamespaceScope() and
520+
reason =
521+
"declares a name which is reserved for a type from the " + TargetedCLibrary::getName() +
522+
" standard library header <" + header + ">"
523+
)
524+
)
525+
}
526+
}
300527
}

0 commit comments

Comments
 (0)