Index: tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp |
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0ed953fccf92e57197fcb7cc54a99bff36b8a675 |
--- /dev/null |
+++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp |
@@ -0,0 +1,152 @@ |
+// Copyright 2015 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 "CheckFieldsVisitor.h" |
+ |
+#include <cassert> |
+ |
+#include "BlinkGCPluginOptions.h" |
+#include "RecordInfo.h" |
+ |
+CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options) |
+ : options_(options), |
+ current_(0), |
+ stack_allocated_host_(false) { |
+} |
+ |
+CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() { |
+ return invalid_fields_; |
+} |
+ |
+bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) { |
+ stack_allocated_host_ = info->IsStackAllocated(); |
+ managed_host_ = stack_allocated_host_ || |
+ info->IsGCAllocated() || |
+ info->IsNonNewable() || |
+ info->IsOnlyPlacementNewable(); |
+ for (RecordInfo::Fields::iterator it = info->GetFields().begin(); |
+ it != info->GetFields().end(); |
+ ++it) { |
+ context().clear(); |
+ current_ = &it->second; |
+ current_->edge()->Accept(this); |
+ } |
+ return !invalid_fields_.empty(); |
+} |
+ |
+void CheckFieldsVisitor::AtMember(Member* edge) { |
+ if (managed_host_) |
+ return; |
+ // A member is allowed to appear in the context of a root. |
+ for (Context::iterator it = context().begin(); |
+ it != context().end(); |
+ ++it) { |
+ if ((*it)->Kind() == Edge::kRoot) |
+ return; |
+ } |
+ invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged)); |
+} |
+ |
+void CheckFieldsVisitor::AtValue(Value* edge) { |
+ // TODO: what should we do to check unions? |
+ if (edge->value()->record()->isUnion()) |
+ return; |
+ |
+ if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) { |
+ invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack)); |
+ return; |
+ } |
+ |
+ if (!Parent() && |
+ edge->value()->IsGCDerived() && |
+ !edge->value()->IsGCMixin()) { |
+ invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject)); |
+ return; |
+ } |
+ |
+ // If in a stack allocated context, be fairly insistent that T in Member<T> |
+ // is GC allocated, as stack allocated objects do not have a trace() |
+ // that separately verifies the validity of Member<T>. |
+ // |
+ // Notice that an error is only reported if T's definition is in scope; |
+ // we do not require that it must be brought into scope as that would |
+ // prevent declarations of mutually dependent class types. |
+ // |
+ // (Note: Member<>'s constructor will at run-time verify that the |
+ // pointer it wraps is indeed heap allocated.) |
+ if (stack_allocated_host_ && Parent() && Parent()->IsMember() && |
+ edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) { |
+ invalid_fields_.push_back(std::make_pair(current_, |
+ kMemberToGCUnmanaged)); |
+ return; |
+ } |
+ |
+ if (!Parent() || !edge->value()->IsGCAllocated()) |
+ return; |
+ |
+ // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's, |
+ // also disallow T* in stack-allocated types. |
+ if (options_.enable_oilpan) { |
+ if (Parent()->IsOwnPtr() || |
+ Parent()->IsRawPtrClass() || |
+ (stack_allocated_host_ && Parent()->IsRawPtr())) { |
+ invalid_fields_.push_back(std::make_pair( |
+ current_, InvalidSmartPtr(Parent()))); |
+ return; |
+ } |
+ if (options_.warn_raw_ptr && Parent()->IsRawPtr()) { |
+ if (static_cast<RawPtr*>(Parent())->HasReferenceType()) { |
+ invalid_fields_.push_back(std::make_pair( |
+ current_, kReferencePtrToGCManagedWarning)); |
+ } else { |
+ invalid_fields_.push_back(std::make_pair( |
+ current_, kRawPtrToGCManagedWarning)); |
+ } |
+ } |
+ return; |
+ } |
+ |
+ if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) { |
+ invalid_fields_.push_back(std::make_pair( |
+ current_, InvalidSmartPtr(Parent()))); |
+ return; |
+ } |
+} |
+ |
+void CheckFieldsVisitor::AtCollection(Collection* edge) { |
+ if (edge->on_heap() && Parent() && Parent()->IsOwnPtr()) |
+ invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged)); |
+} |
+ |
+bool CheckFieldsVisitor::IsWarning(Error error) { |
+ if (error == kRawPtrToGCManagedWarning) |
+ return true; |
+ if (error == kReferencePtrToGCManagedWarning) |
+ return true; |
+ return false; |
+} |
+ |
+bool CheckFieldsVisitor::IsRawPtrError(Error error) { |
+ return (error == kRawPtrToGCManaged || |
+ error == kRawPtrToGCManagedWarning); |
+} |
+ |
+bool CheckFieldsVisitor::IsReferencePtrError(Error error) { |
+ return (error == kReferencePtrToGCManaged || |
+ error == kReferencePtrToGCManagedWarning); |
+} |
+ |
+CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) { |
+ if (ptr->IsRawPtr()) { |
+ if (static_cast<RawPtr*>(ptr)->HasReferenceType()) |
+ return kReferencePtrToGCManaged; |
+ else |
+ return kRawPtrToGCManaged; |
+ } |
+ if (ptr->IsRefPtr()) |
+ return kRefPtrToGCManaged; |
+ if (ptr->IsOwnPtr()) |
+ return kOwnPtrToGCManaged; |
+ assert(false && "Unknown smart pointer kind"); |
+} |