Logo ROOT  
Reference Guide
TClingMemberIter.h
Go to the documentation of this file.
1// @(#)root/core/meta:$Id$
2// Author: Axel Naumann 2020-08-25
3
4/*************************************************************************
5 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifndef ROOT_TClingMemberIter
13#define ROOT_TClingMemberIter
14
15//////////////////////////////////////////////////////////////////////////
16// //
17// TClingMemberIter //
18// //
19// Iteration through function or data members, //
20// //
21//////////////////////////////////////////////////////////////////////////
22
23#include "clang/AST/DeclBase.h"
24#include "clang/AST/DeclCXX.h"
25
26#include "llvm/ADT/SmallVector.h"
27
28#include <memory>
29#include <stack>
30
31namespace clang {
32class Sema;
33class RedeclarableDemplateDecl;
34} // namespace clang
35
36namespace cling {
37class Interpreter;
38class LookupHelper;
39} // namespace cling
40
42/// Iteration over collected DeclContexts
43class DCIter {
44 cling::Interpreter *fInterp = nullptr;
45 llvm::SmallVector<clang::DeclContext *, 2> fContexts; // Set of DeclContext to iterate over.
46 size_t fDCIdx = 0; // Index of current element in fContexts.
47 clang::DeclContext::decl_iterator fDeclIter;
48
49 /// Do not return inline namespaces etc.
51
52 /// Return true if fDeclIter has triggered an inline or anonymous namespace / ...
53 /// to be appended to fContexts.
55
56 /// Increment the iterator, possibly moving to the next context.
57 bool IterNext();
58
59public:
60 DCIter() = default;
61 DCIter(clang::DeclContext *DC, cling::Interpreter *interp);
62
63 bool Next();
64
65 clang::Decl *operator->() const { return operator*(); }
66 clang::Decl *operator*() const { return fInterp ? *fDeclIter : nullptr; }
67
68 bool IsValid() const { return fInterp && fDCIdx < fContexts.size(); }
69};
70
73 clang::UsingDecl::shadow_iterator fShadowedIter; // Shadowed decl iterator of fCurrentUsingDecl.
74 clang::UsingDecl::shadow_iterator fShadowedEnd; // Shadowed decl iterator of fCurrentUsingDecl.
75
76 UsingDeclFrame(const clang::UsingDecl *UD) : fShadowedIter(UD->shadow_begin()), fShadowedEnd(UD->shadow_end()) {}
77 };
78 /// Handle nested UsingDecls:
79 /// ```
80 /// struct A { void f(); void f(int); };
81 /// struct B: A { using A::f; void f(float); };
82 /// struct C: B { using B::f; void f(char); };
83 /// ```
84 /// will cause the UsingDecl iteration to be stacked,
85 /// to recursively resolve all used decls for `f` in `C`.
86 std::stack<UsingDeclFrame> fUsingIterStack;
87 cling::Interpreter *fInterp = nullptr;
88
89 clang::UsingDecl::shadow_iterator &Iter() { return fUsingIterStack.top().fShadowedIter; }
90 const clang::UsingDecl::shadow_iterator &Iter() const { return fUsingIterStack.top().fShadowedIter; }
91 const clang::UsingDecl::shadow_iterator &End() const { return fUsingIterStack.top().fShadowedEnd; }
92
93public:
94 UsingDeclIter() = default;
95 UsingDeclIter(const clang::UsingDecl *UD, cling::Interpreter *interp);
96
97 bool Next();
98
99 clang::Decl *operator->() const { return operator*(); }
100
101 clang::Decl *operator*() const { return IsValid() ? *Iter() : nullptr; }
102
103 bool IsValid() const { return !fUsingIterStack.empty(); }
104};
105
106}; // namespace ClingMemberIterInternal
107
108/// Iterate over all DeclT-s (or UsingShadowDecl-s pointing to DeclT-s) of a decl
109/// context, skipping those for which DerivedT::ShouldSkip(const Decl*) returns `true`
110/// when invoked with the Decl.
112private:
113 cling::Interpreter *fInterp = nullptr;
114 const clang::Decl *fTemplateSpec =
115 nullptr; // an all-default-template-args member corresponding to the current iteration Decl.
116 ClingMemberIterInternal::DCIter fDCIter; // DeclContext iterator.
117 ClingMemberIterInternal::UsingDeclIter fUsingDeclIter; // Iterating the shadowed decls of a using decl.
118
119 const clang::Decl *GetDeclSlow() const;
120
121 bool Advance();
122
123protected:
124 virtual clang::Decl *AdvanceUnfiltered()
125 {
127 return *fUsingDeclIter;
128 if (fDCIter.IsValid() && fDCIter.Next())
129 return *fDCIter;
130 return nullptr;
131 }
132
133 virtual const clang::Decl *InstantiateTemplateWithDefaults(const clang::RedeclarableTemplateDecl *TD) const
134 {
135 // TODO: add support for variable templates.
136 return nullptr;
137 }
138
139 virtual bool ShouldSkip(const clang::Decl *D) const = 0;
140 virtual bool ShouldSkip(const clang::UsingShadowDecl *USD) const { return ShouldSkip((clang::Decl *)USD); };
141
142public:
143 TClingMemberIter() = default;
144
145 TClingMemberIter(cling::Interpreter *interp, clang::DeclContext *DC) : fInterp(interp), fDCIter(DC, interp) {}
146
147 void Init()
148 {
149 // This function needs the derived class to be constructed (vtable and such),
150 // and thus cannot be embedded in the constructor.
151 if (IsValid())
152 Advance();
153 }
154
155 /// Advance to next non-skipped; return false if no next decl exists.
156 bool Next()
157 {
158 if (AdvanceUnfiltered())
159 return Advance();
160 return false;
161 }
162
163 virtual const clang::Decl *Get() const
164 {
165 if (fTemplateSpec)
166 return fTemplateSpec;
168 return *fUsingDeclIter;
169 if (fDCIter.IsValid())
170 return *fDCIter;
171 return nullptr;
172 }
173
174 const clang::Decl *operator->() const { return Get(); }
175
176 const clang::Decl *operator*() const { return Get(); }
177
178 virtual bool IsValid() const { return fInterp && (fDCIter.IsValid() || fUsingDeclIter.IsValid()); }
179
180 cling::Interpreter *GetInterpreter() const { return fInterp; }
181};
182
183#endif // ROOT_TClingMethodInfo
Iteration over collected DeclContexts.
llvm::SmallVector< clang::DeclContext *, 2 > fContexts
clang::Decl * operator*() const
bool AdvanceToFirstValidDecl()
Do not return inline namespaces etc.
bool IterNext()
Increment the iterator, possibly moving to the next context.
clang::DeclContext::decl_iterator fDeclIter
clang::Decl * operator->() const
bool HandleInlineDeclContext()
Return true if fDeclIter has triggered an inline or anonymous namespace / ... to be appended to fCont...
std::stack< UsingDeclFrame > fUsingIterStack
Handle nested UsingDecls:
const clang::UsingDecl::shadow_iterator & Iter() const
const clang::UsingDecl::shadow_iterator & End() const
clang::UsingDecl::shadow_iterator & Iter()
Iterate over all DeclT-s (or UsingShadowDecl-s pointing to DeclT-s) of a decl context,...
ClingMemberIterInternal::UsingDeclIter fUsingDeclIter
TClingMemberIter()=default
virtual const clang::Decl * Get() const
virtual bool ShouldSkip(const clang::Decl *D) const =0
virtual bool ShouldSkip(const clang::UsingShadowDecl *USD) const
const clang::Decl * fTemplateSpec
const clang::Decl * operator->() const
bool Next()
Advance to next non-skipped; return false if no next decl exists.
cling::Interpreter * fInterp
TClingMemberIter(cling::Interpreter *interp, clang::DeclContext *DC)
virtual clang::Decl * AdvanceUnfiltered()
const clang::Decl * GetDeclSlow() const
cling::Interpreter * GetInterpreter() const
virtual bool IsValid() const
ClingMemberIterInternal::DCIter fDCIter
const clang::Decl * operator*() const
virtual const clang::Decl * InstantiateTemplateWithDefaults(const clang::RedeclarableTemplateDecl *TD) const