From afa232cc176f1f61025a5ed353ee5bf70262d70e Mon Sep 17 00:00:00 2001 From: Christian Blichmann Date: Tue, 6 Oct 2020 01:04:11 -0700 Subject: [PATCH] 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 --- .../tools/clang_generator/generator.cc | 6 +-- .../tools/clang_generator/generator.h | 3 +- sandboxed_api/tools/clang_generator/types.cc | 33 ++++++++++------- sandboxed_api/tools/clang_generator/types.h | 37 ++++++++++++------- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/sandboxed_api/tools/clang_generator/generator.cc b/sandboxed_api/tools/clang_generator/generator.cc index 091b234..c647fe4 100644 --- a/sandboxed_api/tools/clang_generator/generator.cc +++ b/sandboxed_api/tools/clang_generator/generator.cc @@ -59,9 +59,9 @@ bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) { options_.function_names.count(ToStringView(decl->getName())) > 0)) { functions_.push_back(decl); - CollectRelatedTypes(decl->getDeclaredReturnType(), &types_); + collector_.CollectRelatedTypes(decl->getDeclaredReturnType()); for (const clang::ParmVarDecl* param : decl->parameters()) { - CollectRelatedTypes(param->getType(), &types_); + collector_.CollectRelatedTypes(param->getType()); } } return true; @@ -75,7 +75,7 @@ void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) { "AST traversal exited early"); } - for (clang::QualType qual : visitor_.types_) { + for (clang::QualType qual : visitor_.collector_.collected()) { emitter_.CollectType(qual); } for (clang::FunctionDecl* func : visitor_.functions_) { diff --git a/sandboxed_api/tools/clang_generator/generator.h b/sandboxed_api/tools/clang_generator/generator.h index bc59860..f13890d 100644 --- a/sandboxed_api/tools/clang_generator/generator.h +++ b/sandboxed_api/tools/clang_generator/generator.h @@ -65,8 +65,9 @@ class GeneratorASTVisitor private: friend class GeneratorASTConsumer; + TypeCollector collector_; + std::vector functions_; - QualTypeSet types_; const GeneratorOptions& options_; }; diff --git a/sandboxed_api/tools/clang_generator/types.cc b/sandboxed_api/tools/clang_generator/types.cc index 4e12746..bc9dd37 100644 --- a/sandboxed_api/tools/clang_generator/types.cc +++ b/sandboxed_api/tools/clang_generator/types.cc @@ -30,10 +30,15 @@ bool IsFunctionReferenceType(clang::QualType qual) { } // 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()) { - CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types); - types->insert(qual); + CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType()); + collected_.insert(qual); return; } @@ -43,26 +48,26 @@ void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) { ->getAs()) { // 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. - CollectRelatedTypes(function_type->getReturnType(), types); + CollectRelatedTypes(function_type->getReturnType()); for (const clang::QualType& param : function_type->getParamTypes()) { - CollectRelatedTypes(param, types); + CollectRelatedTypes(param); } return; } } if (IsPointerOrReference(qual)) { - clang::QualType pointee = qual->getPointeeType(); - while (IsPointerOrReference(pointee)) { + clang::QualType pointee = qual; + do { pointee = pointee->getPointeeType(); - } - CollectRelatedTypes(pointee, types); + } while (IsPointerOrReference(pointee)); + CollectRelatedTypes(pointee); return; } // C array with specified constant size (i.e. int a[42])? if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) { - CollectRelatedTypes(array_type->getElementType(), types); + CollectRelatedTypes(array_type->getElementType()); 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 // be a typedef. if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) { - CollectRelatedTypes(decl->getIntegerType(), types); + CollectRelatedTypes(decl->getIntegerType()); } } - types->insert(qual); + collected_.insert(qual); return; } if (const auto* record_type = qual->getAs()) { const clang::RecordDecl* decl = record_type->getDecl(); for (const clang::FieldDecl* field : decl->fields()) { - CollectRelatedTypes(field->getType(), types); + CollectRelatedTypes(field->getType()); } - types->insert(qual); + collected_.insert(qual); return; } } diff --git a/sandboxed_api/tools/clang_generator/types.h b/sandboxed_api/tools/clang_generator/types.h index 78c7706..d4a78c1 100644 --- a/sandboxed_api/tools/clang_generator/types.h +++ b/sandboxed_api/tools/clang_generator/types.h @@ -41,20 +41,29 @@ inline bool IsPointerOrReference(clang::QualType qual) { qual->isLValueReferenceType() || qual->isRValueReferenceType(); } -// Computes the transitive closure of all types that a type depends on. Those -// are types that need to be declared before a declaration of the type denoted -// by the qual parameter is valid. For example, given -// struct SubStruct { bool truth_value; }; -// struct AggregateStruct { -// int int_member; -// SubStruct struct_member; -// }; -// -// calling this function on the type "AggregateStruct" yields these types: -// int -// SubStruct -// bool -void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types); +class TypeCollector { + public: + // Computes the transitive closure of all types that a type depends on. Those + // are types that need to be declared before a declaration of the type denoted + // by the qual parameter is valid. For example, given + // struct SubStruct { bool truth_value; }; + // struct AggregateStruct { + // int int_member; + // SubStruct struct_member; + // }; + // + // calling this function on the type "AggregateStruct" yields these types: + // int + // 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 // is used for the generated code that invokes the actual function call RPC.