[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clang-tidy / bugprone / NondeterministicPointerIterationOrderCheck.cpp
blob22ecd689614696fa2df07be0cb9a4b51a3735ca4
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 //===----------------------------------------------------------------------===//
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"),
32 this);
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()))))))))))));
43 Finder->addMatcher(
44 callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"),
45 this);
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>(
57 "recorddecl")) {
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;
68 return;
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