10#include "clang/AST/ASTContext.h"
11#include "clang/Lex/Lexer.h"
18 MatchFinder *Finder) {
20 auto LoopVariable = varDecl(hasType(
21 qualType(hasCanonicalType(anyOf(referenceType(), pointerType())))));
23 auto RangeInit = declRefExpr(to(varDecl(
24 hasType(recordDecl(hasAnyName(
"std::unordered_set",
"std::unordered_map",
25 "std::unordered_multiset",
26 "std::unordered_multimap"))
27 .bind(
"recorddecl")))));
29 Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable),
30 hasRangeInit(RangeInit.bind(
"rangeinit")))
31 .bind(
"cxxForRangeStmt"),
34 auto SortFuncM = callee(functionDecl(hasAnyName(
35 "std::is_sorted",
"std::nth_element",
"std::sort",
"std::partial_sort",
36 "std::partition",
"std::stable_partition",
"std::stable_sort")));
38 auto IteratesPointerEltsM = hasArgument(
40 cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType(
41 hasCanonicalType(pointsTo(hasCanonicalType(pointerType()))))))))))));
44 callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind(
"sortsemantic"),
49 const MatchFinder::MatchResult &Result) {
50 const auto *ForRangePointers =
51 Result.Nodes.getNodeAs<CXXForRangeStmt>(
"cxxForRangeStmt");
53 if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) {
54 const auto *RangeInit = Result.Nodes.getNodeAs<Stmt>(
"rangeinit");
55 if (
const auto *ClassTemplate =
56 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
58 const TemplateArgumentList &TemplateArgs =
59 ClassTemplate->getTemplateArgs();
60 const bool IsAlgoArgPointer =
61 TemplateArgs[0].getAsType()->isPointerType();
63 if (IsAlgoArgPointer) {
64 SourceRange R = RangeInit->getSourceRange();
65 diag(R.getBegin(),
"iteration of pointers is nondeterministic") << R;
70 const auto *SortPointers = Result.Nodes.getNodeAs<Stmt>(
"sortsemantic");
72 if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) {
73 SourceRange R = SortPointers->getSourceRange();
74 diag(R.getBegin(),
"sorting pointers is nondeterministic") << R;
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.