mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Clang generator: Remember "seen" types when collecting related types
This change includes a small refactoring to remember which types the generator has already seen during header generations. Otherwise we may loop indefinitely on certain complex types. One such type is `std::FILE` in Clang's libc++. PiperOrigin-RevId: 335589238 Change-Id: I5bbe03b6c7fc89c743163f5534075d7912ed4e58
This commit is contained in:
parent
b74cf8839b
commit
afa232cc17
|
@ -59,9 +59,9 @@ bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
|
||||||
options_.function_names.count(ToStringView(decl->getName())) > 0)) {
|
options_.function_names.count(ToStringView(decl->getName())) > 0)) {
|
||||||
functions_.push_back(decl);
|
functions_.push_back(decl);
|
||||||
|
|
||||||
CollectRelatedTypes(decl->getDeclaredReturnType(), &types_);
|
collector_.CollectRelatedTypes(decl->getDeclaredReturnType());
|
||||||
for (const clang::ParmVarDecl* param : decl->parameters()) {
|
for (const clang::ParmVarDecl* param : decl->parameters()) {
|
||||||
CollectRelatedTypes(param->getType(), &types_);
|
collector_.CollectRelatedTypes(param->getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -75,7 +75,7 @@ void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
|
||||||
"AST traversal exited early");
|
"AST traversal exited early");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (clang::QualType qual : visitor_.types_) {
|
for (clang::QualType qual : visitor_.collector_.collected()) {
|
||||||
emitter_.CollectType(qual);
|
emitter_.CollectType(qual);
|
||||||
}
|
}
|
||||||
for (clang::FunctionDecl* func : visitor_.functions_) {
|
for (clang::FunctionDecl* func : visitor_.functions_) {
|
||||||
|
|
|
@ -65,8 +65,9 @@ class GeneratorASTVisitor
|
||||||
private:
|
private:
|
||||||
friend class GeneratorASTConsumer;
|
friend class GeneratorASTConsumer;
|
||||||
|
|
||||||
|
TypeCollector collector_;
|
||||||
|
|
||||||
std::vector<clang::FunctionDecl*> functions_;
|
std::vector<clang::FunctionDecl*> functions_;
|
||||||
QualTypeSet types_;
|
|
||||||
|
|
||||||
const GeneratorOptions& options_;
|
const GeneratorOptions& options_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,10 +30,15 @@ bool IsFunctionReferenceType(clang::QualType qual) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
void TypeCollector::CollectRelatedTypes(clang::QualType qual) {
|
||||||
|
if (seen_.contains(qual)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen_.insert(qual);
|
||||||
|
|
||||||
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
||||||
CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types);
|
CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType());
|
||||||
types->insert(qual);
|
collected_.insert(qual);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,26 +48,26 @@ void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
||||||
->getAs<clang::FunctionProtoType>()) {
|
->getAs<clang::FunctionProtoType>()) {
|
||||||
// Note: Do not add the function type itself, as this will always be a
|
// Note: Do not add the function type itself, as this will always be a
|
||||||
// pointer argument. We only need to collect all its related types.
|
// pointer argument. We only need to collect all its related types.
|
||||||
CollectRelatedTypes(function_type->getReturnType(), types);
|
CollectRelatedTypes(function_type->getReturnType());
|
||||||
for (const clang::QualType& param : function_type->getParamTypes()) {
|
for (const clang::QualType& param : function_type->getParamTypes()) {
|
||||||
CollectRelatedTypes(param, types);
|
CollectRelatedTypes(param);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPointerOrReference(qual)) {
|
if (IsPointerOrReference(qual)) {
|
||||||
clang::QualType pointee = qual->getPointeeType();
|
clang::QualType pointee = qual;
|
||||||
while (IsPointerOrReference(pointee)) {
|
do {
|
||||||
pointee = pointee->getPointeeType();
|
pointee = pointee->getPointeeType();
|
||||||
}
|
} while (IsPointerOrReference(pointee));
|
||||||
CollectRelatedTypes(pointee, types);
|
CollectRelatedTypes(pointee);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C array with specified constant size (i.e. int a[42])?
|
// C array with specified constant size (i.e. int a[42])?
|
||||||
if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) {
|
if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) {
|
||||||
CollectRelatedTypes(array_type->getElementType(), types);
|
CollectRelatedTypes(array_type->getElementType());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,19 +76,19 @@ void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
||||||
// Collect the underlying integer type of enum classes as well, as it may
|
// Collect the underlying integer type of enum classes as well, as it may
|
||||||
// be a typedef.
|
// be a typedef.
|
||||||
if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) {
|
if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) {
|
||||||
CollectRelatedTypes(decl->getIntegerType(), types);
|
CollectRelatedTypes(decl->getIntegerType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
types->insert(qual);
|
collected_.insert(qual);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* record_type = qual->getAs<clang::RecordType>()) {
|
if (const auto* record_type = qual->getAs<clang::RecordType>()) {
|
||||||
const clang::RecordDecl* decl = record_type->getDecl();
|
const clang::RecordDecl* decl = record_type->getDecl();
|
||||||
for (const clang::FieldDecl* field : decl->fields()) {
|
for (const clang::FieldDecl* field : decl->fields()) {
|
||||||
CollectRelatedTypes(field->getType(), types);
|
CollectRelatedTypes(field->getType());
|
||||||
}
|
}
|
||||||
types->insert(qual);
|
collected_.insert(qual);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,20 +41,29 @@ inline bool IsPointerOrReference(clang::QualType qual) {
|
||||||
qual->isLValueReferenceType() || qual->isRValueReferenceType();
|
qual->isLValueReferenceType() || qual->isRValueReferenceType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes the transitive closure of all types that a type depends on. Those
|
class TypeCollector {
|
||||||
// are types that need to be declared before a declaration of the type denoted
|
public:
|
||||||
// by the qual parameter is valid. For example, given
|
// Computes the transitive closure of all types that a type depends on. Those
|
||||||
// struct SubStruct { bool truth_value; };
|
// are types that need to be declared before a declaration of the type denoted
|
||||||
// struct AggregateStruct {
|
// by the qual parameter is valid. For example, given
|
||||||
// int int_member;
|
// struct SubStruct { bool truth_value; };
|
||||||
// SubStruct struct_member;
|
// struct AggregateStruct {
|
||||||
// };
|
// int int_member;
|
||||||
//
|
// SubStruct struct_member;
|
||||||
// calling this function on the type "AggregateStruct" yields these types:
|
// };
|
||||||
// int
|
//
|
||||||
// SubStruct
|
// calling this function on the type "AggregateStruct" yields these types:
|
||||||
// bool
|
// int
|
||||||
void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types);
|
// SubStruct
|
||||||
|
// bool
|
||||||
|
void CollectRelatedTypes(clang::QualType qual);
|
||||||
|
|
||||||
|
QualTypeSet& collected() { return collected_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QualTypeSet collected_;
|
||||||
|
QualTypeSet seen_;
|
||||||
|
};
|
||||||
|
|
||||||
// Maps a qualified type to a fully qualified SAPI-compatible type name. This
|
// Maps a qualified type to a fully qualified SAPI-compatible type name. This
|
||||||
// is used for the generated code that invokes the actual function call RPC.
|
// is used for the generated code that invokes the actual function call RPC.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user