1 //===----- NondeterministicPointerIterationOrderCheck.cpp - clang-tidy ----===//
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
7 //===----------------------------------------------------------------------===//
9 #include "NondeterministicPointerIterationOrderCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/Lex/Lexer.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::bugprone
{
17 void NondeterministicPointerIterationOrderCheck::registerMatchers(
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"),
48 void NondeterministicPointerIterationOrderCheck::check(
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
;
78 } // namespace clang::tidy::bugprone