xref: /freebsd/contrib/llvm-project/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- ExtractAPI/Serialization/APISetVisitor.h ----------------*- 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 /// \file
10 /// This file defines the ExtractAPI APISetVisitor interface.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
15 #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
16 
17 #include "clang/ExtractAPI/API.h"
18 
19 namespace clang {
20 namespace extractapi {
21 
22 // A helper macro to implement short-circuiting when recursing.  It
23 // invokes CALL_EXPR, which must be a method call, on the derived
24 // object (s.t. a user of RecursiveASTVisitor can override the method
25 // in CALL_EXPR).
26 #define TRY_TO(CALL_EXPR)                                                      \
27   do {                                                                         \
28     if (!getDerived()->CALL_EXPR)                                              \
29       return false;                                                            \
30   } while (false)
31 
32 /// The base interface of visitors for API information, the interface and usage
33 /// is almost identical to RecurisveASTVistor. This class performs three
34 /// distinct tasks:
35 /// 1. traverse the APISet (i.e. go to every record);
36 /// 2. at a given record, walk up the class hierarchy starting from the record's
37 /// dynamic type until APIRecord is reached.
38 /// 3. given a (record, class) combination where 'class' is some base class of
39 /// the dynamic type of 'record', call a user-overridable function to actually
40 /// visit the record.
41 ///
42 /// These tasks are done by three groups of methods, respectively:
43 /// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for
44 /// traversing the records starting from x. This method simply forwards to
45 /// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls
46 /// walkUpFromFoo(x) and then recursively visits the child records of x.
47 /// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of
48 /// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent
49 /// class of Foo (unless Foo has no parent) and then calls visitFoo(x).
50 /// 3. visitFoo(Foo *x) does task #3.
51 ///
52 /// These three method groups are tiered (traverse* > walkUpFrom* >
53 /// visit*).  A method (e.g. traverse*) may call methods from the same
54 /// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*).
55 /// It may not call methods from a higher tier.
56 ///
57 /// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar
58 /// is Foo's super class) before calling visitFoo(), the result is
59 /// that the visit*() methods for a given record are called in the
60 /// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the
61 /// order will be visitRecord(), visitObjCPropertyRecord(), and then
62 /// visitObjCInstancePropertyRecord()).
63 ///
64 /// This scheme guarantees that all visit*() calls for the same record
65 /// are grouped together.  In other words, visit*() methods for different
66 /// records are never interleaved.
67 ///
68 /// Clients of this visitor should subclass the visitor (providing
69 /// themselves as the template argument, using the curiously recurring
70 /// template pattern) and override any of the traverse*, walkUpFrom*,
71 /// and visit* methods for records where the visitor should customize
72 /// behavior.  Most users only need to override visit*.  Advanced
73 /// users may override traverse* and walkUpFrom* to implement custom
74 /// traversal strategies.  Returning false from one of these overridden
75 /// functions will abort the entire traversal.
76 template <typename Derived> class APISetVisitor {
77 public:
traverseAPISet()78   bool traverseAPISet() {
79     for (const APIRecord *TLR : API.getTopLevelRecords()) {
80       TRY_TO(traverseAPIRecord(TLR));
81     }
82     return true;
83   }
84 
85   bool traverseAPIRecord(const APIRecord *Record);
walkUpFromAPIRecord(const APIRecord * Record)86   bool walkUpFromAPIRecord(const APIRecord *Record) {
87     TRY_TO(visitAPIRecord(Record));
88     return true;
89   }
visitAPIRecord(const APIRecord * Record)90   bool visitAPIRecord(const APIRecord *Record) { return true; }
91 
92 #define GENERATE_TRAVERSE_METHOD(CLASS, BASE)                                  \
93   bool traverse##CLASS(const CLASS *Record) {                                  \
94     TRY_TO(walkUpFrom##CLASS(Record));                                         \
95     TRY_TO(traverseRecordContext(dyn_cast<RecordContext>(Record)));            \
96     return true;                                                               \
97   }
98 
99 #define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)                         \
100   bool walkUpFrom##CLASS(const CLASS *Record) {                                \
101     TRY_TO(walkUpFrom##BASE(Record));                                          \
102     TRY_TO(visit##CLASS(Record));                                              \
103     return true;                                                               \
104   }                                                                            \
105   bool visit##CLASS(const CLASS *Record) { return true; }
106 
107 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
108   GENERATE_TRAVERSE_METHOD(CLASS, BASE)                                        \
109   GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
110 
111 #define ABSTRACT_RECORD(CLASS, BASE)                                           \
112   GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
113 
114 #include "../APIRecords.inc"
115 
116 #undef GENERATE_WALKUP_AND_VISIT_METHODS
117 #undef GENERATE_TRAVERSE_METHOD
118 
119   bool traverseRecordContext(const RecordContext *);
120 
121 protected:
122   const APISet &API;
123 
124 public:
125   APISetVisitor() = delete;
126   APISetVisitor(const APISetVisitor &) = delete;
127   APISetVisitor(APISetVisitor &&) = delete;
128   APISetVisitor &operator=(const APISetVisitor &) = delete;
129   APISetVisitor &operator=(APISetVisitor &&) = delete;
130 
131 protected:
APISetVisitor(const APISet & API)132   APISetVisitor(const APISet &API) : API(API) {}
133   ~APISetVisitor() = default;
134 
getDerived()135   Derived *getDerived() { return static_cast<Derived *>(this); };
136 };
137 
138 template <typename Derived>
traverseRecordContext(const RecordContext * Context)139 bool APISetVisitor<Derived>::traverseRecordContext(
140     const RecordContext *Context) {
141   if (!Context)
142     return true;
143 
144   for (auto *Child : Context->records())
145     TRY_TO(traverseAPIRecord(Child));
146 
147   return true;
148 }
149 
150 template <typename Derived>
traverseAPIRecord(const APIRecord * Record)151 bool APISetVisitor<Derived>::traverseAPIRecord(const APIRecord *Record) {
152   switch (Record->getKind()) {
153 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
154   case APIRecord::KIND: {                                                      \
155     TRY_TO(traverse##CLASS(static_cast<const CLASS *>(Record)));               \
156     break;                                                                     \
157   }
158 #include "../APIRecords.inc"
159   case APIRecord::RK_Unknown: {
160     TRY_TO(walkUpFromAPIRecord(static_cast<const APIRecord *>(Record)));
161     break;
162   }
163   default:
164     llvm_unreachable("API Record with uninstantiable kind");
165   }
166   return true;
167 }
168 
169 } // namespace extractapi
170 } // namespace clang
171 
172 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
173