Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Unified Diff: tools/clang/plugins/ChromeClassTester.cpp

Issue 6368055: Commit my clang plugin and fix up documentation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add makefile for thakis Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/clang/plugins/ChromeClassTester.cpp
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..106f16ec0bbaf6b3e2d4698cb824a185d922a349
--- /dev/null
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -0,0 +1,208 @@
+// Copyright (c) 2011 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.
+
+// A general interface for filtering and only acting on classes in Chromium C++
+// code.
+
+#include "ChromeClassTester.h"
+
+#include "clang/Basic/FileManager.h"
+
+using namespace clang;
+
+namespace {
+
+bool starts_with(const std::string& one, const std::string& two) {
+ return one.substr(0, two.size()) == two;
+}
+
+bool ends_with(const std::string& one, const std::string& two) {
+ return one.substr(one.size() - two.size(), two.size()) == two;
+}
+
+} // namespace
+
+ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
+ : instance_(instance),
+ diagnostic_(instance.getDiagnostics()) {
+ banned_namespaces_.push_back("std");
+ banned_namespaces_.push_back("__gnu_cxx");
+
+ banned_directories_.push_back("third_party");
+ banned_directories_.push_back("native_client");
+ banned_directories_.push_back("breakpad");
+ banned_directories_.push_back("courgette");
+ banned_directories_.push_back("ppapi");
+ banned_directories_.push_back("/usr");
+ banned_directories_.push_back("testing");
+ banned_directories_.push_back("googleurl");
+ banned_directories_.push_back("v8");
+ banned_directories_.push_back("sdch");
+
+ // You are standing in a mazy of twisty dependencies, all resolved by
+ // putting everything in the header.
+ banned_directories_.push_back("chrome/test/automation");
+
+ // Used in really low level threading code that probably shouldn't be out of
+ // lined.
+ ignored_record_names_.push_back("ThreadLocalBoolean");
+
+ // A complicated pickle derived struct that is all packed integers.
+ ignored_record_names_.push_back("Header");
+
+ // Part of the GPU system that uses multiple included header
+ // weirdness. Never getting this right.
+ ignored_record_names_.push_back("Validators");
+
+ // RAII class that's simple enough (media/base/callback.h).
+ ignored_record_names_.push_back("AutoTaskRunner");
+ ignored_record_names_.push_back("AutoCallbackRunner");
+
+ // Part of our public interface that nacl and friends use. (Arguably, this
+ // should mean that this is a higher priority but fixing this looks hard.)
+ ignored_record_names_.push_back("PluginVersionInfo");
+}
+
+ChromeClassTester::~ChromeClassTester() {}
+
+void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
+ if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
+ // If this is a POD or a class template or a type dependent on a
+ // templated class, assume there's no ctor/dtor/virtual method
+ // optimization that we can do.
+ if (record->isPOD() ||
+ record->getDescribedClassTemplate() ||
+ record->getTemplateSpecializationKind() ||
+ record->isDependentType())
+ return;
+
+ if (InBannedNamespace(record))
+ return;
+
+ SourceLocation record_location = record->getInnerLocStart();
+ if (InBannedDirectory(record_location))
+ return;
+
+ // For now, due to large amounts of inlining in our unit test code, there's
+ // no way in hell we'll pass our checks but we want to deploy clang plugins
+ // now.
+ //
+ // TODO(erg): Deinline all our test code, and only perform something like
+ // this check for the "virtual" inlining tests on GMOCK code (since all of
+ // that is autogenerated and doesn't specify the "virtual" keyword).
+ if (IsTestCode(record)) {
+ return;
+ }
+
+ // We sadly need to maintain a blacklist of types that violate these
+ // rules, but do so for good reason or due to limitations of this
+ // checker (i.e., we don't handle extern templates very well).
+ if (IsIgnoredType(record))
+ return;
+
+ CheckChromeClass(record_location, record);
+ }
+}
+
+void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
+ FullSourceLoc full(loc, instance().getSourceManager());
+ std::string err;
+ err = "[chrome-style] ";
+ err += raw_error;
+ unsigned id = diagnostic().getCustomDiagID(Diagnostic::Warning, err);
+ DiagnosticBuilder B = diagnostic().Report(full, id);
+}
+
+bool ChromeClassTester::IsTestCode(Decl* record) {
+ if (instance_.hasSourceManager()) {
+ SourceManager& m = instance_.getSourceManager();
+ std::string name = m.getFileEntryForID(m.getMainFileID())->getName();
+ return name.find("test") != name.npos ||
+ name.find("mock") != name.npos;
+ }
+ return false;
+}
+
+bool ChromeClassTester::InBannedNamespace(Decl* record) {
+ std::string n = GetNamespace(record);
+ if (n != "") {
+ return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
+ != banned_namespaces_.end();
+ }
+
+ return false;
+}
+
+std::string ChromeClassTester::GetNamespace(Decl* record) {
+ return GetNamespaceImpl(record->getDeclContext(), "");
+}
+
+std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
+ std::string candidate) {
+ switch (context->getDeclKind()) {
+ case Decl::TranslationUnit: {
+ return candidate;
+ }
+ case Decl::Namespace: {
+ const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
+ std::string name_str;
+ llvm::raw_string_ostream OS(name_str);
+ if (decl->isAnonymousNamespace())
+ OS << "<anonymous namespace>";
+ else
+ OS << decl;
+ return GetNamespaceImpl(context->getParent(),
+ OS.str());
+ }
+ default: {
+ return GetNamespaceImpl(context->getParent(), candidate);
+ }
+ }
+}
+
+bool ChromeClassTester::InBannedDirectory(const SourceLocation& loc) {
+ if (loc.isFileID() && loc.isValid()) {
+ bool invalid = false;
+ const char* buffer_name = instance_.getSourceManager().getBufferName(
+ loc, &invalid);
+ if (!invalid && buffer_name) {
+ std::string b(buffer_name);
+
+ // Don't complain about these things in implementation files.
+ if (ends_with(b, ".cc") || ends_with(b, ".cpp")) {
+ return true;
+ }
+
+ // Don't complain about autogenerated protobuf files.
+ if (ends_with(b, ".pb.h")) {
+ return true;
+ }
+
+ // Strip preceding path crap.
+ if (starts_with(b, "./"))
+ b = b.substr(2);
+
+ for (std::vector<std::string>::const_iterator it =
+ banned_directories_.begin();
+ it != banned_directories_.end(); ++it) {
+ if (starts_with(b, *it))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ChromeClassTester::IsIgnoredType(RecordDecl* record) {
+ std::string base_name = record->getNameAsString();
+ for (std::vector<std::string>::const_iterator it =
+ ignored_record_names_.begin();
+ it != ignored_record_names_.end(); ++it) {
+ if (base_name == *it)
+ return true;
+ }
+
+ return false;
+}

Powered by Google App Engine
This is Rietveld 408576698