| 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..6f0a34dd6e846aac5b1aee1c77de7d33ed670cc9
|
| --- /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 (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;
|
| +}
|
|
|