summaryrefslogtreecommitdiffstats
path: root/tools/clang/plugins/ChromeClassTester.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/clang/plugins/ChromeClassTester.cpp')
-rw-r--r--tools/clang/plugins/ChromeClassTester.cpp104
1 files changed, 75 insertions, 29 deletions
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp
index 74a1339..31b77b3 100644
--- a/tools/clang/plugins/ChromeClassTester.cpp
+++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -9,6 +9,8 @@
#include <sys/param.h>
+#include "clang/Basic/FileManager.h"
+
using namespace clang;
namespace {
@@ -88,6 +90,7 @@ void ChromeClassTester::BuildBannedLists() {
// Don't check autogenerated headers.
banned_directories_.push_back("out");
+ banned_directories_.push_back("llvm");
banned_directories_.push_back("xcodebuild");
// You are standing in a mazy of twisty dependencies, all resolved by
@@ -132,6 +135,10 @@ void ChromeClassTester::BuildBannedLists() {
ChromeClassTester::~ChromeClassTester() {}
void ChromeClassTester::HandleTagDeclDefinition(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
@@ -165,6 +172,34 @@ void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
}
}
+void ChromeClassTester::HandleTranslationUnit(clang::ASTContext& ctx) {
+ RecursivelyCheckTopLevels(ctx.getTranslationUnitDecl());
+}
+
+void ChromeClassTester::RecursivelyCheckTopLevels(Decl* d) {
+ // Unlike HandleTagDeclDefinition, we can only rely on having parsing
+ // information here. We absoluetly shouldn't check that any semantic data
+ // here because we will assert.
+
+ Decl::Kind kind = d->getKind();
+ if (kind == Decl::UsingDirective) {
+ UsingDirectiveDecl* record = cast<UsingDirectiveDecl>(d);
+ SourceLocation record_location = record->getLocation();
+ if (!InBannedDirectory(record_location))
+ CheckChromeUsingDirective(record_location, record);
+ }
+
+ // If this is a DeclContext that isn't a function/method, recurse.
+ if (DeclContext* context = dyn_cast<DeclContext>(d)) {
+ if (context->isFileContext()) {
+ for (DeclContext::decl_iterator it = context->decls_begin();
+ it != context->decls_end(); ++it) {
+ RecursivelyCheckTopLevels(*it);
+ }
+ }
+ }
+}
+
void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
FullSourceLoc full(loc, instance().getSourceManager());
std::string err;
@@ -219,40 +254,51 @@ std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
}
}
-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);
+bool ChromeClassTester::InBannedDirectory(SourceLocation loc) {
+ const SourceManager &SM = instance_.getSourceManager();
+ SourceLocation spelling_location = SM.getSpellingLoc(loc);
+ PresumedLoc ploc = SM.getPresumedLoc(spelling_location);
+ std::string buffer_name;
+ if (ploc.isInvalid()) {
+ // If we're in an invalid location, we're looking at things that aren't
+ // actually stated in the source; treat this as a banned location instead
+ // of going through our full lookup process.
+ return true;
+ } else {
+ std::string b = ploc.getFilename();
+
+ // 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 (b == "<scratch space>")
+ return true;
- // Don't complain about these things in implementation files.
- if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) {
- return true;
- }
+ // Don't complain about these things in implementation files.
+ if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) {
+ return true;
+ }
- // Don't complain about autogenerated protobuf files.
- if (ends_with(b, ".pb.h")) {
- return true;
- }
+ // Don't complain about autogenerated protobuf files.
+ if (ends_with(b, ".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(b.c_str(), resolvedPath)) {
- std::string resolved = resolvedPath;
- if (starts_with(resolved, src_root_)) {
- b = resolved.substr(src_root_.size());
- }
+ // 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(b.c_str(), resolvedPath)) {
+ std::string resolved = resolvedPath;
+ if (starts_with(resolved, src_root_)) {
+ b = resolved.substr(src_root_.size());
}
+ }
- for (std::vector<std::string>::const_iterator it =
- banned_directories_.begin();
- it != banned_directories_.end(); ++it) {
- if (starts_with(b, *it))
- return true;
+ for (std::vector<std::string>::const_iterator it =
+ banned_directories_.begin();
+ it != banned_directories_.end(); ++it) {
+ if (starts_with(b, *it)) {
+ return true;
}
}
}