[clang] [clang-tools-extra] RFC: [clang-tidy] [analyzer] Nondeterministic pointer usage improvements (PR #110471)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 6 06:39:49 PDT 2024


https://github.com/vabridgers updated https://github.com/llvm/llvm-project/pull/110471

>From 3ab034755e5876ba9c2d6a0de7450783851140d6 Mon Sep 17 00:00:00 2001
From: einvbri <vince.a.bridgers at ericsson.com>
Date: Thu, 26 Sep 2024 16:24:59 +0200
Subject: [PATCH] [clang-tidy] [analyzer] Move nondeterministic pointer usage
 check to tidy

This change moves the alpha.nondeterministic.PointerSorting and
alpha.nondeterministic.PointerIteration static analyzer checkers to
a single clang-tidy check. Those checkers were implemented as clang-tidy
checks wrapped in the static analyzer framework. The documentation was
updated to describe what the checks can and cannot do, and testing
was completed on a broad set of open source projects.
---
 .../bugprone/BugproneTidyModule.cpp           |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt        |   1 +
 .../NondeterministicPointerUsageCheck.cpp     |  67 ++++++++
 .../NondeterministicPointerUsageCheck.h       |  34 ++++
 clang-tools-extra/docs/ReleaseNotes.rst       |   6 +
 ...ndeterministic-pointer-iteration-order.rst |  35 ++++
 .../system-header-simulator/sim_algorithm     |  31 ++++
 .../system-header-simulator/sim_c++config.h   |  11 ++
 .../sim_initializer_list                      |  39 +++++
 .../system-header-simulator/sim_iterator_base |  22 +++
 .../Inputs/system-header-simulator/sim_map    |  35 ++++
 .../Inputs/system-header-simulator/sim_set    |  45 ++++++
 .../system-header-simulator/sim_stl_pair      |  33 ++++
 .../system-header-simulator/sim_type_traits   |  19 +++
 .../system-header-simulator/sim_unordered_map |  35 ++++
 .../system-header-simulator/sim_unordered_set |  36 +++++
 .../Inputs/system-header-simulator/sim_vector | 150 ++++++++++++++++++
 .../nondeterministic-pointer-usage.cpp        |  83 ++++++++++
 clang/docs/ReleaseNotes.rst                   |   6 +
 clang/docs/analyzer/checkers.rst              |  31 ----
 .../clang/StaticAnalyzer/Checkers/Checkers.td |  18 ---
 .../StaticAnalyzer/Checkers/CMakeLists.txt    |   2 -
 .../Checkers/PointerIterationChecker.cpp      | 101 ------------
 .../Checkers/PointerSortingChecker.cpp        | 115 --------------
 clang/test/Analysis/ptr-iter.cpp              |  28 ----
 clang/test/Analysis/ptr-sort.cpp              |  36 -----
 26 files changed, 691 insertions(+), 331 deletions(-)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-usage.cpp
 delete mode 100644 clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp
 delete mode 100644 clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
 delete mode 100644 clang/test/Analysis/ptr-iter.cpp
 delete mode 100644 clang/test/Analysis/ptr-sort.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 9120c4b6c0d9ae..597ea3e7e9c962 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -49,6 +49,7 @@
 #include "MultipleStatementMacroCheck.h"
 #include "NoEscapeCheck.h"
 #include "NonZeroEnumToBoolConversionCheck.h"
+#include "NondeterministicPointerUsageCheck.h"
 #include "NotNullTerminatedResultCheck.h"
 #include "OptionalValueConversionCheck.h"
 #include "ParentVirtualCallCheck.h"
@@ -174,6 +175,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-multiple-new-in-one-expression");
     CheckFactories.registerCheck<MultipleStatementMacroCheck>(
         "bugprone-multiple-statement-macro");
+    CheckFactories.registerCheck<NondeterministicPointerUsageCheck>(
+        "bugprone-nondeterministic-pointer-iteration-order");
     CheckFactories.registerCheck<OptionalValueConversionCheck>(
         "bugprone-optional-value-conversion");
     CheckFactories.registerCheck<PointerArithmeticOnPolymorphicObjectCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 24fc5f23249c0d..9e8ffb973e100d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -45,6 +45,7 @@ add_clang_library(clangTidyBugproneModule
   MultipleNewInOneExpressionCheck.cpp
   MultipleStatementMacroCheck.cpp
   NoEscapeCheck.cpp
+  NondeterministicPointerUsageCheck.cpp
   NonZeroEnumToBoolConversionCheck.cpp
   NotNullTerminatedResultCheck.cpp
   OptionalValueConversionCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.cpp
new file mode 100644
index 00000000000000..9dc3b1218cf5a2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.cpp
@@ -0,0 +1,67 @@
+//===------- NondetermnisticPointerUsageCheck.cpp - clang-tidy ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NondeterministicPointerUsageCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void NondeterministicPointerUsageCheck::registerMatchers(MatchFinder *Finder) {
+
+  auto LoopVariable = varDecl(hasType(hasCanonicalType(pointerType())));
+
+  auto RangeInit = declRefExpr(to(varDecl(hasType(recordDecl(
+      anyOf(hasName("std::unordered_set"), hasName("std::unordered_map"),
+            hasName("std::unordered_multiset"),
+            hasName("std::unordered_multimap")))))));
+
+  Finder->addMatcher(
+      stmt(cxxForRangeStmt(hasRangeInit(RangeInit.bind("rangeinit")),
+                           hasLoopVariable(LoopVariable.bind("loopVar"))))
+          .bind("cxxForRangeStmt"),
+      this);
+
+  auto SortFuncM = anyOf(callee(functionDecl(hasName("std::is_sorted"))),
+                         callee(functionDecl(hasName("std::nth_element"))),
+                         callee(functionDecl(hasName("std::sort"))),
+                         callee(functionDecl(hasName("std::partial_sort"))),
+                         callee(functionDecl(hasName("std::partition"))),
+                         callee(functionDecl(hasName("std::stable_partition"))),
+                         callee(functionDecl(hasName("std::stable_sort"))));
+
+  auto IteratesPointerEltsM = hasArgument(
+      0,
+      cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(
+          hasCanonicalType(pointsTo(hasCanonicalType(pointerType())))))))))));
+
+  Finder->addMatcher(stmt(callExpr(allOf(SortFuncM, IteratesPointerEltsM)))
+                         .bind("sortsemantic"),
+                     this);
+}
+
+void NondeterministicPointerUsageCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *ForRangePointers =
+      Result.Nodes.getNodeAs<Stmt>("cxxForRangeStmt");
+  const auto *SortPointers = Result.Nodes.getNodeAs<Stmt>("sortsemantic");
+
+  if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) {
+    const auto *Node = dyn_cast<CXXForRangeStmt>(ForRangePointers);
+    diag(Node->getRParenLoc(), "Iteration of pointers is nondeterministic");
+  }
+
+  if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) {
+    const auto *Node = dyn_cast<Stmt>(SortPointers);
+    diag(Node->getBeginLoc(), "Sorting pointers is nondeterministic");
+  }
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.h b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.h
new file mode 100644
index 00000000000000..f1ab145a90a2cd
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerUsageCheck.h
@@ -0,0 +1,34 @@
+//===------- NondeterministicPointerUsageCheck.h - clang-tidy ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTICPOINTERUSAGECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTICPOINTERUSAGECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/nondeterministic-pointer-usage.html
+class NondeterministicPointerUsageCheck : public ClangTidyCheck {
+public:
+  NondeterministicPointerUsageCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTICPOINTERUSAGECHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3e051c7db6adcc..44fdd6b42e9eee 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -121,6 +121,12 @@ New checks
   Gives warnings for tagged unions, where the number of tags is
   different from the number of data members inside the union.
 
+- New :doc:`bugprone-nondeterministic-pointer-iteration-order
+  <clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order>`
+  check.
+
+  Finds nondeterministic usages of pointers in unordered containers.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst
new file mode 100644
index 00000000000000..05d021d7e134db
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst
@@ -0,0 +1,35 @@
+.. title:: clang-tidy - bugprone-nondeterministic-pointer-iteration-order
+
+bugprone-nondeterministic-pointer-iteration-order
+=================================================
+
+Finds nondeterministic usages of pointers in unordered containers.
+
+One canonical example is iteration across a container of pointers.
+
+.. code-block:: c++
+
+  {
+    int a = 1, b = 2;
+    std::unordered_set<int *> UnorderedPtrSet = {&a, &b};
+    for (auto i : UnorderedPtrSet)
+      f(i);
+  }
+
+Another such example is sorting a container of pointers.
+
+.. code-block:: c++
+
+  {
+    int a = 1, b = 2;
+    std::vector<int *> VectorOfPtr = {&a, &b};
+    std::sort(VectorOfPtr.begin(), VectorOfPtr.end());
+  }
+
+Iteration of a containers of pointers may present the order of different
+pointers differently across different runs of a program. In some cases this
+may be acceptable behavior, in others this may be unexpected behavior. This
+check is advisory for this reason.
+
+This check only detects range-based for loops over unordered sets. Other
+similar usages will not be found and are false negatives.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm
new file mode 100644
index 00000000000000..6dbca55a8e365f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm
@@ -0,0 +1,31 @@
+#ifndef _SIM_ALGORITHM
+#define _SIM_ALGORITHM
+
+#pragma clang system_header
+
+namespace std {
+
+template<class ForwardIt>
+bool is_sorted(ForwardIt first, ForwardIt last);
+
+template <class RandomIt>
+void nth_element(RandomIt first, RandomIt nth, RandomIt last);
+
+template<class RandomIt>
+void partial_sort(RandomIt first, RandomIt middle, RandomIt last);
+
+template<class RandomIt>
+void sort (RandomIt first, RandomIt last);
+
+template<class RandomIt>
+void stable_sort(RandomIt first, RandomIt last);
+
+template<class BidirIt, class UnaryPredicate>
+BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p);
+
+template<class BidirIt, class UnaryPredicate>
+BidirIt stable_partition(BidirIt first, BidirIt last, UnaryPredicate p);
+
+} // namespace std
+
+#endif // _SIM_ALGORITHM
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h
new file mode 100644
index 00000000000000..ba98e0cc2208ba
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h
@@ -0,0 +1,11 @@
+#ifndef _SIM_CPP_CONFIG_H
+#define _SIM_CPP_CONFIG_H
+
+#pragma clang system_header
+
+typedef unsigned char uint8_t;
+
+typedef __typeof__(sizeof(int)) size_t;
+typedef __typeof__((char*)0-(char*)0) ptrdiff_t;
+
+#endif // _SIM_CPP_CONFIG_H
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list
new file mode 100644
index 00000000000000..e4d9d534b3bd78
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list
@@ -0,0 +1,39 @@
+#ifndef _INITIALIZER_LIST
+#define _INITIALIZER_LIST
+
+#pragma clang system_header
+#
+#include "sim_c++config.h" // size_t
+
+namespace std {
+
+template <class _E>
+class initializer_list  {
+  const _E* __begin_;
+  size_t    __size_;
+
+  initializer_list(const _E* __b, size_t __s)
+    : __begin_(__b),
+      __size_(__s)
+  {}
+
+public:
+  typedef _E        value_type;
+  typedef const _E& reference;
+  typedef const _E& const_reference;
+  typedef size_t    size_type;
+
+  typedef const _E* iterator;
+  typedef const _E* const_iterator;
+
+  initializer_list() : __begin_(0), __size_(0) {}
+
+  size_t    size()  const {return __size_;}
+  const _E* begin() const {return __begin_;}
+  const _E* end()   const {return __begin_ + __size_;}
+
+}; // class initializer_list
+
+} // namespace std
+
+#endif // _INITIALIZER_LIST
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base
new file mode 100644
index 00000000000000..3b205d1722c9dd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base
@@ -0,0 +1,22 @@
+#ifndef _SIM_ITERATOR_BASE
+#define _SIM_ITERATOR_BASE
+
+namespace std {
+
+struct input_iterator_tag { };
+struct output_iterator_tag { };
+struct forward_iterator_tag : public input_iterator_tag { };
+struct bidirectional_iterator_tag : public forward_iterator_tag { };
+struct random_access_iterator_tag : public bidirectional_iterator_tag { };
+
+template <typename Iterator> struct iterator_traits {
+  typedef typename Iterator::difference_type difference_type;
+  typedef typename Iterator::value_type value_type;
+  typedef typename Iterator::pointer pointer;
+  typedef typename Iterator::reference reference;
+  typedef typename Iterator::iterator_category iterator_category;
+};
+
+} // namespace std
+
+#endif // _SIM_ITERATOR_BASE
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map
new file mode 100644
index 00000000000000..6a71b1d533bd06
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map
@@ -0,0 +1,35 @@
+
+#ifndef _SIM_MAP
+#define _SIM_MAP
+
+#pragma clang system_header
+#include "sim_stl_pair"
+
+namespace std {
+
+template <typename Key, typename Value>
+class map {
+ public:
+  using value_type = pair<Key, Value>;
+  map();
+  map(initializer_list<pair<Key, Value>> initList);
+  value_type& operator[](const Key& key);
+  value_type& operator[](Key&& key);
+    class iterator {
+    public:
+      iterator(Key *key): ptr(key) {}
+      iterator& operator++() { ++ptr; return *this; }
+      bool operator!=(const iterator &other) const { return ptr != other.ptr; }
+      const Key &operator*() const { return *ptr; }
+    private:
+      Key *ptr;
+    };
+  public:
+    Key *val;
+    iterator begin() const { return iterator(val); }
+    iterator end() const { return iterator(val + 1); }
+};
+
+} // namespace std
+
+#endif // _SIM_MAP
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set
new file mode 100644
index 00000000000000..5f153717cf3483
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set
@@ -0,0 +1,45 @@
+
+#ifndef _SIM_SET
+#define _SIM_SET
+
+#pragma clang system_header
+#include "sim_initializer_list"
+
+namespace std {
+
+template< class T = void >
+struct less;
+
+template< class T >
+struct allocator;
+
+template< class Key >
+struct hash;
+
+template<
+  class Key,
+  class Compare = std::less<Key>,
+  class Alloc = std::allocator<Key>
+> class set {
+  public:
+    set(initializer_list<Key> __list) {}
+
+    class iterator {
+    public:
+      iterator(Key *key): ptr(key) {}
+      iterator& operator++() { ++ptr; return *this; }
+      bool operator!=(const iterator &other) const { return ptr != other.ptr; }
+      const Key &operator*() const { return *ptr; }
+    private:
+      Key *ptr;
+    };
+
+  public:
+    Key *val;
+    iterator begin() const { return iterator(val); }
+    iterator end() const { return iterator(val + 1); }
+};
+
+} // namespace std
+
+#endif // _SIM_SET
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair
new file mode 100644
index 00000000000000..d9c9dc3d78aabd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair
@@ -0,0 +1,33 @@
+#ifndef _SIM_STL_PAIR
+#define _SIM_STL_PAIR
+
+#pragma clang system_header
+
+#include "sim_type_traits"
+
+namespace std {
+
+
+template <class T1, class T2>
+struct pair {
+  T1 first;
+  T2 second;
+
+  pair() : first(), second() {}
+  pair(const T1 &a, const T2 &b) : first(a), second(b) {}
+
+  template<class U1, class U2>
+  pair(const pair<U1, U2> &other) : first(other.first),
+                                      second(other.second) {}
+};
+
+template <typename T1, typename T2>
+pair<typename remove_reference<T1>::type, typename remove_reference<T2>::type>
+make_pair(T1 &&, T2 &&) {
+  return {};
+};
+
+} // namespace std
+
+#endif // _SIM_STL_PAIR
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits
new file mode 100644
index 00000000000000..f066767c4d9858
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits
@@ -0,0 +1,19 @@
+
+#ifndef _SIM_TYPE_TRAITS
+#define _SIM_TYPE_TRAITS
+
+#pragma clang system_header
+namespace std {
+
+template< class T > struct remove_reference      {typedef T type;};
+template< class T > struct remove_reference<T&>  {typedef T type;};
+template< class T > struct remove_reference<T&&> {typedef T type;};
+
+template<typename T> typename remove_reference<T>::type&& move(T&& a);
+
+template< class T >
+using remove_reference_t = typename remove_reference<T>::type;
+
+} // namespace std
+
+#endif // _SIM_TYPE_TRAITS
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map
new file mode 100644
index 00000000000000..4f26ca08a1a0b0
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map
@@ -0,0 +1,35 @@
+#ifndef _SIM_UNORDERED_MAP
+#define _SIM_UNORDERED_MAP
+
+
+#pragma clang system_header
+#include "sim_initializer_list"
+
+namespace std {
+
+template <typename Key, typename Value>
+class unordered_map {
+ public:
+  using value_type = pair<Key, Value>;
+  unordered_map();
+  unordered_map(initializer_list<pair<Key, Value>> initList);
+  value_type& operator[](const Key& key);
+  value_type& operator[](Key&& key);
+    class iterator {
+    public:
+      iterator(Key *key): ptr(key) {}
+      iterator& operator++() { ++ptr; return *this; }
+      bool operator!=(const iterator &other) const { return ptr != other.ptr; }
+      const Key &operator*() const { return *ptr; }
+    private:
+      Key *ptr;
+    };
+  public:
+    Key *val;
+    iterator begin() const { return iterator(val); }
+    iterator end() const { return iterator(val + 1); }
+};
+
+} // namespace std
+
+#endif // _SIM_UNORDERED_MAP
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set
new file mode 100644
index 00000000000000..0770e19ab1a1ba
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set
@@ -0,0 +1,36 @@
+#ifndef _SIM_UNORDERED_SET
+#define _SIM_UNORDERED_SET
+
+#pragma clang system_header
+#include "sim_initializer_list"
+
+namespace std {
+
+template<
+  class Key,
+  class Hash = std::hash<Key>,
+  class Compare = std::less<Key>,
+  class Alloc = std::allocator<Key>
+> class unordered_set {
+  public:
+    unordered_set(initializer_list<Key> __list) {}
+
+    class iterator {
+    public:
+      iterator(Key *key): ptr(key) {}
+      iterator& operator++() { ++ptr; return *this; }
+      bool operator!=(const iterator &other) const { return ptr != other.ptr; }
+      const Key &operator*() const { return *ptr; }
+    private:
+      Key *ptr;
+    };
+
+  public:
+    Key *val;
+    iterator begin() const { return iterator(val); }
+    iterator end() const { return iterator(val + 1); }
+};
+
+} // namespace std
+
+#endif // _SIM_UNORDERED_SET
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector
new file mode 100644
index 00000000000000..dfa9abfb8863ec
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector
@@ -0,0 +1,150 @@
+#ifndef _SIM_VECTOR
+#define _SIM_VECTOR
+
+#pragma clang system_header
+
+#include "sim_iterator_base"
+
+namespace std {
+
+template <typename T, typename Ptr, typename Ref> struct __vector_iterator {
+  typedef __vector_iterator<T, T *, T &> iterator;
+  typedef __vector_iterator<T, const T *, const T &> const_iterator;
+
+  typedef ptrdiff_t difference_type;
+  typedef T value_type;
+  typedef Ptr pointer;
+  typedef Ref reference;
+  typedef std::random_access_iterator_tag iterator_category;
+
+  __vector_iterator(const Ptr p = 0) : ptr(p) {}
+  __vector_iterator(const iterator &rhs): ptr(rhs.base()) {}
+  __vector_iterator<T, Ptr, Ref>& operator++() { ++ ptr; return *this; }
+  __vector_iterator<T, Ptr, Ref> operator++(int) {
+    auto tmp = *this;
+    ++ ptr;
+    return tmp;
+  }
+  __vector_iterator<T, Ptr, Ref> operator--() { -- ptr; return *this; }
+  __vector_iterator<T, Ptr, Ref> operator--(int) {
+    auto tmp = *this; -- ptr;
+    return tmp;
+  }
+  __vector_iterator<T, Ptr, Ref> operator+(difference_type n) {
+    return ptr + n;
+  }
+  friend __vector_iterator<T, Ptr, Ref> operator+(
+      difference_type n,
+      const __vector_iterator<T, Ptr, Ref> &iter) {
+    return n + iter.ptr;
+  }
+  __vector_iterator<T, Ptr, Ref> operator-(difference_type n) {
+    return ptr - n;
+  }
+  __vector_iterator<T, Ptr, Ref> operator+=(difference_type n) {
+    return ptr += n;
+  }
+  __vector_iterator<T, Ptr, Ref> operator-=(difference_type n) {
+    return ptr -= n;
+  }
+
+  template<typename U, typename Ptr2, typename Ref2>
+  difference_type operator-(const __vector_iterator<U, Ptr2, Ref2> &rhs);
+
+  Ref operator*() const { return *ptr; }
+  Ptr operator->() const { return ptr; }
+
+  Ref operator[](difference_type n) {
+    return *(ptr+n);
+  }
+
+  bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; }
+  bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; }
+
+  bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
+  bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+
+  const Ptr& base() const { return ptr; }
+
+private:
+  Ptr ptr;
+};
+
+template<typename T>
+class vector {
+  T *_start;
+  T *_finish;
+  T *_end_of_storage;
+
+public:
+  typedef T value_type;
+  typedef size_t size_type;
+  typedef __vector_iterator<T, T *, T &> iterator;
+  typedef __vector_iterator<T, const T *, const T &> const_iterator;
+
+  vector() : _start(0), _finish(0), _end_of_storage(0) {}
+  template <typename InputIterator>
+  vector(InputIterator first, InputIterator last);
+  vector(const vector &other);
+  vector(vector &&other);
+  ~vector();
+
+  size_t size() const {
+    return size_t(_finish - _start);
+  }
+
+  vector& operator=(const vector &other);
+  vector& operator=(vector &&other);
+  vector& operator=(std::initializer_list<T> ilist);
+
+  void assign(size_type count, const T &value);
+  template <typename InputIterator >
+  void assign(InputIterator first, InputIterator last);
+  void assign(std::initializer_list<T> ilist);
+
+  void clear();
+
+  void push_back(const T &value);
+  void push_back(T &&value);
+  template<class... Args>
+  void emplace_back(Args&&... args);
+  void pop_back();
+
+  iterator insert(const_iterator position, const value_type &val);
+  iterator insert(const_iterator position, size_type n,
+                  const value_type &val);
+  template <typename InputIterator>
+  iterator insert(const_iterator position, InputIterator first,
+                  InputIterator last);
+  iterator insert(const_iterator position, value_type &&val);
+  iterator insert(const_iterator position, initializer_list<value_type> il);
+
+  template <class... Args>
+  iterator emplace(const_iterator position, Args&&... args);
+
+  iterator erase(const_iterator position);
+  iterator erase(const_iterator first, const_iterator last);
+
+  T &operator[](size_t n) {
+    return _start[n];
+  }
+
+  const T &operator[](size_t n) const {
+    return _start[n];
+  }
+
+  iterator begin() { return iterator(_start); }
+  const_iterator begin() const { return const_iterator(_start); }
+  const_iterator cbegin() const { return const_iterator(_start); }
+  iterator end() { return iterator(_finish); }
+  const_iterator end() const { return const_iterator(_finish); }
+  const_iterator cend() const { return const_iterator(_finish); }
+  T& front() { return *begin(); }
+  const T& front() const { return *begin(); }
+  T& back() { return *(end() - 1); }
+  const T& back() const { return *(end() - 1); }
+};
+
+} // namespace std
+
+#endif // _SIM_VECTOR
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-usage.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-usage.cpp
new file mode 100644
index 00000000000000..6e791a6e715619
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-usage.cpp
@@ -0,0 +1,83 @@
+// RUN: %check_clang_tidy %s bugprone-nondeterministic-pointer-iteration-order %t -- -- -I%S -std=c++!4
+
+#include "Inputs/system-header-simulator/sim_set"
+#include "Inputs/system-header-simulator/sim_unordered_set"
+#include "Inputs/system-header-simulator/sim_map"
+#include "Inputs/system-header-simulator/sim_unordered_map"
+#include "Inputs/system-header-simulator/sim_vector"
+#include "Inputs/system-header-simulator/sim_algorithm"
+
+template<class T>
+void f(T x);
+
+void PointerIteration() {
+  int a = 1, b = 2;
+  std::set<int> OrderedIntSet = {a, b};
+  std::set<int *> OrderedPtrSet = {&a, &b};
+  std::unordered_set<int> UnorderedIntSet = {a, b};
+  std::unordered_set<int *> UnorderedPtrSet = {&a, &b};
+  std::map<int, int> IntMap = { std::make_pair(a,a), std::make_pair(b,b) };
+  std::map<int*, int*> PtrMap = { std::make_pair(&a,&a), std::make_pair(&b,&b) };
+  std::unordered_map<int, int> IntUnorderedMap = { std::make_pair(a,a), std::make_pair(b,b) };
+  std::unordered_map<int*, int*> PtrUnorderedMap = { std::make_pair(&a,&a), std::make_pair(&b,&b) };
+
+  for (auto i : OrderedIntSet) // no-warning
+    f(i);
+
+  for (auto i : OrderedPtrSet) // no-warning
+    f(i);
+
+  for (auto i : UnorderedIntSet) // no-warning
+    f(i);
+
+  for (auto i : UnorderedPtrSet)
+    f(i);
+  // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: Iteration of pointers is nondeterministic
+
+  for (auto &i : UnorderedPtrSet) // no-warning
+    f(i);
+
+  for (auto &i : IntMap) // no-warning
+    f(i);
+
+  for (auto &i : PtrMap) // no-warning
+    f(i);
+
+  for (auto &i : IntUnorderedMap) // no-warning
+    f(i);
+
+  // TODO: a false negative, detect this case
+  for (auto &i : PtrUnorderedMap)
+    f(i);
+}
+
+bool g (int *x) { return true; }
+bool h (int x) { return true; }
+
+void PointerSorting() {
+  int a = 1, b = 2, c = 3;
+  std::vector<int> V1 = {a, b};
+  std::vector<int *> V2 = {&a, &b};
+
+  std::is_sorted(V1.begin(), V1.end());                    // no-warning
+  std::nth_element(V1.begin(), V1.begin() + 1, V1.end());  // no-warning
+  std::partial_sort(V1.begin(), V1.begin() + 1, V1.end()); // no-warning
+  std::sort(V1.begin(), V1.end());                         // no-warning
+  std::stable_sort(V1.begin(), V1.end());                  // no-warning
+  std::partition(V1.begin(), V1.end(), h);                 // no-warning
+  std::stable_partition(V1.begin(), V1.end(), h);          // no-warning
+  std::is_sorted(V2.begin(), V2.end());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::nth_element(V2.begin(), V2.begin() + 1, V2.end());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::partial_sort(V2.begin(), V2.begin() + 1, V2.end());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::sort(V2.begin(), V2.end());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::stable_sort(V2.begin(), V2.end());
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::partition(V2.begin(), V2.end(), g);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+  std::stable_partition(V2.begin(), V2.end(), g);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Sorting pointers is nondeterministic
+}
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 44d5f348ed2d54..8a698db4806d21 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -658,6 +658,12 @@ Moved checkers
   To detect too large arguments passed to malloc, consider using the checker
   ``alpha.taint.TaintedAlloc``.
 
