clang-tools 20.0.0git
NondeterministicPointerIterationOrderCheck.cpp
Go to the documentation of this file.
1//===----- NondeterministicPointerIterationOrderCheck.cpp - clang-tidy ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/AST/ASTContext.h"
11#include "clang/Lex/Lexer.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::bugprone {
16
18 MatchFinder *Finder) {
19
20 auto LoopVariable = varDecl(hasType(
21 qualType(hasCanonicalType(anyOf(referenceType(), pointerType())))));
22
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")))));
28
29 Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable),
30 hasRangeInit(RangeInit.bind("rangeinit")))
31 .bind("cxxForRangeStmt"),
32 this);
33
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")));
37
38 auto IteratesPointerEltsM = hasArgument(
39 0,
40 cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType(
41 hasCanonicalType(pointsTo(hasCanonicalType(pointerType()))))))))))));
42
43 Finder->addMatcher(
44 callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"),
45 this);
46}
47
49 const MatchFinder::MatchResult &Result) {
50 const auto *ForRangePointers =
51 Result.Nodes.getNodeAs<CXXForRangeStmt>("cxxForRangeStmt");
52
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>(
57 "recorddecl")) {
58 const TemplateArgumentList &TemplateArgs =
59 ClassTemplate->getTemplateArgs();
60 const bool IsAlgoArgPointer =
61 TemplateArgs[0].getAsType()->isPointerType();
62
63 if (IsAlgoArgPointer) {
64 SourceRange R = RangeInit->getSourceRange();
65 diag(R.getBegin(), "iteration of pointers is nondeterministic") << R;
66 }
67 }
68 return;
69 }
70 const auto *SortPointers = Result.Nodes.getNodeAs<Stmt>("sortsemantic");
71
72 if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) {
73 SourceRange R = SortPointers->getSourceRange();
74 diag(R.getBegin(), "sorting pointers is nondeterministic") << R;
75 }
76}
77
78} // namespace clang::tidy::bugprone
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.