Index: tools/clang/blink_gc_plugin/RecordInfo.cpp |
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp |
index b491e4738db8ef5c40b19cbb9342ecd901f28450..cd5263289a1cab84fedf470eb83af45593815efd 100644 |
--- a/tools/clang/blink_gc_plugin/RecordInfo.cpp |
+++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp |
@@ -23,13 +23,11 @@ RecordInfo::RecordInfo(CXXRecordDecl* record, RecordCache* cache) |
trace_method_(0), |
trace_dispatch_method_(0), |
finalize_dispatch_method_(0), |
- is_gc_derived_(false), |
- base_paths_(0) {} |
+ is_gc_derived_(false) {} |
RecordInfo::~RecordInfo() { |
delete fields_; |
delete bases_; |
- delete base_paths_; |
} |
// Get |count| number of template arguments. Returns false if there |
@@ -74,22 +72,12 @@ bool RecordInfo::IsHeapAllocatedCollection() { |
return Config::IsGCCollection(name_); |
} |
-static bool IsGCBaseCallback(const CXXBaseSpecifier* specifier, |
- CXXBasePath& path, |
- void* data) { |
- if (CXXRecordDecl* record = specifier->getType()->getAsCXXRecordDecl()) |
- return Config::IsGCBase(record->getName()); |
- return false; |
-} |
- |
// Test if a record is derived from a garbage collected base. |
bool RecordInfo::IsGCDerived() { |
// If already computed, return the known result. |
- if (base_paths_) |
+ if (gc_base_names_.size()) |
return is_gc_derived_; |
- base_paths_ = new CXXBasePaths(true, true, false); |
- |
if (!record_->hasDefinition()) |
return false; |
@@ -98,19 +86,62 @@ bool RecordInfo::IsGCDerived() { |
return false; |
// Walk the inheritance tree to find GC base classes. |
- is_gc_derived_ = record_->lookupInBases(IsGCBaseCallback, 0, *base_paths_); |
+ walkBases(); |
return is_gc_derived_; |
} |
+CXXRecordDecl* RecordInfo::GetDependentTemplatedDecl(const Type& type) { |
+ const TemplateSpecializationType* tmpl_type = |
+ type.getAs<TemplateSpecializationType>(); |
+ if (!tmpl_type) |
+ return 0; |
+ |
+ TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); |
+ if (!tmpl_decl) |
+ return 0; |
+ |
+ return dyn_cast_or_null<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); |
+} |
+ |
+void RecordInfo::walkBases() { |
+ // This traversal is akin to CXXRecordDecl::forallBases()'s, |
+ // but without stepping over dependent bases -- these might also |
+ // have a "GC base name", so are to be included and considered. |
+ SmallVector<const CXXRecordDecl*, 8> queue; |
+ |
+ const CXXRecordDecl *base_record = record(); |
+ while (true) { |
+ for (const auto& it : base_record->bases()) { |
+ const RecordType *type = it.getType()->getAs<RecordType>(); |
+ CXXRecordDecl* base; |
+ if (!type) |
+ base = GetDependentTemplatedDecl(*it.getType()); |
+ else { |
+ base = cast_or_null<CXXRecordDecl>(type->getDecl()->getDefinition()); |
+ if (base) |
+ queue.push_back(base); |
+ } |
+ if (!base) |
+ continue; |
+ |
+ const std::string& name = base->getName(); |
+ if (Config::IsGCBase(name)) { |
+ gc_base_names_.push_back(name); |
+ is_gc_derived_ = true; |
+ } |
+ } |
+ |
+ if (queue.empty()) |
+ break; |
+ base_record = queue.pop_back_val(); // not actually a queue. |
+ } |
+} |
+ |
bool RecordInfo::IsGCFinalized() { |
if (!IsGCDerived()) |
return false; |
- for (CXXBasePaths::paths_iterator it = base_paths_->begin(); |
- it != base_paths_->end(); |
- ++it) { |
- const CXXBasePathElement& elem = (*it)[it->size() - 1]; |
- CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); |
- if (Config::IsGCFinalizedBase(base->getName())) |
+ for (const auto& gc_base : gc_base_names_) { |
+ if (Config::IsGCFinalizedBase(gc_base)) |
return true; |
} |
return false; |
@@ -119,16 +150,11 @@ bool RecordInfo::IsGCFinalized() { |
// A GC mixin is a class that inherits from a GC mixin base and has |
// not yet been "mixed in" with another GC base class. |
bool RecordInfo::IsGCMixin() { |
- if (!IsGCDerived() || base_paths_->begin() == base_paths_->end()) |
+ if (!IsGCDerived() || !gc_base_names_.size()) |
return false; |
- for (CXXBasePaths::paths_iterator it = base_paths_->begin(); |
- it != base_paths_->end(); |
- ++it) { |
- // Get the last element of the path. |
- const CXXBasePathElement& elem = (*it)[it->size() - 1]; |
- CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); |
+ for (const auto& gc_base : gc_base_names_) { |
// If it is not a mixin base we are done. |
- if (!Config::IsGCMixinBase(base->getName())) |
+ if (!Config::IsGCMixinBase(gc_base)) |
return false; |
} |
// This is a mixin if all GC bases are mixins. |