summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/tools/clang/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/tools/clang/plugins')
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.cpp294
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.h84
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/FindBadConstructs.cpp435
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/Makefile19
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/OWNERS1
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/README.chromium4
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.cpp72
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.h121
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.txt23
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.cpp5
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.h12
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.txt5
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.cpp25
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.h21
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.txt8
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.cpp23
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.h19
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.txt6
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.cpp5
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.h22
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.txt8
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.cpp38
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.h54
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.txt20
-rwxr-xr-xthird_party/libwebrtc/tools/clang/plugins/tests/test.sh72
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.cpp36
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.h39
-rw-r--r--third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.txt8
28 files changed, 1479 insertions, 0 deletions
diff --git a/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.cpp b/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.cpp
new file mode 100644
index 0000000000..055866c5c5
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.cpp
@@ -0,0 +1,294 @@
+// Copyright (c) 2012 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 <sys/param.h>
+
+#include "clang/AST/AST.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+
+namespace {
+
+bool starts_with(const std::string& one, const std::string& two) {
+ return one.compare(0, two.size(), two) == 0;
+}
+
+std::string lstrip(const std::string& one, const std::string& two) {
+ if (starts_with(one, two))
+ return one.substr(two.size());
+ return one;
+}
+
+bool ends_with(const std::string& one, const std::string& two) {
+ if (two.size() > one.size())
+ return false;
+
+ return one.compare(one.size() - two.size(), two.size(), two) == 0;
+}
+
+} // namespace
+
+ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
+ : instance_(instance),
+ diagnostic_(instance.getDiagnostics()) {
+ BuildBannedLists();
+}
+
+ChromeClassTester::~ChromeClassTester() {}
+
+void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
+ pending_class_decls_.push_back(tag);
+}
+
+bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) {
+ for (size_t i = 0; i < pending_class_decls_.size(); ++i)
+ CheckTag(pending_class_decls_[i]);
+ pending_class_decls_.clear();
+
+ return true; // true means continue parsing.
+}
+
+void ChromeClassTester::CheckTag(TagDecl* tag) {
+ // We handle class types here where we have semantic information. We can only
+ // check structs/classes/enums here, but we get a bunch of nice semantic
+ // information instead of just parsing information.
+
+ 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;
+
+ // 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).
+ std::string base_name = record->getNameAsString();
+ if (IsIgnoredType(base_name))
+ return;
+
+ // We ignore all classes that end with "Matcher" because they're probably
+ // GMock artifacts.
+ if (ends_with(base_name, "Matcher"))
+ return;
+
+ CheckChromeClass(record_location, record);
+ }
+}
+
+void ChromeClassTester::emitWarning(SourceLocation loc,
+ const char* raw_error) {
+ FullSourceLoc full(loc, instance().getSourceManager());
+ std::string err;
+ err = "[chromium-style] ";
+ err += raw_error;
+ DiagnosticsEngine::Level level =
+ diagnostic().getWarningsAsErrors() ?
+ DiagnosticsEngine::Error :
+ DiagnosticsEngine::Warning;
+ unsigned id = diagnostic().getCustomDiagID(level, err);
+ DiagnosticBuilder builder = diagnostic().Report(full, id);
+}
+
+bool ChromeClassTester::InBannedNamespace(const Decl* record) {
+ std::string n = GetNamespace(record);
+ if (!n.empty()) {
+ return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
+ != banned_namespaces_.end();
+ }
+
+ return false;
+}
+
+std::string ChromeClassTester::GetNamespace(const Decl* record) {
+ return GetNamespaceImpl(record->getDeclContext(), "");
+}
+
+bool ChromeClassTester::InImplementationFile(SourceLocation record_location) {
+ std::string filename;
+ if (!GetFilename(record_location, &filename))
+ return false;
+
+ if (ends_with(filename, ".cc") || ends_with(filename, ".cpp") ||
+ ends_with(filename, ".mm")) {
+ return true;
+ }
+
+ return false;
+}
+
+void ChromeClassTester::BuildBannedLists() {
+ banned_namespaces_.push_back("std");
+ banned_namespaces_.push_back("__gnu_cxx");
+ banned_namespaces_.push_back("WebKit");
+
+ 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("pdf/");
+ 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("dart/");
+ banned_directories_.push_back("sdch/");
+ banned_directories_.push_back("icu4c/");
+ banned_directories_.push_back("frameworks/");
+
+ // Don't check autogenerated headers.
+ // Make puts them below $(builddir_name)/.../gen and geni.
+ // Ninja puts them below OUTPUT_DIR/.../gen
+ // Xcode has a fixed output directory for everything.
+ banned_directories_.push_back("gen/");
+ banned_directories_.push_back("geni/");
+ banned_directories_.push_back("xcodebuild/");
+
+ // You are standing in a mazy of twisty dependencies, all resolved by
+ // putting everything in the header.
+ banned_directories_.push_back("automation/");
+
+ // Don't check system headers.
+ banned_directories_.push_back("/Developer/");
+
+ // Used in really low level threading code that probably shouldn't be out of
+ // lined.
+ ignored_record_names_.insert("ThreadLocalBoolean");
+
+ // A complicated pickle derived struct that is all packed integers.
+ ignored_record_names_.insert("Header");
+
+ // Part of the GPU system that uses multiple included header
+ // weirdness. Never getting this right.
+ ignored_record_names_.insert("Validators");
+
+ // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
+ ignored_record_names_.insert("AutocompleteController");
+ ignored_record_names_.insert("HistoryURLProvider");
+
+ // Because of chrome frame
+ ignored_record_names_.insert("ReliabilityTestSuite");
+
+ // Used over in the net unittests. A large enough bundle of integers with 1
+ // non-pod class member. Probably harmless.
+ ignored_record_names_.insert("MockTransaction");
+
+ // Used heavily in ui_unittests and once in views_unittests. Fixing this
+ // isn't worth the overhead of an additional library.
+ ignored_record_names_.insert("TestAnimationDelegate");
+
+ // 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_.insert("PluginVersionInfo");
+}
+
+std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
+ const 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(SourceLocation loc) {
+ std::string filename;
+ if (!GetFilename(loc, &filename)) {
+ // If the filename cannot be determined, simply treat this as a banned
+ // location, instead of going through the full lookup process.
+ return true;
+ }
+
+ // We need to special case scratch space; which is where clang does its
+ // macro expansion. We explicitly want to allow people to do otherwise bad
+ // things through macros that were defined due to third party libraries.
+ if (filename == "<scratch space>")
+ return true;
+
+ // Don't complain about autogenerated protobuf files.
+ if (ends_with(filename, ".pb.h")) {
+ return true;
+ }
+
+ // We need to munge the paths so that they are relative to the repository
+ // srcroot. We first resolve the symlinktastic relative path and then
+ // remove our known srcroot from it if needed.
+ char resolvedPath[MAXPATHLEN];
+ if (realpath(filename.c_str(), resolvedPath)) {
+ filename = resolvedPath;
+ }
+
+ // On linux, chrome is often checked out to /usr/local/google. Due to the
+ // "usr" rule in banned_directories_, all diagnostics would be suppressed
+ // in that case. As a workaround, strip that prefix.
+ filename = lstrip(filename, "/usr/local/google");
+
+ for (std::vector<std::string>::const_iterator it =
+ banned_directories_.begin();
+ it != banned_directories_.end(); ++it) {
+ // If we can find any of the banned path components in this path, then
+ // this file is rejected.
+ size_t index = filename.find(*it);
+ if (index != std::string::npos) {
+ bool matches_full_dir_name = index == 0 || filename[index - 1] == '/';
+ if ((*it)[0] == '/')
+ matches_full_dir_name = true;
+ if (matches_full_dir_name)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
+ return ignored_record_names_.find(base_name) != ignored_record_names_.end();
+}
+
+bool ChromeClassTester::GetFilename(SourceLocation loc,
+ std::string* filename) {
+ const SourceManager& source_manager = instance_.getSourceManager();
+ SourceLocation spelling_location = source_manager.getSpellingLoc(loc);
+ PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
+ if (ploc.isInvalid()) {
+ // If we're in an invalid location, we're looking at things that aren't
+ // actually stated in the source.
+ return false;
+ }
+
+ *filename = ploc.getFilename();
+ return true;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.h b/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.h
new file mode 100644
index 0000000000..588ae9cae5
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/ChromeClassTester.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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.
+
+#ifndef TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_
+#define TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_
+
+#include <set>
+#include <vector>
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+// A class on top of ASTConsumer that forwards classes defined in Chromium
+// headers to subclasses which implement CheckChromeClass().
+class ChromeClassTester : public clang::ASTConsumer {
+ public:
+ explicit ChromeClassTester(clang::CompilerInstance& instance);
+ virtual ~ChromeClassTester();
+
+ // clang::ASTConsumer:
+ virtual void HandleTagDeclDefinition(clang::TagDecl* tag);
+ virtual bool HandleTopLevelDecl(clang::DeclGroupRef group_ref);
+
+ protected:
+ clang::CompilerInstance& instance() { return instance_; }
+ clang::DiagnosticsEngine& diagnostic() { return diagnostic_; }
+
+ // Emits a simple warning; this shouldn't be used if you require printf-style
+ // printing.
+ void emitWarning(clang::SourceLocation loc, const char* error);
+
+ // Utility method for subclasses to check if this class is in a banned
+ // namespace.
+ bool InBannedNamespace(const clang::Decl* record);
+
+ // Utility method for subclasses to determine the namespace of the
+ // specified record, if any. Unnamed namespaces will be identified as
+ // "<anonymous namespace>".
+ std::string GetNamespace(const clang::Decl* record);
+
+ // Utility method for subclasses to check if this class is within an
+ // implementation (.cc, .cpp, .mm) file.
+ bool InImplementationFile(clang::SourceLocation location);
+
+ private:
+ void BuildBannedLists();
+
+ void CheckTag(clang::TagDecl*);
+
+ // Filtered versions of tags that are only called with things defined in
+ // chrome header files.
+ virtual void CheckChromeClass(clang::SourceLocation record_location,
+ clang::CXXRecordDecl* record) = 0;
+
+ // Utility methods used for filtering out non-chrome classes (and ones we
+ // deliberately ignore) in HandleTagDeclDefinition().
+ std::string GetNamespaceImpl(const clang::DeclContext* context,
+ const std::string& candidate);
+ bool InBannedDirectory(clang::SourceLocation loc);
+ bool IsIgnoredType(const std::string& base_name);
+
+ // Attempts to determine the filename for the given SourceLocation.
+ // Returns false if the filename could not be determined.
+ bool GetFilename(clang::SourceLocation loc, std::string* filename);
+
+ clang::CompilerInstance& instance_;
+ clang::DiagnosticsEngine& diagnostic_;
+
+ // List of banned namespaces.
+ std::vector<std::string> banned_namespaces_;
+
+ // List of banned directories.
+ std::vector<std::string> banned_directories_;
+
+ // List of types that we don't check.
+ std::set<std::string> ignored_record_names_;
+
+ // List of decls to check once the current top-level decl is parsed.
+ std::vector<clang::TagDecl*> pending_class_decls_;
+};
+
+#endif // TOOLS_CLANG_PLUGINS_CHROMECLASSTESTER_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/FindBadConstructs.cpp b/third_party/libwebrtc/tools/clang/plugins/FindBadConstructs.cpp
new file mode 100644
index 0000000000..b79a64dbd1
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/FindBadConstructs.cpp
@@ -0,0 +1,435 @@
+// Copyright (c) 2012 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.
+
+// This file defines a bunch of recurring problems in the Chromium C++ code.
+//
+// Checks that are implemented:
+// - Constructors/Destructors should not be inlined if they are of a complex
+// class type.
+// - Missing "virtual" keywords on methods that should be virtual.
+// - Non-annotated overriding virtual methods.
+// - Virtual methods with nonempty implementations in their headers.
+// - Classes that derive from base::RefCounted / base::RefCountedThreadSafe
+// should have protected or private destructors.
+
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "ChromeClassTester.h"
+
+using namespace clang;
+
+namespace {
+
+bool TypeHasNonTrivialDtor(const Type* type) {
+ if (const CXXRecordDecl* cxx_r = type->getCXXRecordDeclForPointerType())
+ return cxx_r->hasTrivialDestructor();
+
+ return false;
+}
+
+// Returns the underlying Type for |type| by expanding typedefs and removing
+// any namespace qualifiers.
+const Type* UnwrapType(const Type* type) {
+ if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type))
+ return UnwrapType(elaborated->getNamedType().getTypePtr());
+ if (const TypedefType* typedefed = dyn_cast<TypedefType>(type))
+ return UnwrapType(typedefed->desugar().getTypePtr());
+ return type;
+}
+
+// Searches for constructs that we know we don't want in the Chromium code base.
+class FindBadConstructsConsumer : public ChromeClassTester {
+ public:
+ FindBadConstructsConsumer(CompilerInstance& instance,
+ bool check_refcounted_dtors,
+ bool check_virtuals_in_implementations)
+ : ChromeClassTester(instance),
+ check_refcounted_dtors_(check_refcounted_dtors),
+ check_virtuals_in_implementations_(check_virtuals_in_implementations) {
+ }
+
+ virtual void CheckChromeClass(SourceLocation record_location,
+ CXXRecordDecl* record) {
+ bool implementation_file = InImplementationFile(record_location);
+
+ if (!implementation_file) {
+ // Only check for "heavy" constructors/destructors in header files;
+ // within implementation files, there is no performance cost.
+ CheckCtorDtorWeight(record_location, record);
+ }
+
+ if (!implementation_file || check_virtuals_in_implementations_) {
+ bool warn_on_inline_bodies = !implementation_file;
+
+ // Check that all virtual methods are marked accordingly with both
+ // virtual and OVERRIDE.
+ CheckVirtualMethods(record_location, record, warn_on_inline_bodies);
+ }
+
+ if (check_refcounted_dtors_)
+ CheckRefCountedDtors(record_location, record);
+ }
+
+ private:
+ bool check_refcounted_dtors_;
+ bool check_virtuals_in_implementations_;
+
+ // Returns true if |base| specifies one of the Chromium reference counted
+ // classes (base::RefCounted / base::RefCountedThreadSafe). |user_data| is
+ // ignored.
+ static bool IsRefCountedCallback(const CXXBaseSpecifier* base,
+ CXXBasePath& path,
+ void* user_data) {
+ FindBadConstructsConsumer* self =
+ static_cast<FindBadConstructsConsumer*>(user_data);
+
+ const TemplateSpecializationType* base_type =
+ dyn_cast<TemplateSpecializationType>(
+ UnwrapType(base->getType().getTypePtr()));
+ if (!base_type) {
+ // Base-most definition is not a template, so this cannot derive from
+ // base::RefCounted. However, it may still be possible to use with a
+ // scoped_refptr<> and support ref-counting, so this is not a perfect
+ // guarantee of safety.
+ return false;
+ }
+
+ TemplateName name = base_type->getTemplateName();
+ if (TemplateDecl* decl = name.getAsTemplateDecl()) {
+ std::string base_name = decl->getNameAsString();
+
+ // Check for both base::RefCounted and base::RefCountedThreadSafe.
+ if (base_name.compare(0, 10, "RefCounted") == 0 &&
+ self->GetNamespace(decl) == "base") {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Prints errors if the destructor of a RefCounted class is public.
+ void CheckRefCountedDtors(SourceLocation record_location,
+ CXXRecordDecl* record) {
+ // Skip anonymous structs.
+ if (record->getIdentifier() == NULL)
+ return;
+
+ CXXBasePaths paths;
+ if (!record->lookupInBases(
+ &FindBadConstructsConsumer::IsRefCountedCallback, this, paths)) {
+ return; // Class does not derive from a ref-counted base class.
+ }
+
+ if (!record->hasUserDeclaredDestructor()) {
+ emitWarning(
+ record_location,
+ "Classes that are ref-counted should have explicit "
+ "destructors that are protected or private.");
+ } else if (CXXDestructorDecl* dtor = record->getDestructor()) {
+ if (dtor->getAccess() == AS_public) {
+ emitWarning(
+ dtor->getInnerLocStart(),
+ "Classes that are ref-counted should not have "
+ "public destructors.");
+ }
+ }
+ }
+
+ // Prints errors if the constructor/destructor weight is too heavy.
+ void CheckCtorDtorWeight(SourceLocation record_location,
+ CXXRecordDecl* record) {
+ // We don't handle anonymous structs. If this record doesn't have a
+ // name, it's of the form:
+ //
+ // struct {
+ // ...
+ // } name_;
+ if (record->getIdentifier() == NULL)
+ return;
+
+ // Count the number of templated base classes as a feature of whether the
+ // destructor can be inlined.
+ int templated_base_classes = 0;
+ for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin();
+ it != record->bases_end(); ++it) {
+ if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() ==
+ TypeLoc::TemplateSpecialization) {
+ ++templated_base_classes;
+ }
+ }
+
+ // Count the number of trivial and non-trivial member variables.
+ int trivial_member = 0;
+ int non_trivial_member = 0;
+ int templated_non_trivial_member = 0;
+ for (RecordDecl::field_iterator it = record->field_begin();
+ it != record->field_end(); ++it) {
+ CountType(it->getType().getTypePtr(),
+ &trivial_member,
+ &non_trivial_member,
+ &templated_non_trivial_member);
+ }
+
+ // Check to see if we need to ban inlined/synthesized constructors. Note
+ // that the cutoffs here are kind of arbitrary. Scores over 10 break.
+ int dtor_score = 0;
+ // Deriving from a templated base class shouldn't be enough to trigger
+ // the ctor warning, but if you do *anything* else, it should.
+ //
+ // TODO(erg): This is motivated by templated base classes that don't have
+ // any data members. Somehow detect when templated base classes have data
+ // members and treat them differently.
+ dtor_score += templated_base_classes * 9;
+ // Instantiating a template is an insta-hit.
+ dtor_score += templated_non_trivial_member * 10;
+ // The fourth normal class member should trigger the warning.
+ dtor_score += non_trivial_member * 3;
+
+ int ctor_score = dtor_score;
+ // You should be able to have 9 ints before we warn you.
+ ctor_score += trivial_member;
+
+ if (ctor_score >= 10) {
+ if (!record->hasUserDeclaredConstructor()) {
+ emitWarning(record_location,
+ "Complex class/struct needs an explicit out-of-line "
+ "constructor.");
+ } else {
+ // Iterate across all the constructors in this file and yell if we
+ // find one that tries to be inline.
+ for (CXXRecordDecl::ctor_iterator it = record->ctor_begin();
+ it != record->ctor_end(); ++it) {
+ if (it->hasInlineBody()) {
+ if (it->isCopyConstructor() &&
+ !record->hasUserDeclaredCopyConstructor()) {
+ emitWarning(record_location,
+ "Complex class/struct needs an explicit out-of-line "
+ "copy constructor.");
+ } else {
+ emitWarning(it->getInnerLocStart(),
+ "Complex constructor has an inlined body.");
+ }
+ }
+ }
+ }
+ }
+
+ // The destructor side is equivalent except that we don't check for
+ // trivial members; 20 ints don't need a destructor.
+ if (dtor_score >= 10 && !record->hasTrivialDestructor()) {
+ if (!record->hasUserDeclaredDestructor()) {
+ emitWarning(
+ record_location,
+ "Complex class/struct needs an explicit out-of-line "
+ "destructor.");
+ } else if (CXXDestructorDecl* dtor = record->getDestructor()) {
+ if (dtor->hasInlineBody()) {
+ emitWarning(dtor->getInnerLocStart(),
+ "Complex destructor has an inline body.");
+ }
+ }
+ }
+ }
+
+ void CheckVirtualMethod(const CXXMethodDecl* method,
+ bool warn_on_inline_bodies) {
+ if (!method->isVirtual())
+ return;
+
+ if (!method->isVirtualAsWritten()) {
+ SourceLocation loc = method->getTypeSpecStartLoc();
+ if (isa<CXXDestructorDecl>(method))
+ loc = method->getInnerLocStart();
+ emitWarning(loc, "Overriding method must have \"virtual\" keyword.");
+ }
+
+ // Virtual methods should not have inline definitions beyond "{}". This
+ // only matters for header files.
+ if (warn_on_inline_bodies && method->hasBody() &&
+ method->hasInlineBody()) {
+ if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
+ if (cs->size()) {
+ emitWarning(
+ cs->getLBracLoc(),
+ "virtual methods with non-empty bodies shouldn't be "
+ "declared inline.");
+ }
+ }
+ }
+ }
+
+ bool InTestingNamespace(const Decl* record) {
+ return GetNamespace(record).find("testing") != std::string::npos;
+ }
+
+ bool IsMethodInBannedNamespace(const CXXMethodDecl* method) {
+ if (InBannedNamespace(method))
+ return true;
+ for (CXXMethodDecl::method_iterator i = method->begin_overridden_methods();
+ i != method->end_overridden_methods();
+ ++i) {
+ const CXXMethodDecl* overridden = *i;
+ if (IsMethodInBannedNamespace(overridden))
+ return true;
+ }
+
+ return false;
+ }
+
+ void CheckOverriddenMethod(const CXXMethodDecl* method) {
+ if (!method->size_overridden_methods() || method->getAttr<OverrideAttr>())
+ return;
+
+ if (isa<CXXDestructorDecl>(method) || method->isPure())
+ return;
+
+ if (IsMethodInBannedNamespace(method))
+ return;
+
+ SourceLocation loc = method->getTypeSpecStartLoc();
+ emitWarning(loc, "Overriding method must be marked with OVERRIDE.");
+ }
+
+ // Makes sure there is a "virtual" keyword on virtual methods.
+ //
+ // Gmock objects trigger these for each MOCK_BLAH() macro used. So we have a
+ // trick to get around that. If a class has member variables whose types are
+ // in the "testing" namespace (which is how gmock works behind the scenes),
+ // there's a really high chance we won't care about these errors
+ void CheckVirtualMethods(SourceLocation record_location,
+ CXXRecordDecl* record,
+ bool warn_on_inline_bodies) {
+ for (CXXRecordDecl::field_iterator it = record->field_begin();
+ it != record->field_end(); ++it) {
+ CXXRecordDecl* record_type =
+ it->getTypeSourceInfo()->getTypeLoc().getTypePtr()->
+ getAsCXXRecordDecl();
+ if (record_type) {
+ if (InTestingNamespace(record_type)) {
+ return;
+ }
+ }
+ }
+
+ for (CXXRecordDecl::method_iterator it = record->method_begin();
+ it != record->method_end(); ++it) {
+ if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) {
+ // Ignore constructors and assignment operators.
+ } else if (isa<CXXDestructorDecl>(*it) &&
+ !record->hasUserDeclaredDestructor()) {
+ // Ignore non-user-declared destructors.
+ } else {
+ CheckVirtualMethod(*it, warn_on_inline_bodies);
+ CheckOverriddenMethod(*it);
+ }
+ }
+ }
+
+ void CountType(const Type* type,
+ int* trivial_member,
+ int* non_trivial_member,
+ int* templated_non_trivial_member) {
+ switch (type->getTypeClass()) {
+ case Type::Record: {
+ // Simplifying; the whole class isn't trivial if the dtor is, but
+ // we use this as a signal about complexity.
+ if (TypeHasNonTrivialDtor(type))
+ (*trivial_member)++;
+ else
+ (*non_trivial_member)++;
+ break;
+ }
+ case Type::TemplateSpecialization: {
+ TemplateName name =
+ dyn_cast<TemplateSpecializationType>(type)->getTemplateName();
+ bool whitelisted_template = false;
+
+ // HACK: I'm at a loss about how to get the syntax checker to get
+ // whether a template is exterened or not. For the first pass here,
+ // just do retarded string comparisons.
+ if (TemplateDecl* decl = name.getAsTemplateDecl()) {
+ std::string base_name = decl->getNameAsString();
+ if (base_name == "basic_string")
+ whitelisted_template = true;
+ }
+
+ if (whitelisted_template)
+ (*non_trivial_member)++;
+ else
+ (*templated_non_trivial_member)++;
+ break;
+ }
+ case Type::Elaborated: {
+ CountType(
+ dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr(),
+ trivial_member, non_trivial_member, templated_non_trivial_member);
+ break;
+ }
+ case Type::Typedef: {
+ while (const TypedefType* TT = dyn_cast<TypedefType>(type)) {
+ type = TT->getDecl()->getUnderlyingType().getTypePtr();
+ }
+ CountType(type, trivial_member, non_trivial_member,
+ templated_non_trivial_member);
+ break;
+ }
+ default: {
+ // Stupid assumption: anything we see that isn't the above is one of
+ // the 20 integer types.
+ (*trivial_member)++;
+ break;
+ }
+ }
+ }
+};
+
+class FindBadConstructsAction : public PluginASTAction {
+ public:
+ FindBadConstructsAction()
+ : check_refcounted_dtors_(true),
+ check_virtuals_in_implementations_(true) {
+ }
+
+ protected:
+ // Overridden from PluginASTAction:
+ virtual ASTConsumer* CreateASTConsumer(CompilerInstance& instance,
+ llvm::StringRef ref) {
+ return new FindBadConstructsConsumer(
+ instance, check_refcounted_dtors_, check_virtuals_in_implementations_);
+ }
+
+ virtual bool ParseArgs(const CompilerInstance& instance,
+ const std::vector<std::string>& args) {
+ bool parsed = true;
+
+ for (size_t i = 0; i < args.size() && parsed; ++i) {
+ if (args[i] == "skip-refcounted-dtors") {
+ check_refcounted_dtors_ = false;
+ } else if (args[i] == "skip-virtuals-in-implementations") {
+ check_virtuals_in_implementations_ = false;
+ } else {
+ parsed = false;
+ llvm::errs() << "Unknown argument: " << args[i] << "\n";
+ }
+ }
+
+ return parsed;
+ }
+
+ private:
+ bool check_refcounted_dtors_;
+ bool check_virtuals_in_implementations_;
+};
+
+} // namespace
+
+static FrontendPluginRegistry::Add<FindBadConstructsAction>
+X("find-bad-constructs", "Finds bad C++ constructs");
diff --git a/third_party/libwebrtc/tools/clang/plugins/Makefile b/third_party/libwebrtc/tools/clang/plugins/Makefile
new file mode 100644
index 0000000000..0cfec71159
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/Makefile
@@ -0,0 +1,19 @@
+# This file requires the clang build system, at least for now. So to use this
+# Makefile, you should execute the following commands to copy this directory
+# into a clang checkout:
+#
+# cp -R <this directory> third_party/llvm/tools/clang/tools/chrome-plugin
+# cd third_party/llvm/tools/clang/tools/chrome-plugin
+# make
+
+CLANG_LEVEL := ../..
+LIBRARYNAME = FindBadConstructs
+
+LINK_LIBS_IN_SHARED = 0
+SHARED_LIBRARY = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+ifeq ($(OS),Darwin)
+ LDFLAGS=-Wl,-undefined,dynamic_lookup
+endif
diff --git a/third_party/libwebrtc/tools/clang/plugins/OWNERS b/third_party/libwebrtc/tools/clang/plugins/OWNERS
new file mode 100644
index 0000000000..4733a4f06b
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/OWNERS
@@ -0,0 +1 @@
+erg@chromium.org
diff --git a/third_party/libwebrtc/tools/clang/plugins/README.chromium b/third_party/libwebrtc/tools/clang/plugins/README.chromium
new file mode 100644
index 0000000000..a2ce0ff557
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/README.chromium
@@ -0,0 +1,4 @@
+Documentation for this code is:
+
+- http://code.google.com/p/chromium/wiki/Clang
+- http://code.google.com/p/chromium/wiki/WritingClangPlugins
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.cpp
new file mode 100644
index 0000000000..364a3e888c
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2012 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 "base_refcounted.h"
+
+#include <cstddef>
+
+namespace {
+
+// Unsafe; should error.
+class AnonymousDerivedProtectedToPublicInImpl
+ : public ProtectedRefCountedDtorInHeader {
+ public:
+ AnonymousDerivedProtectedToPublicInImpl() {}
+ ~AnonymousDerivedProtectedToPublicInImpl() {}
+};
+
+} // namespace
+
+// Unsafe; should error.
+class PublicRefCountedDtorInImpl
+ : public base::RefCounted<PublicRefCountedDtorInImpl> {
+ public:
+ PublicRefCountedDtorInImpl() {}
+ ~PublicRefCountedDtorInImpl() {}
+
+ private:
+ friend class base::RefCounted<PublicRefCountedDtorInImpl>;
+};
+
+class Foo {
+ public:
+ class BarInterface {
+ protected:
+ virtual ~BarInterface() {}
+ };
+
+ typedef base::RefCounted<BarInterface> RefCountedBar;
+ typedef RefCountedBar AnotherTypedef;
+};
+
+class Baz {
+ public:
+ typedef typename Foo::AnotherTypedef MyLocalTypedef;
+};
+
+// Unsafe; should error.
+class UnsafeTypedefChainInImpl : public Baz::MyLocalTypedef {
+ public:
+ UnsafeTypedefChainInImpl() {}
+ ~UnsafeTypedefChainInImpl() {}
+};
+
+int main() {
+ PublicRefCountedDtorInHeader bad;
+ PublicRefCountedDtorInImpl also_bad;
+
+ ProtectedRefCountedDtorInHeader* protected_ok = NULL;
+ PrivateRefCountedDtorInHeader* private_ok = NULL;
+
+ DerivedProtectedToPublicInHeader still_bad;
+ PublicRefCountedThreadSafeDtorInHeader another_bad_variation;
+ AnonymousDerivedProtectedToPublicInImpl and_this_is_bad_too;
+ ImplicitDerivedProtectedToPublicInHeader bad_yet_again;
+ UnsafeTypedefChainInImpl and_again_this_is_bad;
+
+ WebKitPublicDtorInHeader ignored;
+ WebKitDerivedPublicDtorInHeader still_ignored;
+
+ return 0;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.h b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.h
new file mode 100644
index 0000000000..1e53215997
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2012 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.
+
+#ifndef BASE_REFCOUNTED_H_
+#define BASE_REFCOUNTED_H_
+
+namespace base {
+
+template <typename T>
+class RefCounted {
+ public:
+ RefCounted() {}
+ ~RefCounted() {}
+};
+
+template <typename T>
+class RefCountedThreadSafe {
+ public:
+ RefCountedThreadSafe() {}
+ ~RefCountedThreadSafe() {}
+};
+
+} // namespace base
+
+// Ignore classes whose inheritance tree ends in WebKit's RefCounted base
+// class. Though prone to error, this pattern is very prevalent in WebKit
+// code, so do not issue any warnings.
+namespace WebKit {
+
+template <typename T>
+class RefCounted {
+ public:
+ RefCounted() {}
+ ~RefCounted() {}
+};
+
+} // namespace WebKit
+
+// Unsafe; should error.
+class PublicRefCountedDtorInHeader
+ : public base::RefCounted<PublicRefCountedDtorInHeader> {
+ public:
+ PublicRefCountedDtorInHeader() {}
+ ~PublicRefCountedDtorInHeader() {}
+
+ private:
+ friend class base::RefCounted<PublicRefCountedDtorInHeader>;
+};
+
+// Unsafe; should error.
+class PublicRefCountedThreadSafeDtorInHeader
+ : public base::RefCountedThreadSafe<
+ PublicRefCountedThreadSafeDtorInHeader> {
+ public:
+ PublicRefCountedThreadSafeDtorInHeader() {}
+ ~PublicRefCountedThreadSafeDtorInHeader() {}
+
+ private:
+ friend class base::RefCountedThreadSafe<
+ PublicRefCountedThreadSafeDtorInHeader>;
+};
+
+// Safe; should not have errors.
+class ProtectedRefCountedDtorInHeader
+ : public base::RefCounted<ProtectedRefCountedDtorInHeader> {
+ public:
+ ProtectedRefCountedDtorInHeader() {}
+
+ protected:
+ ~ProtectedRefCountedDtorInHeader() {}
+
+ private:
+ friend class base::RefCounted<ProtectedRefCountedDtorInHeader>;
+};
+
+// Safe; should not have errors.
+class PrivateRefCountedDtorInHeader
+ : public base::RefCounted<PrivateRefCountedDtorInHeader> {
+ public:
+ PrivateRefCountedDtorInHeader() {}
+
+ private:
+ ~PrivateRefCountedDtorInHeader() {}
+ friend class base::RefCounted<PrivateRefCountedDtorInHeader>;
+};
+
+// Unsafe; A grandchild class ends up exposing their parent and grandparent's
+// destructors.
+class DerivedProtectedToPublicInHeader
+ : public ProtectedRefCountedDtorInHeader {
+ public:
+ DerivedProtectedToPublicInHeader() {}
+ ~DerivedProtectedToPublicInHeader() {}
+};
+
+// Unsafe; A grandchild ends up implicitly exposing their parent and
+// grantparent's destructors.
+class ImplicitDerivedProtectedToPublicInHeader
+ : public ProtectedRefCountedDtorInHeader {
+ public:
+ ImplicitDerivedProtectedToPublicInHeader() {}
+};
+
+// Unsafe-but-ignored; should not have errors.
+class WebKitPublicDtorInHeader
+ : public WebKit::RefCounted<WebKitPublicDtorInHeader> {
+ public:
+ WebKitPublicDtorInHeader() {}
+ ~WebKitPublicDtorInHeader() {}
+};
+
+// Unsafe-but-ignored; should not have errors.
+class WebKitDerivedPublicDtorInHeader
+ : public WebKitPublicDtorInHeader {
+ public:
+ WebKitDerivedPublicDtorInHeader() {}
+ ~WebKitDerivedPublicDtorInHeader() {}
+};
+
+#endif // BASE_REFCOUNTED_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.txt b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.txt
new file mode 100644
index 0000000000..4626424177
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/base_refcounted.txt
@@ -0,0 +1,23 @@
+In file included from base_refcounted.cpp:5:
+./base_refcounted.h:45:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~PublicRefCountedDtorInHeader() {}
+ ^
+./base_refcounted.h:57:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~PublicRefCountedThreadSafeDtorInHeader() {}
+ ^
+./base_refcounted.h:94:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~DerivedProtectedToPublicInHeader() {}
+ ^
+./base_refcounted.h:99:1: warning: [chromium-style] Classes that are ref-counted should have explicit destructors that are protected or private.
+class ImplicitDerivedProtectedToPublicInHeader
+^
+base_refcounted.cpp:16:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~AnonymousDerivedProtectedToPublicInImpl() {}
+ ^
+base_refcounted.cpp:26:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~PublicRefCountedDtorInImpl() {}
+ ^
+base_refcounted.cpp:52:3: warning: [chromium-style] Classes that are ref-counted should not have public destructors.
+ ~UnsafeTypedefChainInImpl() {}
+ ^
+7 warnings generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.cpp
new file mode 100644
index 0000000000..dcd90020c5
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.cpp
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 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 "inline_copy_ctor.h"
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.h b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.h
new file mode 100644
index 0000000000..619a18392b
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 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.
+
+struct C {
+ C();
+ ~C();
+
+ static C foo() { return C(); }
+
+ int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p , q, r, s, t, u, v, w, x;
+};
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.txt b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.txt
new file mode 100644
index 0000000000..bc4bd8911e
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_copy_ctor.txt
@@ -0,0 +1,5 @@
+In file included from inline_copy_ctor.cpp:5:
+./inline_copy_ctor.h:5:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line copy constructor.
+struct C {
+^
+1 warning generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.cpp
new file mode 100644
index 0000000000..6a751fb405
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.cpp
@@ -0,0 +1,25 @@
+// 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.
+
+#include "inline_ctor.h"
+
+#include <string>
+#include <vector>
+
+// We don't warn on classes that are in CPP files.
+class InlineInCPPOK {
+ public:
+ InlineInCPPOK() {}
+ ~InlineInCPPOK() {}
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+};
+
+int main() {
+ InlineInCPPOK one;
+ InlineCtorsArentOKInHeader two;
+ return 0;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.h b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.h
new file mode 100644
index 0000000000..d053b2f57d
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 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.
+
+#ifndef INLINE_CTOR_H_
+#define INLINE_CTOR_H_
+
+#include <string>
+#include <vector>
+
+class InlineCtorsArentOKInHeader {
+ public:
+ InlineCtorsArentOKInHeader() {}
+ ~InlineCtorsArentOKInHeader() {}
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+};
+
+#endif // INLINE_CTOR_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.txt b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.txt
new file mode 100644
index 0000000000..caa0cb4e3b
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/inline_ctor.txt
@@ -0,0 +1,8 @@
+In file included from inline_ctor.cpp:5:
+./inline_ctor.h:13:3: warning: [chromium-style] Complex constructor has an inlined body.
+ InlineCtorsArentOKInHeader() {}
+ ^
+./inline_ctor.h:14:3: warning: [chromium-style] Complex destructor has an inline body.
+ ~InlineCtorsArentOKInHeader() {}
+ ^
+2 warnings generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.cpp
new file mode 100644
index 0000000000..8ee2fb2ac8
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.cpp
@@ -0,0 +1,23 @@
+// 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.
+
+#include "missing_ctor.h"
+
+#include <string>
+#include <vector>
+
+// We don't warn on classes that use default ctors in cpp files.
+class MissingInCPPOK {
+ public:
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+};
+
+int main() {
+ MissingInCPPOK one;
+ MissingCtorsArentOKInHeader two;
+ return 0;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.h b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.h
new file mode 100644
index 0000000000..1050457a1a
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef MISSING_CTOR_H_
+#define MISSING_CTOR_H_
+
+#include <string>
+#include <vector>
+
+class MissingCtorsArentOKInHeader {
+ public:
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+};
+
+#endif // MISSING_CTOR_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.txt b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.txt
new file mode 100644
index 0000000000..301449c4ac
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/missing_ctor.txt
@@ -0,0 +1,6 @@
+In file included from missing_ctor.cpp:5:
+./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
+class MissingCtorsArentOKInHeader {
+^
+./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
+2 warnings generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.cpp
new file mode 100644
index 0000000000..aa90a95eb3
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.cpp
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 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 "nested_class_inline_ctor.h"
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.h b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.h
new file mode 100644
index 0000000000..01cfea9232
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 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.
+
+#ifndef NESTED_CLASS_INLINE_CTOR_H_
+#define NESTED_CLASS_INLINE_CTOR_H_
+
+#include <string>
+#include <vector>
+
+// See crbug.com/136863.
+
+class Foo {
+ class Bar {
+ Bar() {}
+ ~Bar() {}
+
+ std::vector<std::string> a;
+ };
+};
+
+#endif // NESTED_CLASS_INLINE_CTOR_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.txt b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.txt
new file mode 100644
index 0000000000..39bd6e1dce
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/nested_class_inline_ctor.txt
@@ -0,0 +1,8 @@
+In file included from nested_class_inline_ctor.cpp:5:
+./nested_class_inline_ctor.h:15:5: warning: [chromium-style] Complex constructor has an inlined body.
+ Bar() {}
+ ^
+./nested_class_inline_ctor.h:16:5: warning: [chromium-style] Complex destructor has an inline body.
+ ~Bar() {}
+ ^
+2 warnings generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.cpp
new file mode 100644
index 0000000000..f572a41733
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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 "overridden_methods.h"
+
+// Fill in the implementations
+void DerivedClass::SomeMethod() {}
+void DerivedClass::SomeOtherMethod() {}
+void DerivedClass::WebKitModifiedSomething() {}
+
+class ImplementationInterimClass : public BaseClass {
+ public:
+ // Should not warn about pure virtual methods.
+ virtual void SomeMethod() = 0;
+};
+
+class ImplementationDerivedClass : public ImplementationInterimClass,
+ public webkit_glue::WebKitObserverImpl {
+ public:
+ // Should not warn about destructors.
+ virtual ~ImplementationDerivedClass() {}
+ // Should warn.
+ virtual void SomeMethod();
+ // Should not warn if marked as override.
+ virtual void SomeOtherMethod() override;
+ // Should not warn for inline implementations in implementation files.
+ virtual void SomeInlineMethod() {}
+ // Should not warn if overriding a method whose origin is WebKit.
+ virtual void WebKitModifiedSomething();
+ // Should warn if overridden method isn't pure.
+ virtual void SomeNonPureBaseMethod() {}
+};
+
+int main() {
+ DerivedClass something;
+ ImplementationDerivedClass something_else;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.h b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.h
new file mode 100644
index 0000000000..150c79913f
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef OVERRIDDEN_METHODS_H_
+#define OVERRIDDEN_METHODS_H_
+
+// Should warn about overriding of methods.
+class BaseClass {
+ public:
+ virtual ~BaseClass() {}
+ virtual void SomeMethod() = 0;
+ virtual void SomeOtherMethod() = 0;
+ virtual void SomeInlineMethod() = 0;
+ virtual void SomeNonPureBaseMethod() {}
+};
+
+class InterimClass : public BaseClass {
+ // Should not warn about pure virtual methods.
+ virtual void SomeMethod() = 0;
+};
+
+namespace WebKit {
+class WebKitObserver {
+ public:
+ virtual void WebKitModifiedSomething() {};
+};
+} // namespace WebKit
+
+namespace webkit_glue {
+class WebKitObserverImpl : WebKit::WebKitObserver {
+ public:
+ virtual void WebKitModifiedSomething() {};
+};
+} // namespace webkit_glue
+
+class DerivedClass : public InterimClass,
+ public webkit_glue::WebKitObserverImpl {
+ public:
+ // Should not warn about destructors.
+ virtual ~DerivedClass() {}
+ // Should warn.
+ virtual void SomeMethod();
+ // Should not warn if marked as override.
+ virtual void SomeOtherMethod() override;
+ // Should warn for inline implementations.
+ virtual void SomeInlineMethod() {}
+ // Should not warn if overriding a method whose origin is WebKit.
+ virtual void WebKitModifiedSomething();
+ // Should warn if overridden method isn't pure.
+ virtual void SomeNonPureBaseMethod() {}
+};
+
+#endif // OVERRIDDEN_METHODS_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.txt b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.txt
new file mode 100644
index 0000000000..7553ade70e
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/overridden_methods.txt
@@ -0,0 +1,20 @@
+In file included from overridden_methods.cpp:5:
+./overridden_methods.h:43:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeMethod();
+ ^
+./overridden_methods.h:47:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeInlineMethod() {}
+ ^
+./overridden_methods.h:51:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeNonPureBaseMethod() {}
+ ^
+overridden_methods.cpp:24:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeMethod();
+ ^
+overridden_methods.cpp:28:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeInlineMethod() {}
+ ^
+overridden_methods.cpp:32:11: warning: [chromium-style] Overriding method must be marked with OVERRIDE.
+ virtual void SomeNonPureBaseMethod() {}
+ ^
+6 warnings generated.
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/test.sh b/third_party/libwebrtc/tools/clang/plugins/tests/test.sh
new file mode 100755
index 0000000000..262ebbba29
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/test.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# 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.
+#
+# Hacky, primitive testing: This runs the style plugin for a set of input files
+# and compares the output with golden result files.
+
+E_BADARGS=65
+E_FAILEDTEST=1
+
+failed_any_test=
+
+# Prints usage information.
+usage() {
+ echo "Usage: $(basename "${0}")" \
+ "<Path to the llvm build dir, usually Release+Asserts>"
+ echo ""
+ echo " Runs all the libFindBadConstructs unit tests"
+ echo ""
+}
+
+# Runs a single test case.
+do_testcase() {
+ local output="$("${CLANG_DIR}"/bin/clang -c -Wno-c++11-extensions \
+ -Xclang -load -Xclang "${CLANG_DIR}"/lib/libFindBadConstructs.${LIB} \
+ -Xclang -plugin -Xclang find-bad-constructs ${1} 2>&1)"
+ local diffout="$(echo "${output}" | diff - "${2}")"
+ if [ "${diffout}" = "" ]; then
+ echo "PASS: ${1}"
+ else
+ failed_any_test=yes
+ echo "FAIL: ${1}"
+ echo "Output of compiler:"
+ echo "${output}"
+ echo "Expected output:"
+ cat "${2}"
+ echo
+ fi
+}
+
+# Validate input to the script.
+if [[ -z "${1}" ]]; then
+ usage
+ exit ${E_BADARGS}
+elif [[ ! -d "${1}" ]]; then
+ echo "${1} is not a directory."
+ usage
+ exit ${E_BADARGS}
+else
+ export CLANG_DIR="${PWD}/${1}"
+ echo "Using clang directory ${CLANG_DIR}..."
+
+ # The golden files assume that the cwd is this directory. To make the script
+ # work no matter what the cwd is, explicitly cd to there.
+ cd "$(dirname "${0}")"
+
+ if [ "$(uname -s)" = "Linux" ]; then
+ export LIB=so
+ elif [ "$(uname -s)" = "Darwin" ]; then
+ export LIB=dylib
+ fi
+fi
+
+for input in *.cpp; do
+ do_testcase "${input}" "${input%cpp}txt"
+done
+
+if [[ "${failed_any_test}" ]]; then
+ exit ${E_FAILEDTEST}
+fi
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.cpp b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.cpp
new file mode 100644
index 0000000000..a07cbe4875
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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 "virtual_methods.h"
+
+// Shouldn't warn about method usage in the implementation file.
+class VirtualMethodsInImplementation {
+ public:
+ virtual void MethodIsAbstract() = 0;
+ virtual void MethodHasNoArguments();
+ virtual void MethodHasEmptyDefaultImpl() {}
+ virtual bool ComplainAboutThis() { return true; }
+};
+
+// Stubs to fill in the abstract method
+class ConcreteVirtualMethodsInHeaders : public VirtualMethodsInHeaders {
+ public:
+ virtual void MethodIsAbstract() override {}
+};
+
+class ConcreteVirtualMethodsInImplementation
+ : public VirtualMethodsInImplementation {
+ public:
+ virtual void MethodIsAbstract() override {}
+};
+
+// Fill in the implementations
+void VirtualMethodsInHeaders::MethodHasNoArguments() {}
+void WarnOnMissingVirtual::MethodHasNoArguments() {}
+void VirtualMethodsInImplementation::MethodHasNoArguments() {}
+
+int main() {
+ ConcreteVirtualMethodsInHeaders one;
+ ConcreteVirtualMethodsInImplementation two;
+}
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.h b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.h
new file mode 100644
index 0000000000..d9fbf96ed3
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef VIRTUAL_METHODS_H_
+#define VIRTUAL_METHODS_H_
+
+// Should warn about virtual method usage.
+class VirtualMethodsInHeaders {
+ public:
+ // Don't complain about these.
+ virtual void MethodIsAbstract() = 0;
+ virtual void MethodHasNoArguments();
+ virtual void MethodHasEmptyDefaultImpl() {}
+
+ // But complain about this:
+ virtual bool ComplainAboutThis() { return true; }
+};
+
+// Complain on missing 'virtual' keyword in overrides.
+class WarnOnMissingVirtual : public VirtualMethodsInHeaders {
+ public:
+ void MethodHasNoArguments() override;
+};
+
+// Don't complain about things in a 'testing' namespace.
+namespace testing {
+struct TestStruct {};
+} // namespace testing
+
+class VirtualMethodsInHeadersTesting : public VirtualMethodsInHeaders {
+ public:
+ // Don't complain about no virtual testing methods.
+ void MethodHasNoArguments();
+ private:
+ testing::TestStruct tester_;
+};
+
+#endif // VIRTUAL_METHODS_H_
diff --git a/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.txt b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.txt
new file mode 100644
index 0000000000..571d6d667d
--- /dev/null
+++ b/third_party/libwebrtc/tools/clang/plugins/tests/virtual_methods.txt
@@ -0,0 +1,8 @@
+In file included from virtual_methods.cpp:5:
+./virtual_methods.h:17:36: warning: [chromium-style] virtual methods with non-empty bodies shouldn't be declared inline.
+ virtual bool ComplainAboutThis() { return true; }
+ ^
+./virtual_methods.h:23:3: warning: [chromium-style] Overriding method must have "virtual" keyword.
+ void MethodHasNoArguments() override;
+ ^
+2 warnings generated.