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