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