Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:53

0001 //===- ExtractAPI/Serialization/APISetVisitor.h ----------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// This file defines the ExtractAPI APISetVisitor interface.
0011 ///
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
0015 #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
0016 
0017 #include "clang/ExtractAPI/API.h"
0018 
0019 namespace clang {
0020 namespace extractapi {
0021 
0022 // A helper macro to implement short-circuiting when recursing.  It
0023 // invokes CALL_EXPR, which must be a method call, on the derived
0024 // object (s.t. a user of RecursiveASTVisitor can override the method
0025 // in CALL_EXPR).
0026 #define TRY_TO(CALL_EXPR)                                                      \
0027   do {                                                                         \
0028     if (!getDerived()->CALL_EXPR)                                              \
0029       return false;                                                            \
0030   } while (false)
0031 
0032 /// The base interface of visitors for API information, the interface and usage
0033 /// is almost identical to RecurisveASTVistor. This class performs three
0034 /// distinct tasks:
0035 /// 1. traverse the APISet (i.e. go to every record);
0036 /// 2. at a given record, walk up the class hierarchy starting from the record's
0037 /// dynamic type until APIRecord is reached.
0038 /// 3. given a (record, class) combination where 'class' is some base class of
0039 /// the dynamic type of 'record', call a user-overridable function to actually
0040 /// visit the record.
0041 ///
0042 /// These tasks are done by three groups of methods, respectively:
0043 /// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for
0044 /// traversing the records starting from x. This method simply forwards to
0045 /// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls
0046 /// walkUpFromFoo(x) and then recursively visits the child records of x.
0047 /// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of
0048 /// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent
0049 /// class of Foo (unless Foo has no parent) and then calls visitFoo(x).
0050 /// 3. visitFoo(Foo *x) does task #3.
0051 ///
0052 /// These three method groups are tiered (traverse* > walkUpFrom* >
0053 /// visit*).  A method (e.g. traverse*) may call methods from the same
0054 /// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*).
0055 /// It may not call methods from a higher tier.
0056 ///
0057 /// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar
0058 /// is Foo's super class) before calling visitFoo(), the result is
0059 /// that the visit*() methods for a given record are called in the
0060 /// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the
0061 /// order will be visitRecord(), visitObjCPropertyRecord(), and then
0062 /// visitObjCInstancePropertyRecord()).
0063 ///
0064 /// This scheme guarantees that all visit*() calls for the same record
0065 /// are grouped together.  In other words, visit*() methods for different
0066 /// records are never interleaved.
0067 ///
0068 /// Clients of this visitor should subclass the visitor (providing
0069 /// themselves as the template argument, using the curiously recurring
0070 /// template pattern) and override any of the traverse*, walkUpFrom*,
0071 /// and visit* methods for records where the visitor should customize
0072 /// behavior.  Most users only need to override visit*.  Advanced
0073 /// users may override traverse* and walkUpFrom* to implement custom
0074 /// traversal strategies.  Returning false from one of these overridden
0075 /// functions will abort the entire traversal.
0076 template <typename Derived> class APISetVisitor {
0077 public:
0078   bool traverseAPISet() {
0079     for (const APIRecord *TLR : API.getTopLevelRecords()) {
0080       TRY_TO(traverseAPIRecord(TLR));
0081     }
0082     return true;
0083   }
0084 
0085   bool traverseAPIRecord(const APIRecord *Record);
0086   bool walkUpFromAPIRecord(const APIRecord *Record) {
0087     TRY_TO(visitAPIRecord(Record));
0088     return true;
0089   }
0090   bool visitAPIRecord(const APIRecord *Record) { return true; }
0091 
0092 #define GENERATE_TRAVERSE_METHOD(CLASS, BASE)                                  \
0093   bool traverse##CLASS(const CLASS *Record) {                                  \
0094     TRY_TO(walkUpFrom##CLASS(Record));                                         \
0095     TRY_TO(traverseRecordContext(dyn_cast<RecordContext>(Record)));            \
0096     return true;                                                               \
0097   }
0098 
0099 #define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)                         \
0100   bool walkUpFrom##CLASS(const CLASS *Record) {                                \
0101     TRY_TO(walkUpFrom##BASE(Record));                                          \
0102     TRY_TO(visit##CLASS(Record));                                              \
0103     return true;                                                               \
0104   }                                                                            \
0105   bool visit##CLASS(const CLASS *Record) { return true; }
0106 
0107 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
0108   GENERATE_TRAVERSE_METHOD(CLASS, BASE)                                        \
0109   GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
0110 
0111 #define ABSTRACT_RECORD(CLASS, BASE)                                           \
0112   GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
0113 
0114 #include "../APIRecords.inc"
0115 
0116 #undef GENERATE_WALKUP_AND_VISIT_METHODS
0117 #undef GENERATE_TRAVERSE_METHOD
0118 
0119   bool traverseRecordContext(const RecordContext *);
0120 
0121 protected:
0122   const APISet &API;
0123 
0124 public:
0125   APISetVisitor() = delete;
0126   APISetVisitor(const APISetVisitor &) = delete;
0127   APISetVisitor(APISetVisitor &&) = delete;
0128   APISetVisitor &operator=(const APISetVisitor &) = delete;
0129   APISetVisitor &operator=(APISetVisitor &&) = delete;
0130 
0131 protected:
0132   APISetVisitor(const APISet &API) : API(API) {}
0133   ~APISetVisitor() = default;
0134 
0135   Derived *getDerived() { return static_cast<Derived *>(this); };
0136 };
0137 
0138 template <typename Derived>
0139 bool APISetVisitor<Derived>::traverseRecordContext(
0140     const RecordContext *Context) {
0141   if (!Context)
0142     return true;
0143 
0144   for (auto *Child : Context->records())
0145     TRY_TO(traverseAPIRecord(Child));
0146 
0147   return true;
0148 }
0149 
0150 template <typename Derived>
0151 bool APISetVisitor<Derived>::traverseAPIRecord(const APIRecord *Record) {
0152   switch (Record->getKind()) {
0153 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
0154   case APIRecord::KIND: {                                                      \
0155     TRY_TO(traverse##CLASS(static_cast<const CLASS *>(Record)));               \
0156     break;                                                                     \
0157   }
0158 #include "../APIRecords.inc"
0159   case APIRecord::RK_Unknown: {
0160     TRY_TO(walkUpFromAPIRecord(static_cast<const APIRecord *>(Record)));
0161     break;
0162   }
0163   default:
0164     llvm_unreachable("API Record with uninstantiable kind");
0165   }
0166   return true;
0167 }
0168 
0169 } // namespace extractapi
0170 } // namespace clang
0171 
0172 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H