| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| //===----- NondeterministicPointerIterationOrderCheck.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 "NondeterministicPointerIterationOrderCheck.h" | ||
| #include "clang/AST/ASTContext.h" | ||
| #include "clang/Lex/Lexer.h" | ||
|
|
||
| using namespace clang::ast_matchers; | ||
|
|
||
| namespace clang::tidy::bugprone { | ||
|
|
||
| void NondeterministicPointerIterationOrderCheck::registerMatchers( | ||
| MatchFinder *Finder) { | ||
|
|
||
| auto LoopVariable = varDecl(hasType( | ||
| qualType(hasCanonicalType(anyOf(referenceType(), pointerType()))))); | ||
|
|
||
| auto RangeInit = declRefExpr(to(varDecl( | ||
| hasType(recordDecl(hasAnyName("std::unordered_set", "std::unordered_map", | ||
| "std::unordered_multiset", | ||
| "std::unordered_multimap")) | ||
| .bind("recorddecl"))))); | ||
|
|
||
| Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable), | ||
| hasRangeInit(RangeInit.bind("rangeinit"))) | ||
| .bind("cxxForRangeStmt"), | ||
| this); | ||
|
|
||
| auto SortFuncM = callee(functionDecl(hasAnyName( | ||
| "std::is_sorted", "std::nth_element", "std::sort", "std::partial_sort", | ||
| "std::partition", "std::stable_partition", "std::stable_sort"))); | ||
|
|
||
| auto IteratesPointerEltsM = hasArgument( | ||
| 0, | ||
| cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType( | ||
| hasCanonicalType(pointsTo(hasCanonicalType(pointerType())))))))))))); | ||
|
|
||
| Finder->addMatcher( | ||
| callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"), | ||
| this); | ||
| } | ||
|
|
||
| void NondeterministicPointerIterationOrderCheck::check( | ||
| const MatchFinder::MatchResult &Result) { | ||
| const auto *ForRangePointers = | ||
| Result.Nodes.getNodeAs<CXXForRangeStmt>("cxxForRangeStmt"); | ||
|
|
||
| if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) { | ||
| const auto *RangeInit = Result.Nodes.getNodeAs<Stmt>("rangeinit"); | ||
| if (const auto *ClassTemplate = | ||
| Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>( | ||
| "recorddecl")) { | ||
| const TemplateArgumentList &TemplateArgs = | ||
| ClassTemplate->getTemplateArgs(); | ||
| const bool IsAlgoArgPointer = | ||
| TemplateArgs[0].getAsType()->isPointerType(); | ||
|
|
||
| if (IsAlgoArgPointer) { | ||
| SourceRange R = RangeInit->getSourceRange(); | ||
| diag(R.getBegin(), "iteration of pointers is nondeterministic") << R; | ||
| } | ||
| } | ||
| return; | ||
| } | ||
| const auto *SortPointers = Result.Nodes.getNodeAs<Stmt>("sortsemantic"); | ||
|
|
||
| if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) { | ||
| SourceRange R = SortPointers->getSourceRange(); | ||
| diag(R.getBegin(), "sorting pointers is nondeterministic") << R; | ||
| } | ||
| } | ||
|
|
||
| } // namespace clang::tidy::bugprone |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| //=== NondeterministicPointerIterationOrderCheck.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_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H | ||
| #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H | ||
|
|
||
| #include "../ClangTidyCheck.h" | ||
|
|
||
| namespace clang::tidy::bugprone { | ||
|
|
||
| /// Finds nondeterministic usages of pointers in unordered containers. The | ||
| /// check also finds calls to sorting-like algorithms on a container of | ||
| /// pointers. | ||
| /// | ||
| /// For the user-facing documentation see: | ||
| /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.html | ||
| class NondeterministicPointerIterationOrderCheck : public ClangTidyCheck { | ||
| public: | ||
| NondeterministicPointerIterationOrderCheck(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_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| .. 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 and maps. It | ||
| also detects calls sorting-like algorithms on containers holding pointers. | ||
| Other similar usages will not be found and are false negatives. | ||
|
|
||
| Limitations: | ||
|
|
||
| * This check currently does not check if a nondeterministic iteration order is | ||
| likely to be a mistake, and instead marks all such iterations as bugprone. | ||
| * std::reference_wrapper is not considered yet. | ||
| * Only for loops are considered, other iterators can be included in | ||
| improvements. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // RUN: not clang-query --invalid-arg 2>&1 | FileCheck %s | ||
|
|
||
| // CHECK: error: clang-query{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-query{{(\.exe)?}} --help' | ||
| // CHECK-NEXT: clang-query{{(\.exe)?}}: Did you mean '--extra-arg'? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
|
|
||
| #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; | ||
| }; | ||
| Key *val; | ||
| iterator begin() const { return iterator(val); } | ||
| iterator end() const { return iterator(val + 1); } | ||
| }; | ||
|
|
||
| } // namespace std | ||
|
|
||
| #endif // _SIM_MAP |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
|
|
||
| #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; | ||
| }; | ||
|
|
||
| Key *val; | ||
| iterator begin() const { return iterator(val); } | ||
| iterator end() const { return iterator(val + 1); } | ||
| }; | ||
|
|
||
| } // namespace std | ||
|
|
||
| #endif // _SIM_SET |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| #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 | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #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; | ||
| }; | ||
| Key *val; | ||
| iterator begin() const { return iterator(val); } | ||
| iterator end() const { return iterator(val + 1); } | ||
| }; | ||
|
|
||
| } // namespace std | ||
|
|
||
| #endif // _SIM_UNORDERED_MAP |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #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; | ||
| }; | ||
|
|
||
| Key *val; | ||
| iterator begin() const { return iterator(val); } | ||
| iterator end() const { return iterator(val + 1); } | ||
| }; | ||
|
|
||
| } // namespace std | ||
|
|
||
| #endif // _SIM_UNORDERED_SET |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| // 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]]:17: warning: iteration of pointers is nondeterministic | ||
|
|
||
| for (auto &i : UnorderedPtrSet) | ||
| f(i); | ||
| // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: iteration of pointers is nondeterministic | ||
|
|
||
| for (auto &i : IntMap) // no-warning | ||
| f(i); | ||
|
|
||
| for (auto &i : PtrMap) // no-warning | ||
| f(i); | ||
|
|
||
| for (auto &i : IntUnorderedMap) // no-warning | ||
| f(i); | ||
|
|
||
| for (auto &i : PtrUnorderedMap) | ||
| f(i); | ||
| // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: iteration of pointers is nondeterministic | ||
| } | ||
|
|
||
| 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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // RUN: not clang-tidy --invalid-arg 2>&1 | FileCheck %s | ||
|
|
||
| // CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-tidy{{(\.exe)?}} --help' | ||
| // CHECK-NEXT: clang-tidy{{(\.exe)?}}: Did you mean '--extra-arg'? |