[clang] Make getAttr, getSpecificAttr, hasAttr, and hasSpecificAttr variadic (PR #78518)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 17 15:07:58 PST 2024


================
@@ -43,80 +55,102 @@ class specific_attr_iterator {
   mutable Iterator Current;
 
   void AdvanceToNext() const {
-    while (!isa<SpecificAttr>(*Current))
+    while (!isa<SpecificAttrs...>(*Current))
       ++Current;
   }
 
   void AdvanceToNext(Iterator I) const {
-    while (Current != I && !isa<SpecificAttr>(*Current))
+    while (Current != I && !isa<SpecificAttrs...>(*Current))
       ++Current;
   }
 
 public:
-  using value_type = SpecificAttr *;
-  using reference = SpecificAttr *;
-  using pointer = SpecificAttr *;
+  using value_type = base_type *;
+  using reference = value_type;
+  using pointer = value_type;
   using iterator_category = std::forward_iterator_tag;
   using difference_type = std::ptrdiff_t;
 
-  specific_attr_iterator() = default;
-  explicit specific_attr_iterator(Iterator i) : Current(i) {}
+  specific_attr_iterator_impl() = default;
+  explicit specific_attr_iterator_impl(Iterator i) : Current(i) {}
 
   reference operator*() const {
     AdvanceToNext();
-    return cast<SpecificAttr>(*Current);
+    return cast<base_type>(*Current);
   }
   pointer operator->() const {
     AdvanceToNext();
-    return cast<SpecificAttr>(*Current);
+    return cast<base_type>(*Current);
   }
 
-  specific_attr_iterator& operator++() {
+  specific_attr_iterator_impl &operator++() {
     ++Current;
     return *this;
   }
-  specific_attr_iterator operator++(int) {
-    specific_attr_iterator Tmp(*this);
+  specific_attr_iterator_impl operator++(int) {
+    specific_attr_iterator_impl Tmp(*this);
     ++(*this);
     return Tmp;
   }
 
-  friend bool operator==(specific_attr_iterator Left,
-                         specific_attr_iterator Right) {
+  friend bool operator==(specific_attr_iterator_impl Left,
+                         specific_attr_iterator_impl Right) {
     assert((Left.Current == nullptr) == (Right.Current == nullptr));
     if (Left.Current < Right.Current)
       Left.AdvanceToNext(Right.Current);
     else
       Right.AdvanceToNext(Left.Current);
     return Left.Current == Right.Current;
   }
-  friend bool operator!=(specific_attr_iterator Left,
-                         specific_attr_iterator Right) {
+  friend bool operator!=(specific_attr_iterator_impl Left,
+                         specific_attr_iterator_impl Right) {
     return !(Left == Right);
   }
 };
 
-template <typename SpecificAttr, typename Container>
-inline specific_attr_iterator<SpecificAttr, Container>
-          specific_attr_begin(const Container& container) {
-  return specific_attr_iterator<SpecificAttr, Container>(container.begin());
+/// Iterates over a subrange of a collection, only providing attributes that are
+/// of a specific type/s.
+template <typename Container, typename... SpecificAttrs>
+class specific_attr_iterator;
+
+template <typename SpecificAttr>
+class specific_attr_iterator<SpecificAttr>
+    : public specific_attr_iterator_impl<AttrVec, SpecificAttr> {
+  using specific_attr_iterator_impl<AttrVec,
+                                    SpecificAttr>::specific_attr_iterator_impl;
+};
+
+template <typename Container, typename... SpecificAttrs>
+class specific_attr_iterator
----------------
erichkeane wrote:

I have a version I played with where I put a conversion operator here, so that we can convert to the partial specialization, but it would only be useful in 1 place.

The downside we have here is you cannot do:

`specific_attr_iterator<MyAttr> Foo = Decl->specific_attr_iterator_begin<MyAttr>()`

since the two specializations are 'different' types.  I was hoping @ldionne /someone else might have a clever way of combining the uses of these two.

https://github.com/llvm/llvm-project/pull/78518


More information about the cfe-commits mailing list