diff options
Diffstat (limited to 'tools/clang/plugins/ChromeClassTester.cpp')
-rw-r--r-- | tools/clang/plugins/ChromeClassTester.cpp | 104 |
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; } } } |