1 //===- AttrIterator.h - Classes for attribute iteration ---------*- C++ -*-===// 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 // 9 // This file defines the Attr vector and specific_attr_iterator interfaces. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_AST_ATTRITERATOR_H 14 #define LLVM_CLANG_AST_ATTRITERATOR_H 15 16 #include "clang/Basic/LLVM.h" 17 #include "llvm/ADT/ADL.h" 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/Support/Casting.h" 20 #include <cassert> 21 #include <cstddef> 22 #include <iterator> 23 #include <type_traits> 24 25 namespace clang { 26 27 class Attr; 28 29 /// AttrVec - A vector of Attr, which is how they are stored on the AST. 30 using AttrVec = SmallVector<Attr *, 4>; 31 32 /// specific_attr_iterator - Iterates over a subrange of an AttrVec, only 33 /// providing attributes that are of a specific type. 34 template <typename SpecificAttr, typename Container = AttrVec> 35 class specific_attr_iterator { 36 using Iterator = typename Container::const_iterator; 37 38 /// Current - The current, underlying iterator. 39 /// In order to ensure we don't dereference an invalid iterator unless 40 /// specifically requested, we don't necessarily advance this all the 41 /// way. Instead, we advance it when an operation is requested; if the 42 /// operation is acting on what should be a past-the-end iterator, 43 /// then we offer no guarantees, but this way we do not dereference a 44 /// past-the-end iterator when we move to a past-the-end position. 45 mutable Iterator Current; 46 47 void AdvanceToNext() const { 48 while (!isa<SpecificAttr>(*Current)) 49 ++Current; 50 } 51 52 void AdvanceToNext(Iterator I) const { 53 while (Current != I && !isa<SpecificAttr>(*Current)) 54 ++Current; 55 } 56 57 public: 58 using value_type = SpecificAttr *; 59 using reference = SpecificAttr *; 60 using pointer = SpecificAttr *; 61 using iterator_category = std::forward_iterator_tag; 62 using difference_type = std::ptrdiff_t; 63 64 specific_attr_iterator() = default; 65 explicit specific_attr_iterator(Iterator i) : Current(i) {} 66 67 reference operator*() const { 68 AdvanceToNext(); 69 return cast<SpecificAttr>(*Current); 70 } 71 pointer operator->() const { 72 AdvanceToNext(); 73 return cast<SpecificAttr>(*Current); 74 } 75 76 specific_attr_iterator& operator++() { 77 ++Current; 78 return *this; 79 } 80 specific_attr_iterator operator++(int) { 81 specific_attr_iterator Tmp(*this); 82 ++(*this); 83 return Tmp; 84 } 85 86 friend bool operator==(specific_attr_iterator Left, 87 specific_attr_iterator Right) { 88 assert((Left.Current == nullptr) == (Right.Current == nullptr)); 89 if (Left.Current < Right.Current) 90 Left.AdvanceToNext(Right.Current); 91 else 92 Right.AdvanceToNext(Left.Current); 93 return Left.Current == Right.Current; 94 } 95 friend bool operator!=(specific_attr_iterator Left, 96 specific_attr_iterator Right) { 97 return !(Left == Right); 98 } 99 }; 100 101 template <typename SpecificAttr, typename Container> 102 inline specific_attr_iterator<SpecificAttr, Container> 103 specific_attr_begin(const Container& container) { 104 return specific_attr_iterator<SpecificAttr, Container>(container.begin()); 105 } 106 template <typename SpecificAttr, typename Container> 107 inline specific_attr_iterator<SpecificAttr, Container> 108 specific_attr_end(const Container& container) { 109 return specific_attr_iterator<SpecificAttr, Container>(container.end()); 110 } 111 112 template <typename SpecificAttr, typename Container> 113 inline bool hasSpecificAttr(const Container& container) { 114 return specific_attr_begin<SpecificAttr>(container) != 115 specific_attr_end<SpecificAttr>(container); 116 } 117 template <typename SpecificAttr, typename Container> 118 inline auto *getSpecificAttr(const Container &container) { 119 using ValueTy = llvm::detail::ValueOfRange<Container>; 120 using ValuePointeeTy = std::remove_pointer_t<ValueTy>; 121 using IterTy = std::conditional_t<std::is_const_v<ValuePointeeTy>, 122 const SpecificAttr, SpecificAttr>; 123 auto It = specific_attr_begin<IterTy>(container); 124 return It != specific_attr_end<IterTy>(container) ? *It : nullptr; 125 } 126 127 } // namespace clang 128 129 #endif // LLVM_CLANG_AST_ATTRITERATOR_H 130