clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
173 lines
7.1 KiB
C++
173 lines
7.1 KiB
C++
//===- ExtractAPI/Serialization/APISetVisitor.h ----------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file defines the ExtractAPI APISetVisitor interface.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
|
|
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
|
|
|
|
#include "clang/ExtractAPI/API.h"
|
|
|
|
namespace clang {
|
|
namespace extractapi {
|
|
|
|
// A helper macro to implement short-circuiting when recursing. It
|
|
// invokes CALL_EXPR, which must be a method call, on the derived
|
|
// object (s.t. a user of RecursiveASTVisitor can override the method
|
|
// in CALL_EXPR).
|
|
#define TRY_TO(CALL_EXPR) \
|
|
do { \
|
|
if (!getDerived()->CALL_EXPR) \
|
|
return false; \
|
|
} while (false)
|
|
|
|
/// The base interface of visitors for API information, the interface and usage
|
|
/// is almost identical to RecurisveASTVistor. This class performs three
|
|
/// distinct tasks:
|
|
/// 1. traverse the APISet (i.e. go to every record);
|
|
/// 2. at a given record, walk up the class hierarchy starting from the record's
|
|
/// dynamic type until APIRecord is reached.
|
|
/// 3. given a (record, class) combination where 'class' is some base class of
|
|
/// the dynamic type of 'record', call a user-overridable function to actually
|
|
/// visit the record.
|
|
///
|
|
/// These tasks are done by three groups of methods, respectively:
|
|
/// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for
|
|
/// traversing the records starting from x. This method simply forwards to
|
|
/// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls
|
|
/// walkUpFromFoo(x) and then recursively visits the child records of x.
|
|
/// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of
|
|
/// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent
|
|
/// class of Foo (unless Foo has no parent) and then calls visitFoo(x).
|
|
/// 3. visitFoo(Foo *x) does task #3.
|
|
///
|
|
/// These three method groups are tiered (traverse* > walkUpFrom* >
|
|
/// visit*). A method (e.g. traverse*) may call methods from the same
|
|
/// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*).
|
|
/// It may not call methods from a higher tier.
|
|
///
|
|
/// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar
|
|
/// is Foo's super class) before calling visitFoo(), the result is
|
|
/// that the visit*() methods for a given record are called in the
|
|
/// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the
|
|
/// order will be visitRecord(), visitObjCPropertyRecord(), and then
|
|
/// visitObjCInstancePropertyRecord()).
|
|
///
|
|
/// This scheme guarantees that all visit*() calls for the same record
|
|
/// are grouped together. In other words, visit*() methods for different
|
|
/// records are never interleaved.
|
|
///
|
|
/// Clients of this visitor should subclass the visitor (providing
|
|
/// themselves as the template argument, using the curiously recurring
|
|
/// template pattern) and override any of the traverse*, walkUpFrom*,
|
|
/// and visit* methods for records where the visitor should customize
|
|
/// behavior. Most users only need to override visit*. Advanced
|
|
/// users may override traverse* and walkUpFrom* to implement custom
|
|
/// traversal strategies. Returning false from one of these overridden
|
|
/// functions will abort the entire traversal.
|
|
template <typename Derived> class APISetVisitor {
|
|
public:
|
|
bool traverseAPISet() {
|
|
for (const APIRecord *TLR : API.getTopLevelRecords()) {
|
|
TRY_TO(traverseAPIRecord(TLR));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool traverseAPIRecord(const APIRecord *Record);
|
|
bool walkUpFromAPIRecord(const APIRecord *Record) {
|
|
TRY_TO(visitAPIRecord(Record));
|
|
return true;
|
|
}
|
|
bool visitAPIRecord(const APIRecord *Record) { return true; }
|
|
|
|
#define GENERATE_TRAVERSE_METHOD(CLASS, BASE) \
|
|
bool traverse##CLASS(const CLASS *Record) { \
|
|
TRY_TO(walkUpFrom##CLASS(Record)); \
|
|
TRY_TO(traverseRecordContext(dyn_cast<RecordContext>(Record))); \
|
|
return true; \
|
|
}
|
|
|
|
#define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) \
|
|
bool walkUpFrom##CLASS(const CLASS *Record) { \
|
|
TRY_TO(walkUpFrom##BASE(Record)); \
|
|
TRY_TO(visit##CLASS(Record)); \
|
|
return true; \
|
|
} \
|
|
bool visit##CLASS(const CLASS *Record) { return true; }
|
|
|
|
#define CONCRETE_RECORD(CLASS, BASE, KIND) \
|
|
GENERATE_TRAVERSE_METHOD(CLASS, BASE) \
|
|
GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
|
|
|
|
#define ABSTRACT_RECORD(CLASS, BASE) \
|
|
GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)
|
|
|
|
#include "../APIRecords.inc"
|
|
|
|
#undef GENERATE_WALKUP_AND_VISIT_METHODS
|
|
#undef GENERATE_TRAVERSE_METHOD
|
|
|
|
bool traverseRecordContext(const RecordContext *);
|
|
|
|
protected:
|
|
const APISet &API;
|
|
|
|
public:
|
|
APISetVisitor() = delete;
|
|
APISetVisitor(const APISetVisitor &) = delete;
|
|
APISetVisitor(APISetVisitor &&) = delete;
|
|
APISetVisitor &operator=(const APISetVisitor &) = delete;
|
|
APISetVisitor &operator=(APISetVisitor &&) = delete;
|
|
|
|
protected:
|
|
APISetVisitor(const APISet &API) : API(API) {}
|
|
~APISetVisitor() = default;
|
|
|
|
Derived *getDerived() { return static_cast<Derived *>(this); };
|
|
};
|
|
|
|
template <typename Derived>
|
|
bool APISetVisitor<Derived>::traverseRecordContext(
|
|
const RecordContext *Context) {
|
|
if (!Context)
|
|
return true;
|
|
|
|
for (auto *Child : Context->records())
|
|
TRY_TO(traverseAPIRecord(Child));
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename Derived>
|
|
bool APISetVisitor<Derived>::traverseAPIRecord(const APIRecord *Record) {
|
|
switch (Record->getKind()) {
|
|
#define CONCRETE_RECORD(CLASS, BASE, KIND) \
|
|
case APIRecord::KIND: { \
|
|
TRY_TO(traverse##CLASS(static_cast<const CLASS *>(Record))); \
|
|
break; \
|
|
}
|
|
#include "../APIRecords.inc"
|
|
case APIRecord::RK_Unknown: {
|
|
TRY_TO(walkUpFromAPIRecord(static_cast<const APIRecord *>(Record)));
|
|
break;
|
|
}
|
|
default:
|
|
llvm_unreachable("API Record with uninstantiable kind");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace extractapi
|
|
} // namespace clang
|
|
|
|
#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
|