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 |
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 { |
77 | public: |
78 | bool () { |
79 | for (const APIRecord *TLR : API.getTopLevelRecords()) { |
80 | TRY_TO(traverseAPIRecord(TLR)); |
81 | } |
82 | return true; |
83 | } |
84 | |
85 | bool traverseAPIRecord(const APIRecord *Record); |
86 | bool (const APIRecord *Record) { |
87 | TRY_TO(visitAPIRecord(Record)); |
88 | return true; |
89 | } |
90 | bool (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 &; |
123 | |
124 | public: |
125 | () = delete; |
126 | (const APISetVisitor &) = delete; |
127 | (APISetVisitor &&) = delete; |
128 | APISetVisitor &(const APISetVisitor &) = delete; |
129 | APISetVisitor &(APISetVisitor &&) = delete; |
130 | |
131 | protected: |
132 | (const APISet &API) : API(API) {} |
133 | () = default; |
134 | |
135 | Derived *() { return static_cast<Derived *>(this); }; |
136 | }; |
137 | |
138 | template <typename Derived> |
139 | bool APISetVisitor<Derived>::( |
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> |
151 | bool APISetVisitor<Derived>::(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 | |