Index: tools/clang/blink_gc_plugin/CheckSingletonVisitor.cpp |
diff --git a/tools/clang/blink_gc_plugin/CheckSingletonVisitor.cpp b/tools/clang/blink_gc_plugin/CheckSingletonVisitor.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c3bc43e615a0ec3884a30c3a35886167565cabcd |
--- /dev/null |
+++ b/tools/clang/blink_gc_plugin/CheckSingletonVisitor.cpp |
@@ -0,0 +1,150 @@ |
+// Copyright 2017 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 "CheckSingletonVisitor.h" |
+ |
+#include "BlinkGCPluginOptions.h" |
+#include "Config.h" |
+#include "RecordInfo.h" |
+ |
+using namespace clang; |
+ |
+CheckSingletonVisitor::CheckSingletonVisitor() = default; |
+ |
+CheckSingletonVisitor::~CheckSingletonVisitor() = default; |
+ |
+bool CheckSingletonVisitor::IsScriptWrappable(RecordInfo* info) { |
+ return Config::IsScriptWrappable(info->name()) && info->IsInBlinkNamespace(); |
+} |
+ |
+bool CheckSingletonVisitor::InheritsScriptWrappable(CXXRecordDecl* record) { |
+ RecordInfo* info = info_->cache()->Lookup(record); |
+ if (!info) |
+ return false; |
+ |
+ if (IsScriptWrappable(info)) |
+ return true; |
+ |
+ for (auto& base : info->GetBases()) |
+ if (InheritsScriptWrappable(base.first)) |
+ return true; |
+ |
+ return false; |
+} |
+ |
+void CheckSingletonVisitor::CheckScriptWrappable(const std::string& name, |
+ const Type* type) { |
+ RecordInfo* info = info_->cache()->Lookup(type); |
+ if (!info) |
+ return; |
+ |
+ if (IsScriptWrappable(info)) { |
+ std::string context = GenerateErrorContext(name); |
+ illegal_types_.push_back(std::make_pair(context, type)); |
+ return; |
+ } |
+ |
+ RecordInfo::TemplateArgs args; |
+ if (Config::IsMember(info->name()) && info->GetTemplateArgs(1, &args)) { |
+ PushType(name, args[0]); |
+ return; |
+ } |
+ if (Config::IsWeakMember(info->name()) && info->GetTemplateArgs(1, &args)) { |
+ PushType(name, args[0]); |
+ return; |
+ } |
+ bool has_persistent_name = false; |
+ if (const Type* arg_type = |
+ info->GetPersistentArgumentType(has_persistent_name)) { |
+ PushType(name, arg_type); |
+ return; |
+ } |
+ if (Config::IsGCCollection(info->name()) || |
+ Config::IsWTFCollection(info->name())) { |
+ if (Config::IsPersistentGCCollection(info->name()) || |
+ info->IsHeapAllocatedCollection()) { |
+ size_t count = Config::CollectionDimension(info->name()); |
+ if (info->GetTemplateArgs(count, &args)) { |
+ for (const auto& t : args) |
+ PushType(name, t); |
+ return; |
+ } |
+ } |
+ } |
+ |
+ // First check if the class inherits |blink::ScriptWrappable|, |
+ // and fail early if so. |
+ if (InheritsScriptWrappable(info->record())) { |
+ std::string context = GenerateErrorContext(name); |
+ illegal_types_.push_back(std::make_pair(context, type)); |
+ return; |
+ } |
+ for (auto& base : info->GetBases()) { |
+ PushType(name, base.first->getTypeForDecl()); |
+ } |
+ for (auto& field : info->GetFields()) { |
+ CheckScriptWrappable(field.first->getNameAsString(), |
+ field.first->getType().getTypePtr()); |
+ } |
+} |
+ |
+void CheckSingletonVisitor::PushType(const Type* type) { |
+ if (type->isPointerType() || type->isReferenceType()) |
+ return; |
+ |
+ if (already_seen_.find(type) != already_seen_.end()) |
+ return; |
+ |
+ already_seen_.insert(type); |
+ types_stack_.push_back(std::make_pair("", type)); |
+} |
+ |
+void CheckSingletonVisitor::PushType(const std::string& name, |
+ const Type* type) { |
+ if (type->isPointerType() || type->isReferenceType()) |
+ return; |
+ |
+ if (already_seen_.find(type) != already_seen_.end()) |
+ return; |
+ |
+ already_seen_.insert(type); |
+ types_stack_.push_back(std::make_pair(name, type)); |
+} |
+ |
+bool CheckSingletonVisitor::CheckIfSafe(RecordInfo* info, const Type* type) { |
+ info_ = info; |
+ types_stack_.push_back(std::make_pair("", type)); |
+ while (types_stack_.size()) { |
+ auto t = types_stack_.back(); |
+ types_stack_.pop_back(); |
+ if (!t.second) { |
+ // We push a stack marker when extending the |
+ // (field) error context - pop the context when |
+ // it is encountered again. |
+ error_context_.pop_back(); |
+ continue; |
+ } else if (!t.first.empty()) { |
+ error_context_.push_back(t.first); |
+ types_stack_.push_back(std::make_pair(t.first, nullptr)); |
+ } |
+ CheckScriptWrappable("", t.second); |
+ } |
+ return !illegal_types_.size(); |
+} |
+ |
+std::string CheckSingletonVisitor::GenerateErrorContext( |
+ const std::string& name) { |
+ std::string result; |
+ for (const auto& elem : error_context_) { |
+ if (!result.empty()) |
+ result.append(" => "); |
+ result.append(elem); |
+ } |
+ if (!name.empty()) { |
+ if (!result.empty()) |
+ result.append(" => "); |
+ result.append(name); |
+ } |
+ return result; |
+} |