123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "RecordInfo.h"
- #include <string>
- #include "Config.h"
- #include "clang/Sema/Sema.h"
- using namespace clang;
- using std::string;
- RecordInfo::RecordInfo(CXXRecordDecl* record, RecordCache* cache)
- : cache_(cache),
- record_(record),
- name_(record->getName()),
- fields_need_tracing_(TracingStatus::Unknown()),
- bases_(0),
- fields_(0),
- is_stack_allocated_(kNotComputed),
- is_non_newable_(kNotComputed),
- is_only_placement_newable_(kNotComputed),
- does_need_finalization_(kNotComputed),
- has_gc_mixin_methods_(kNotComputed),
- is_declaring_local_trace_(kNotComputed),
- determined_trace_methods_(false),
- trace_method_(0),
- trace_dispatch_method_(0),
- finalize_dispatch_method_(0),
- is_gc_derived_(false),
- directly_derived_gc_base_(nullptr) {}
- RecordInfo::~RecordInfo() {
- delete fields_;
- delete bases_;
- }
- // Get |count| number of template arguments. Returns false if there
- // are fewer than |count| arguments or any of the arguments are not
- // of a valid Type structure. If |count| is non-positive, all
- // arguments are collected.
- bool RecordInfo::GetTemplateArgs(size_t count, TemplateArgs* output_args) {
- ClassTemplateSpecializationDecl* tmpl =
- dyn_cast<ClassTemplateSpecializationDecl>(record_);
- if (!tmpl)
- return false;
- const TemplateArgumentList& args = tmpl->getTemplateArgs();
- if (args.size() < count)
- return false;
- if (count <= 0)
- count = args.size();
- for (unsigned i = 0; i < count; ++i) {
- TemplateArgument arg = args[i];
- if (arg.getKind() == TemplateArgument::Type && !arg.getAsType().isNull()) {
- output_args->push_back(arg.getAsType().getTypePtr());
- } else {
- return false;
- }
- }
- return true;
- }
- // Test if a record is a HeapAllocated collection.
- bool RecordInfo::IsHeapAllocatedCollection() {
- if (!Config::IsGCCollection(name_) && !Config::IsWTFCollection(name_))
- return false;
- TemplateArgs args;
- if (GetTemplateArgs(0, &args)) {
- for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) {
- if (CXXRecordDecl* decl = (*it)->getAsCXXRecordDecl())
- if (decl->getName() == kHeapAllocatorName)
- return true;
- }
- }
- return Config::IsGCCollection(name_);
- }
- bool RecordInfo::HasOptionalFinalizer() {
- if (!IsHeapAllocatedCollection())
- return false;
- // Heap collections may have a finalizer but it is optional (i.e. may be
- // delayed until FinalizeGarbageCollectedObject() gets called), unless there
- // is an inline buffer. Vector and Deque can have an inline
- // buffer.
- if (name_ != "Vector" && name_ != "Deque" && name_ != "HeapVector" &&
- name_ != "HeapDeque")
- return true;
- ClassTemplateSpecializationDecl* tmpl =
- dyn_cast<ClassTemplateSpecializationDecl>(record_);
- // These collections require template specialization so tmpl should always be
- // non-null for valid code.
- if (!tmpl)
- return false;
- const TemplateArgumentList& args = tmpl->getTemplateArgs();
- if (args.size() < 2)
- return true;
- TemplateArgument arg = args[1];
- // The second template argument must be void or 0 so there is no inline
- // buffer.
- return (arg.getKind() == TemplateArgument::Type &&
- arg.getAsType()->isVoidType()) ||
- (arg.getKind() == TemplateArgument::Integral &&
- arg.getAsIntegral().getExtValue() == 0);
- }
- // Test if a record is derived from a garbage collected base.
- bool RecordInfo::IsGCDerived() {
- // If already computed, return the known result.
- if (gc_base_names_.size())
- return is_gc_derived_;
- if (!record_->hasDefinition())
- return false;
- // The base classes are not themselves considered garbage collected objects.
- if (Config::IsGCBase(name_))
- return false;
- // Walk the inheritance tree to find GC base classes.
- walkBases();
- return is_gc_derived_;
- }
- // Test if a record is directly derived from a garbage collected base.
- bool RecordInfo::IsGCDirectlyDerived() {
- // If already computed, return the known result.
- if (directly_derived_gc_base_)
- return true;
- if (!record_->hasDefinition())
- return false;
- // The base classes are not themselves considered garbage collected objects.
- if (Config::IsGCBase(name_))
- return false;
- for (const auto& it : record()->bases()) {
- const CXXRecordDecl* base = it.getType()->getAsCXXRecordDecl();
- if (!base)
- continue;
- if (Config::IsGCSimpleBase(base->getName())) {
- directly_derived_gc_base_ = ⁢
- break;
- }
- }
- return directly_derived_gc_base_;
- }
- 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;
- if (CXXRecordDecl* record_decl =
- dyn_cast_or_null<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()))
- return record_decl;
- // Type is an alias.
- TypeAliasDecl* alias_decl =
- dyn_cast<TypeAliasDecl>(tmpl_decl->getTemplatedDecl());
- assert(alias_decl);
- const Type* alias_type = alias_decl->getUnderlyingType().getTypePtr();
- if (CXXRecordDecl* record_decl = alias_type->getAsCXXRecordDecl())
- return record_decl;
- return GetDependentTemplatedDecl(*alias_type);
- }
- 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;
- llvm::StringRef name = base->getName();
- if (Config::IsGCBase(name)) {
- gc_base_names_.push_back(std::string(name));
- is_gc_derived_ = true;
- }
- }
- if (queue.empty())
- break;
- base_record = queue.pop_back_val(); // not actually a queue.
- }
- }
- // 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() || !gc_base_names_.size())
- return false;
- for (const auto& gc_base : gc_base_names_) {
- // If it is not a mixin base we are done.
- if (!Config::IsGCMixinBase(gc_base))
- return false;
- }
- // This is a mixin if all GC bases are mixins.
- return true;
- }
- // Test if a record is allocated on the managed heap.
- bool RecordInfo::IsGCAllocated() {
- return IsGCDerived() || IsHeapAllocatedCollection();
- }
- bool RecordInfo::HasDefinition() {
- return record_->hasDefinition();
- }
- RecordInfo* RecordCache::Lookup(CXXRecordDecl* record) {
- // Ignore classes annotated with the GC_PLUGIN_IGNORE macro.
- if (!record || Config::IsIgnoreAnnotated(record))
- return 0;
- Cache::iterator it = cache_.find(record);
- if (it != cache_.end())
- return &it->second;
- return &cache_.insert(std::make_pair(record, RecordInfo(record, this)))
- .first->second;
- }
- bool RecordInfo::HasTypeAlias(std::string marker_name) const {
- for (Decl* decl : record_->decls()) {
- TypeAliasDecl* alias = dyn_cast<TypeAliasDecl>(decl);
- if (!alias)
- continue;
- if (alias->getName() == marker_name)
- return true;
- }
- return false;
- }
- bool RecordInfo::IsStackAllocated() {
- if (is_stack_allocated_ == kNotComputed) {
- is_stack_allocated_ = kFalse;
- if (HasTypeAlias("IsStackAllocatedTypeMarker")) {
- is_stack_allocated_ = kTrue;
- } else {
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end();
- ++it) {
- if (it->second.info()->IsStackAllocated()) {
- is_stack_allocated_ = kTrue;
- break;
- }
- }
- }
- }
- return is_stack_allocated_;
- }
- bool RecordInfo::IsNonNewable() {
- if (is_non_newable_ == kNotComputed) {
- bool deleted = false;
- bool all_deleted = true;
- for (CXXRecordDecl::method_iterator it = record_->method_begin();
- it != record_->method_end();
- ++it) {
- if (it->getNameAsString() == kNewOperatorName) {
- deleted = it->isDeleted();
- all_deleted = all_deleted && deleted;
- }
- }
- is_non_newable_ = (deleted && all_deleted) ? kTrue : kFalse;
- }
- return is_non_newable_;
- }
- bool RecordInfo::IsOnlyPlacementNewable() {
- if (is_only_placement_newable_ == kNotComputed) {
- bool placement = false;
- bool new_deleted = false;
- for (CXXRecordDecl::method_iterator it = record_->method_begin();
- it != record_->method_end();
- ++it) {
- if (it->getNameAsString() == kNewOperatorName) {
- if (it->getNumParams() == 1) {
- new_deleted = it->isDeleted();
- } else if (it->getNumParams() == 2) {
- placement = !it->isDeleted();
- }
- }
- }
- is_only_placement_newable_ = (placement && new_deleted) ? kTrue : kFalse;
- }
- return is_only_placement_newable_;
- }
- CXXMethodDecl* RecordInfo::DeclaresNewOperator() {
- for (CXXRecordDecl::method_iterator it = record_->method_begin();
- it != record_->method_end();
- ++it) {
- if (it->getNameAsString() == kNewOperatorName && it->getNumParams() == 1)
- return *it;
- }
- return 0;
- }
- // An object requires a tracing method if it has any fields that need tracing
- // or if it inherits from multiple bases that need tracing.
- bool RecordInfo::RequiresTraceMethod() {
- if (IsStackAllocated())
- return false;
- if (GetTraceMethod())
- return true;
- unsigned bases_with_trace = 0;
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
- if (it->second.NeedsTracing().IsNeeded())
- ++bases_with_trace;
- }
- // If a single base has a Trace method, this type can inherit the Trace
- // method from that base. If more than a single base has a Trace method,
- // this type needs it's own Trace method which will delegate to each of
- // the bases' Trace methods.
- if (bases_with_trace > 1)
- return true;
- GetFields();
- return fields_need_tracing_.IsNeeded();
- }
- // Get the actual tracing method (ie, can be traceAfterDispatch if there is a
- // dispatch method).
- CXXMethodDecl* RecordInfo::GetTraceMethod() {
- DetermineTracingMethods();
- return trace_method_;
- }
- // Get the static trace dispatch method.
- CXXMethodDecl* RecordInfo::GetTraceDispatchMethod() {
- DetermineTracingMethods();
- return trace_dispatch_method_;
- }
- CXXMethodDecl* RecordInfo::GetFinalizeDispatchMethod() {
- DetermineTracingMethods();
- return finalize_dispatch_method_;
- }
- const CXXBaseSpecifier* RecordInfo::GetDirectGCBase() {
- if (!IsGCDirectlyDerived())
- return nullptr;
- return directly_derived_gc_base_;
- }
- RecordInfo::Bases& RecordInfo::GetBases() {
- if (!bases_)
- bases_ = CollectBases();
- return *bases_;
- }
- bool RecordInfo::InheritsTrace() {
- if (GetTraceMethod())
- return true;
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
- if (it->second.info()->InheritsTrace())
- return true;
- }
- return false;
- }
- CXXMethodDecl* RecordInfo::InheritsNonVirtualTrace() {
- if (CXXMethodDecl* trace = GetTraceMethod())
- return trace->isVirtual() ? 0 : trace;
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
- if (CXXMethodDecl* trace = it->second.info()->InheritsNonVirtualTrace())
- return trace;
- }
- return 0;
- }
- bool RecordInfo::DeclaresGCMixinMethods() {
- DetermineTracingMethods();
- return has_gc_mixin_methods_;
- }
- bool RecordInfo::DeclaresLocalTraceMethod() {
- if (is_declaring_local_trace_ != kNotComputed)
- return is_declaring_local_trace_;
- DetermineTracingMethods();
- is_declaring_local_trace_ = trace_method_ ? kTrue : kFalse;
- if (is_declaring_local_trace_) {
- for (auto it = record_->method_begin();
- it != record_->method_end(); ++it) {
- if (*it == trace_method_) {
- is_declaring_local_trace_ = kTrue;
- break;
- }
- }
- }
- return is_declaring_local_trace_;
- }
- // A (non-virtual) class is considered abstract in Blink if it has
- // no public constructors and no create methods.
- bool RecordInfo::IsConsideredAbstract() {
- for (CXXRecordDecl::ctor_iterator it = record_->ctor_begin();
- it != record_->ctor_end();
- ++it) {
- if (!it->isCopyOrMoveConstructor() && it->getAccess() == AS_public)
- return false;
- }
- for (CXXRecordDecl::method_iterator it = record_->method_begin();
- it != record_->method_end();
- ++it) {
- if (it->getNameAsString() == kCreateName)
- return false;
- }
- return true;
- }
- RecordInfo::Bases* RecordInfo::CollectBases() {
- // Compute the collection locally to avoid inconsistent states.
- Bases* bases = new Bases;
- if (!record_->hasDefinition())
- return bases;
- for (CXXRecordDecl::base_class_iterator it = record_->bases_begin();
- it != record_->bases_end();
- ++it) {
- const CXXBaseSpecifier& spec = *it;
- RecordInfo* info = cache_->Lookup(spec.getType());
- if (!info)
- continue;
- CXXRecordDecl* base = info->record();
- TracingStatus status = info->InheritsTrace()
- ? TracingStatus::Needed()
- : TracingStatus::Unneeded();
- bases->push_back(std::make_pair(base, BasePoint(spec, info, status)));
- }
- return bases;
- }
- RecordInfo::Fields& RecordInfo::GetFields() {
- if (!fields_)
- fields_ = CollectFields();
- return *fields_;
- }
- RecordInfo::Fields* RecordInfo::CollectFields() {
- // Compute the collection locally to avoid inconsistent states.
- Fields* fields = new Fields;
- if (!record_->hasDefinition())
- return fields;
- TracingStatus fields_status = TracingStatus::Unneeded();
- for (RecordDecl::field_iterator it = record_->field_begin();
- it != record_->field_end();
- ++it) {
- FieldDecl* field = *it;
- // Ignore fields annotated with the GC_PLUGIN_IGNORE macro.
- if (Config::IsIgnoreAnnotated(field))
- continue;
- // Check if the unexpanded type should be recorded; needed
- // to track iterator aliases only
- const Type* unexpandedType = field->getType().getSplitUnqualifiedType().Ty;
- Edge* edge = CreateEdgeFromOriginalType(unexpandedType);
- if (!edge)
- edge = CreateEdge(field->getType().getTypePtrOrNull());
- if (edge) {
- fields_status = fields_status.LUB(edge->NeedsTracing(Edge::kRecursive));
- fields->insert(std::make_pair(field, FieldPoint(field, edge)));
- }
- }
- fields_need_tracing_ = fields_status;
- return fields;
- }
- void RecordInfo::DetermineTracingMethods() {
- if (determined_trace_methods_)
- return;
- determined_trace_methods_ = true;
- if (Config::IsGCBase(name_))
- return;
- CXXMethodDecl* trace = nullptr;
- CXXMethodDecl* trace_after_dispatch = nullptr;
- bool has_adjust_and_mark = false;
- bool has_is_heap_object_alive = false;
- for (Decl* decl : record_->decls()) {
- CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl);
- if (!method) {
- if (FunctionTemplateDecl* func_template =
- dyn_cast<FunctionTemplateDecl>(decl))
- method = dyn_cast<CXXMethodDecl>(func_template->getTemplatedDecl());
- }
- if (!method)
- continue;
- switch (Config::GetTraceMethodType(method)) {
- case Config::TRACE_METHOD:
- trace = method;
- break;
- case Config::TRACE_AFTER_DISPATCH_METHOD:
- trace_after_dispatch = method;
- break;
- case Config::NOT_TRACE_METHOD:
- if (method->getNameAsString() == kFinalizeName) {
- finalize_dispatch_method_ = method;
- } else if (method->getNameAsString() == kAdjustAndMarkName) {
- has_adjust_and_mark = true;
- } else if (method->getNameAsString() == kIsHeapObjectAliveName) {
- has_is_heap_object_alive = true;
- }
- break;
- }
- }
- // Record if class defines the two GCMixin methods.
- has_gc_mixin_methods_ =
- has_adjust_and_mark && has_is_heap_object_alive ? kTrue : kFalse;
- if (trace_after_dispatch) {
- trace_method_ = trace_after_dispatch;
- trace_dispatch_method_ = trace;
- } else {
- // TODO: Can we never have a dispatch method called trace without the same
- // class defining a traceAfterDispatch method?
- trace_method_ = trace;
- trace_dispatch_method_ = nullptr;
- }
- if (trace_dispatch_method_ && finalize_dispatch_method_)
- return;
- // If this class does not define dispatching methods inherit them.
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
- // TODO: Does it make sense to inherit multiple dispatch methods?
- if (CXXMethodDecl* dispatch = it->second.info()->GetTraceDispatchMethod()) {
- assert(!trace_dispatch_method_ && "Multiple trace dispatching methods");
- trace_dispatch_method_ = dispatch;
- }
- if (CXXMethodDecl* dispatch =
- it->second.info()->GetFinalizeDispatchMethod()) {
- assert(!finalize_dispatch_method_ &&
- "Multiple finalize dispatching methods");
- finalize_dispatch_method_ = dispatch;
- }
- }
- }
- // TODO: Add classes with a finalize() method that specialize FinalizerTrait.
- bool RecordInfo::NeedsFinalization() {
- if (does_need_finalization_ == kNotComputed) {
- if (HasOptionalFinalizer()) {
- does_need_finalization_ = kFalse;
- return does_need_finalization_;
- }
- // Rely on hasNonTrivialDestructor(), but if the only
- // identifiable reason for it being true is the presence
- // of a safely ignorable class as a direct base,
- // or we're processing such an 'ignorable' class, then it does
- // not need finalization.
- does_need_finalization_ =
- record_->hasNonTrivialDestructor() ? kTrue : kFalse;
- if (!does_need_finalization_)
- return does_need_finalization_;
- CXXDestructorDecl* dtor = record_->getDestructor();
- if (dtor && dtor->isUserProvided())
- return does_need_finalization_;
- for (Fields::iterator it = GetFields().begin();
- it != GetFields().end();
- ++it) {
- if (it->second.edge()->NeedsFinalization())
- return does_need_finalization_;
- }
- for (Bases::iterator it = GetBases().begin();
- it != GetBases().end();
- ++it) {
- if (it->second.info()->NeedsFinalization())
- return does_need_finalization_;
- }
- // Destructor was non-trivial due to bases with destructors that
- // can be safely ignored. Hence, no need for finalization.
- does_need_finalization_ = kFalse;
- }
- return does_need_finalization_;
- }
- // A class needs tracing if:
- // - it is allocated on the managed heap,
- // - it has a Trace method (i.e. the plugin assumes such a method was added for
- // a reason).
- // - it is derived from a class that needs tracing, or
- // - it contains fields that need tracing.
- //
- TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) {
- if (IsGCAllocated())
- return TracingStatus::Needed();
- if (IsStackAllocated())
- return TracingStatus::Unneeded();
- if (GetTraceMethod())
- return TracingStatus::Needed();
- for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
- if (it->second.info()->NeedsTracing(option).IsNeeded())
- return TracingStatus::Needed();
- }
- if (option == Edge::kRecursive)
- GetFields();
- return fields_need_tracing_;
- }
- static bool isInStdNamespace(clang::Sema& sema, NamespaceDecl* ns)
- {
- while (ns) {
- if (sema.getStdNamespace()->InEnclosingNamespaceSetOf(ns))
- return true;
- ns = dyn_cast<NamespaceDecl>(ns->getParent());
- }
- return false;
- }
- Edge* RecordInfo::CreateEdgeFromOriginalType(const Type* type) {
- if (!type)
- return nullptr;
- // look for "typedef ... iterator;"
- if (!isa<ElaboratedType>(type))
- return nullptr;
- const ElaboratedType* elaboratedType = cast<ElaboratedType>(type);
- if (!isa<TypedefType>(elaboratedType->getNamedType()))
- return nullptr;
- const TypedefType* typedefType =
- cast<TypedefType>(elaboratedType->getNamedType());
- std::string typeName = typedefType->getDecl()->getNameAsString();
- if (!Config::IsIterator(typeName))
- return nullptr;
- RecordInfo* info =
- cache_->Lookup(elaboratedType->getQualifier()->getAsType());
- bool on_heap = false;
- // Silently handle unknown types; the on-heap collection types will
- // have to be in scope for the declaration to compile, though.
- if (info) {
- on_heap = Config::IsGCCollection(info->name());
- }
- return new Iterator(info, on_heap);
- }
- Edge* RecordInfo::CreateEdge(const Type* type) {
- if (!type) {
- return 0;
- }
- if (type->isPointerType() || type->isReferenceType()) {
- if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull()))
- return new RawPtr(ptr, type->isReferenceType());
- return 0;
- }
- RecordInfo* info = cache_->Lookup(type);
- // If the type is neither a pointer or a C++ record we ignore it.
- if (!info) {
- return 0;
- }
- TemplateArgs args;
- if (Config::IsRefOrWeakPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
- if (Edge* ptr = CreateEdge(args[0]))
- return new RefPtr(
- ptr, Config::IsRefPtr(info->name()) ? Edge::kStrong : Edge::kWeak);
- return 0;
- }
- if (Config::IsUniquePtr(info->name()) && info->GetTemplateArgs(1, &args)) {
- // Check that this is std::unique_ptr
- NamespaceDecl* ns =
- dyn_cast<NamespaceDecl>(info->record()->getDeclContext());
- clang::Sema& sema = cache_->instance().getSema();
- if (!isInStdNamespace(sema, ns))
- return 0;
- if (Edge* ptr = CreateEdge(args[0]))
- return new UniquePtr(ptr);
- return 0;
- }
- // Find top-level namespace.
- NamespaceDecl* ns = dyn_cast<NamespaceDecl>(info->record()->getDeclContext());
- if (ns) {
- while (NamespaceDecl* outer_ns =
- dyn_cast<NamespaceDecl>(ns->getDeclContext())) {
- ns = outer_ns;
- }
- }
- auto ns_name = ns ? ns->getName() : "";
- if (Config::IsMember(info->name(), ns_name, info, &args)) {
- if (Edge* ptr = CreateEdge(args[0])) {
- return new Member(ptr);
- }
- return 0;
- }
- if (Config::IsWeakMember(info->name(), ns_name, info, &args)) {
- if (Edge* ptr = CreateEdge(args[0]))
- return new WeakMember(ptr);
- return 0;
- }
- bool is_persistent = Config::IsPersistent(info->name(), ns_name, info, &args);
- if (is_persistent ||
- Config::IsCrossThreadPersistent(info->name(), ns_name, info, &args)) {
- if (Edge* ptr = CreateEdge(args[0])) {
- if (is_persistent)
- return new Persistent(ptr);
- else
- return new CrossThreadPersistent(ptr);
- }
- return 0;
- }
- if (Config::IsGCCollection(info->name()) ||
- Config::IsWTFCollection(info->name())) {
- bool on_heap = info->IsHeapAllocatedCollection();
- size_t count = Config::CollectionDimension(info->name());
- if (!info->GetTemplateArgs(count, &args))
- return 0;
- Collection* edge = new Collection(info, on_heap);
- for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) {
- if (Edge* member = CreateEdge(*it)) {
- edge->members().push_back(member);
- }
- // TODO: Handle the case where we fail to create an edge (eg, if the
- // argument is a primitive type or just not fully known yet).
- }
- return edge;
- }
- if (Config::IsTraceWrapperV8Reference(info->name(), ns_name, info, &args)) {
- if (Edge* ptr = CreateEdge(args[0]))
- return new TraceWrapperV8Reference(ptr);
- return 0;
- }
- return new Value(info);
- }
|