+- The checkers ``alpha.nondeterministic.PointerSorting`` and
+  ``alpha.nondeterministic.PointerIteration`` were moved to a new bugprone
+  checker named ``bugprone-nondeterministic-pointer-usage``. The original
+  checkers were implemented only using AST matching and make more sense
+  as a single clang-tidy check.
+
 .. _release-notes-sanitizers:
 
 Sanitizers
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 81264428c72ed1..eeb6435f09391e 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3436,37 +3436,6 @@ Limitations:
 
      More details at the corresponding `GitHub issue <https://github.com/llvm/llvm-project/issues/43459>`_.
 
-.. _alpha-nondeterminism-PointerIteration:
-
-alpha.nondeterminism.PointerIteration (C++)
-"""""""""""""""""""""""""""""""""""""""""""
-Check for non-determinism caused by iterating unordered containers of pointers.
-
-.. code-block:: c
-
- void test() {
-  int a = 1, b = 2;
-  std::unordered_set<int *> UnorderedPtrSet = {&a, &b};
-
-  for (auto i : UnorderedPtrSet) // warn
-    f(i);
- }
-
-.. _alpha-nondeterminism-PointerSorting:
-
-alpha.nondeterminism.PointerSorting (C++)
-"""""""""""""""""""""""""""""""""""""""""
-Check for non-determinism caused by sorting of pointers.
-
-.. code-block:: c
-
- void test() {
-  int a = 1, b = 2;
-  std::vector<int *> V = {&a, &b};
-  std::sort(V.begin(), V.end()); // warn
- }
-
-
 alpha.WebKit
 ^^^^^^^^^^^^
 
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 349040c15eeb83..9a6b35c1b9f774 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -118,8 +118,6 @@ def Debug : Package<"debug">, Hidden;
 
 def CloneDetectionAlpha : Package<"clone">, ParentPackage<Alpha>;
 
-def NonDeterminismAlpha : Package<"nondeterminism">, ParentPackage<Alpha>;
-
 def Fuchsia : Package<"fuchsia">;
 def FuchsiaAlpha : Package<"fuchsia">, ParentPackage<Alpha>;
 
@@ -1711,22 +1709,6 @@ def TaintedDivChecker: Checker<"TaintedDiv">,
 
 } // end "optin.taint"
 
-//===----------------------------------------------------------------------===//
-// NonDeterminism checkers.
-//===----------------------------------------------------------------------===//
-
-let ParentPackage = NonDeterminismAlpha in {
-
-def PointerIterationChecker : Checker<"PointerIteration">,
-  HelpText<"Checks for non-determinism caused by iteration of unordered containers of pointers">,
-  Documentation<HasDocumentation>;
-
-def PointerSortingChecker : Checker<"PointerSorting">,
-  HelpText<"Check for non-determinism caused by sorting of pointers">,
-  Documentation<HasDocumentation>;
-
-} // end alpha.nondeterminism
-
 //===----------------------------------------------------------------------===//
 // Fuchsia checkers.
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 6da3665ab9a4df..62aa5ff7f002a9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -91,8 +91,6 @@ add_clang_library(clangStaticAnalyzerCheckers
   OSObjectCStyleCast.cpp
   PaddingChecker.cpp
   PointerArithChecker.cpp
-  PointerIterationChecker.cpp
-  PointerSortingChecker.cpp
   PointerSubChecker.cpp
   PthreadLockChecker.cpp
   PutenvStackArrayChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp
deleted file mode 100644
index 895b2160b76a7b..00000000000000
--- a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//== PointerIterationChecker.cpp ------------------------------- -*- C++ -*--=//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines PointerIterationChecker which checks for non-determinism
-// caused due to iteration of unordered containers of pointer elements.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-using namespace clang;
-using namespace ento;
-using namespace ast_matchers;
-
-namespace {
-
-// ID of a node at which the diagnostic would be emitted.
-constexpr llvm::StringLiteral WarnAtNode = "iter";
-
-class PointerIterationChecker : public Checker<check::ASTCodeBody> {
-public:
-  void checkASTCodeBody(const Decl *D,
-                        AnalysisManager &AM,
-                        BugReporter &BR) const;
-};
-
-static void emitDiagnostics(const BoundNodes &Match, const Decl *D,
-                            BugReporter &BR, AnalysisManager &AM,
-                            const PointerIterationChecker *Checker) {
-  auto *ADC = AM.getAnalysisDeclContext(D);
-
-  const auto *MarkedStmt = Match.getNodeAs<Stmt>(WarnAtNode);
-  assert(MarkedStmt);
-
-  auto Range = MarkedStmt->getSourceRange();
-  auto Location = PathDiagnosticLocation::createBegin(MarkedStmt,
-                                                      BR.getSourceManager(),
-                                                      ADC);
-  std::string Diagnostics;
-  llvm::raw_string_ostream OS(Diagnostics);
-  OS << "Iteration of pointer-like elements "
-     << "can result in non-deterministic ordering";
-
-  BR.EmitBasicReport(ADC->getDecl(), Checker,
-                     "Iteration of pointer-like elements", "Non-determinism",
-                     Diagnostics, Location, Range);
-}
-
-// Assumption: Iteration of ordered containers of pointers is deterministic.
-
-// TODO: Currently, we only check for std::unordered_set. Other unordered
-// containers like std::unordered_map also need to be handled.
-
-// TODO: Currently, we do not check what the for loop does with the iterated
-// pointer values. Not all iterations may cause non-determinism. For example,
-// counting or summing up the elements should not be non-deterministic.
-
-auto matchUnorderedIterWithPointers() -> decltype(decl()) {
-
-  auto UnorderedContainerM = declRefExpr(to(varDecl(hasType(
-                               recordDecl(hasName("std::unordered_set")
-                             )))));
-
-  auto PointerTypeM = varDecl(hasType(hasCanonicalType(pointerType())));
-
-  auto PointerIterM = stmt(cxxForRangeStmt(
-                             hasLoopVariable(PointerTypeM),
-                             hasRangeInit(UnorderedContainerM)
-                      )).bind(WarnAtNode);
-
-  return decl(forEachDescendant(PointerIterM));
-}
-
-void PointerIterationChecker::checkASTCodeBody(const Decl *D,
-                                             AnalysisManager &AM,
-                                             BugReporter &BR) const {
-  auto MatcherM = matchUnorderedIterWithPointers();
-
-  auto Matches = match(MatcherM, *D, AM.getASTContext());
-  for (const auto &Match : Matches)
-    emitDiagnostics(Match, D, BR, AM, this);
-}
-
-} // end of anonymous namespace
-
-void ento::registerPointerIterationChecker(CheckerManager &Mgr) {
-  Mgr.registerChecker<PointerIterationChecker>();
-}
-
-bool ento::shouldRegisterPointerIterationChecker(const CheckerManager &mgr) {
-  const LangOptions &LO = mgr.getLangOpts();
-  return LO.CPlusPlus;
-}
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
deleted file mode 100644
index 25d87f4acfc910..00000000000000
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-//== PointerSortingChecker.cpp --------------------------------- -*- C++ -*--=//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines PointerSortingChecker which checks for non-determinism
-// caused due to sorting containers with pointer-like elements.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-using namespace clang;
-using namespace ento;
-using namespace ast_matchers;
-
-namespace {
-
-// ID of a node at which the diagnostic would be emitted.
-constexpr llvm::StringLiteral WarnAtNode = "sort";
-
-class PointerSortingChecker : public Checker<check::ASTCodeBody> {
-public:
-  void checkASTCodeBody(const Decl *D,
-                        AnalysisManager &AM,
-                        BugReporter &BR) const;
-};
-
-static void emitDiagnostics(const BoundNodes &Match, const Decl *D,
-                            BugReporter &BR, AnalysisManager &AM,
-                            const PointerSortingChecker *Checker) {
-  auto *ADC = AM.getAnalysisDeclContext(D);
-
-  const auto *MarkedStmt = Match.getNodeAs<CallExpr>(WarnAtNode);
-  assert(MarkedStmt);
-
-  auto Range = MarkedStmt->getSourceRange();
-  auto Location = PathDiagnosticLocation::createBegin(MarkedStmt,
-                                                      BR.getSourceManager(),
-                                                      ADC);
-  std::string Diagnostics;
-  llvm::raw_string_ostream OS(Diagnostics);
-  OS << "Sorting pointer-like elements "
-     << "can result in non-deterministic ordering";
-
-  BR.EmitBasicReport(ADC->getDecl(), Checker,
-                     "Sorting of pointer-like elements", "Non-determinism",
-                     OS.str(), Location, Range);
-}
-
-decltype(auto) callsName(const char *FunctionName) {
-  return callee(functionDecl(hasName(FunctionName)));
-}
-
-// FIXME: Currently we simply check if std::sort is used with pointer-like
-// elements. This approach can have a big false positive rate. Using std::sort,
-// std::unique and then erase is common technique for deduplicating a container
-// (which in some cases might even be quicker than using, let's say std::set).
-// In case a container contains arbitrary memory addresses (e.g. multiple
-// things give different stuff but might give the same thing multiple times)
-// which we don't want to do things with more than once, we might use
-// sort-unique-erase and the sort call will emit a report.
-auto matchSortWithPointers() -> decltype(decl()) {
-  // Match any of these function calls.
-  auto SortFuncM = anyOf(
-                     callsName("std::is_sorted"),
-                     callsName("std::nth_element"),
-                     callsName("std::partial_sort"),
-                     callsName("std::partition"),
-                     callsName("std::sort"),
-                     callsName("std::stable_partition"),
-                     callsName("std::stable_sort")
-                    );
-
-  // Match only if the container has pointer-type elements.
-  auto IteratesPointerEltsM = hasArgument(0,
-                                hasType(cxxRecordDecl(has(
-                                  fieldDecl(hasType(hasCanonicalType(
-                                    pointsTo(hasCanonicalType(pointerType()))
-                                  )))
-                              ))));
-
-  auto PointerSortM = traverse(
-      TK_AsIs,
-      stmt(callExpr(allOf(SortFuncM, IteratesPointerEltsM))).bind(WarnAtNode));
-
-  return decl(forEachDescendant(PointerSortM));
-}
-
-void PointerSortingChecker::checkASTCodeBody(const Decl *D,
-                                             AnalysisManager &AM,
-                                             BugReporter &BR) const {
-  auto MatcherM = matchSortWithPointers();
-
-  auto Matches = match(MatcherM, *D, AM.getASTContext());
-  for (const auto &Match : Matches)
-    emitDiagnostics(Match, D, BR, AM, this);
-}
-
-} // end of anonymous namespace
-
-void ento::registerPointerSortingChecker(CheckerManager &Mgr) {
-  Mgr.registerChecker<PointerSortingChecker>();
-}
-
-bool ento::shouldRegisterPointerSortingChecker(const CheckerManager &mgr) {
-  const LangOptions &LO = mgr.getLangOpts();
-  return LO.CPlusPlus;
-}
diff --git a/clang/test/Analysis/ptr-iter.cpp b/clang/test/Analysis/ptr-iter.cpp
deleted file mode 100644
index a94288cd1c8ccc..00000000000000
--- a/clang/test/Analysis/ptr-iter.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: %clang_analyze_cc1 %s -std=c++14 -analyzer-output=text -verify \
-// RUN: -analyzer-checker=core,alpha.nondeterminism.PointerIteration
-
-#include "Inputs/system-header-simulator-cxx.h"
-
-template<class T>
-void f(T x);
-
-void PointerIteration() {
-  int a = 1, b = 2;
-  std::set<int> OrderedIntSet = {a, b};
-  std::set<int *> OrderedPtrSet = {&a, &b};
-  std::unordered_set<int> UnorderedIntSet = {a, b};
-  std::unordered_set<int *> UnorderedPtrSet = {&a, &b};
-
-  for (auto i : OrderedIntSet) // no-warning
-    f(i);
-
-  for (auto i : OrderedPtrSet) // no-warning
-    f(i);
-
-  for (auto i : UnorderedIntSet) // no-warning
-    f(i);
-
-  for (auto i : UnorderedPtrSet) // expected-warning {{Iteration of pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerIteration]
-// expected-note at -1 {{Iteration of pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerIteration]
-    f(i);
-}
diff --git a/clang/test/Analysis/ptr-sort.cpp b/clang/test/Analysis/ptr-sort.cpp
deleted file mode 100644
index d238b390bdc235..00000000000000
--- a/clang/test/Analysis/ptr-sort.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// RUN: %clang_analyze_cc1 %s -std=c++14 -analyzer-output=text -verify \
-// RUN: -analyzer-checker=core,alpha.nondeterminism.PointerSorting
-
-#include "Inputs/system-header-simulator-cxx.h"
-
-bool f(int x) { return true; }
-bool g(int *x) { return true; }
-
-void PointerSorting() {
-  int a = 1, b = 2;
-  std::vector<int> V1 = {a, b};
-  std::vector<int *> V2 = {&a, &b};
-
-  std::is_sorted(V1.begin(), V1.end());                    // no-warning
-  std::nth_element(V1.begin(), V1.begin() + 1, V1.end());  // no-warning
-  std::partial_sort(V1.begin(), V1.begin() + 1, V1.end()); // no-warning
-  std::sort(V1.begin(), V1.end());                         // no-warning
-  std::stable_sort(V1.begin(), V1.end());                  // no-warning
-  std::partition(V1.begin(), V1.end(), f);                 // no-warning
-  std::stable_partition(V1.begin(), V1.end(), g);          // no-warning
-
-  std::is_sorted(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::nth_element(V2.begin(), V2.begin() + 1, V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::partial_sort(V2.begin(), V2.begin() + 1, V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::stable_sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::partition(V2.begin(), V2.end(), f); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  std::stable_partition(V2.begin(), V2.end(), g); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-  // expected-note at -1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting]
-}



More information about the cfe-commits mailing list