clang-tools 22.0.0git
NondeterministicPointerIterationOrderCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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/Lex/Lexer.h"
11
12using namespace clang::ast_matchers;
13
14namespace clang::tidy::bugprone {
15
17 MatchFinder *Finder) {
18 auto LoopVariable = varDecl(hasType(
19 qualType(hasCanonicalType(anyOf(referenceType(), pointerType())))));
20
21 auto RangeInit = declRefExpr(to(varDecl(
22 hasType(recordDecl(hasAnyName("std::unordered_set", "std::unordered_map",
23 "std::unordered_multiset",
24 "std::unordered_multimap"))
25 .bind("recorddecl")))));
26
27 Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable),
28 hasRangeInit(RangeInit.bind("rangeinit")))
29 .bind("cxxForRangeStmt"),
30 this);
31
32 auto SortFuncM = callee(functionDecl(hasAnyName(
33 "std::is_sorted", "std::nth_element", "std::sort", "std::partial_sort",
34 "std::partition", "std::stable_partition", "std::stable_sort")));
35
36 auto IteratesPointerEltsM = hasArgument(
37 0,
38 cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType(
39 hasCanonicalType(pointsTo(hasCanonicalType(pointerType()))))))))))));
40
41 Finder->addMatcher(
42 callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"),
43 this);
44}
45
47 const MatchFinder::MatchResult &Result) {
48 const auto *ForRangePointers =
49 Result.Nodes.getNodeAs<CXXForRangeStmt>("cxxForRangeStmt");
50
51 if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) {
52 const auto *RangeInit = Result.Nodes.getNodeAs<Stmt>("rangeinit");
53 if (const auto *ClassTemplate =
54 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
55 "recorddecl")) {
56 const TemplateArgumentList &TemplateArgs =
57 ClassTemplate->getTemplateArgs();
58 const bool IsAlgoArgPointer =
59 TemplateArgs[0].getAsType()->isPointerType();
60
61 if (IsAlgoArgPointer) {
62 const SourceRange R = RangeInit->getSourceRange();
63 diag(R.getBegin(), "iteration of pointers is nondeterministic") << R;
64 }
65 }
66 return;
67 }
68 const auto *SortPointers = Result.Nodes.getNodeAs<Stmt>("sortsemantic");
69
70 if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) {
71 const SourceRange R = SortPointers->getSourceRange();
72 diag(R.getBegin(), "sorting pointers is nondeterministic") << R;
73 }
74}
75
76} // namespace clang::tidy::bugprone
void check(const ast_matchers::MatchFinder::MatchResult &Result) override