#include "ChromeClassTester.h"
#include "Util.h"
#include "clang/AST/AST.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#ifdef LLVM_ON_UNIX
#include <sys/param.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
using namespace clang;
using chrome_checker::Options;
namespace {
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;
}
}
ChromeClassTester::ChromeClassTester(CompilerInstance& instance,
const Options& options)
: options_(options),
instance_(instance),
diagnostic_(instance.getDiagnostics()) {
BuildBannedLists();
}
ChromeClassTester::~ChromeClassTester() {}
void ChromeClassTester::CheckTag(TagDecl* tag) {
SourceLocation location = tag->getInnerLocStart();
LocationType location_type = ClassifyLocation(location);
if (location_type == LocationType::kThirdParty)
return;
if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
std::string base_name = record->getNameAsString();
if (IsIgnoredType(base_name))
return;
CheckChromeClass(location_type, location, record);
}
}
ChromeClassTester::LocationType ChromeClassTester::ClassifyLocation(
SourceLocation loc) {
auto classification = chrome_checker::ClassifySourceLocation(
instance().getHeaderSearchOpts(), instance().getSourceManager(), loc);
switch (classification) {
case chrome_checker::LocationClassification::kFirstParty:
return LocationType::kChrome;
case chrome_checker::LocationClassification::kBlink:
return LocationType::kBlink;
case chrome_checker::LocationClassification::kChromiumThirdParty:
return LocationType::kThirdParty;
case chrome_checker::LocationClassification::kThirdParty:
return LocationType::kThirdParty;
case chrome_checker::LocationClassification::kGenerated:
return LocationType::kThirdParty;
case chrome_checker::LocationClassification::kMacro:
return LocationType::kThirdParty;
case chrome_checker::LocationClassification::kSystem:
return LocationType::kThirdParty;
}
assert(false);
}
bool ChromeClassTester::HasIgnoredBases(const CXXRecordDecl* record) {
for (const auto& base : record->bases()) {
CXXRecordDecl* base_record = base.getType()->getAsCXXRecordDecl();
if (!base_record)
continue;
const std::string& base_name = base_record->getQualifiedNameAsString();
if (ignored_base_classes_.count(base_name) > 0)
return true;
if (HasIgnoredBases(base_record))
return true;
}
return false;
}
bool ChromeClassTester::InImplementationFile(SourceLocation record_location) {
std::string filename;
const SourceManager& source_manager = instance_.getSourceManager();
while (true) {
filename = GetFilename(instance().getSourceManager(), record_location,
FilenameLocationType::kSpellingLoc);
if (ends_with(filename, ".cc") || ends_with(filename, ".cpp") ||
ends_with(filename, ".mm")) {
return true;
}
if (!record_location.isMacroID()) {
break;
}
record_location =
source_manager.getImmediateExpansionRange(record_location).getBegin();
}
return false;
}
void ChromeClassTester::BuildBannedLists() {
ignored_record_names_.emplace("Header");
ignored_record_names_.emplace("Validators");
ignored_record_names_.emplace("AutocompleteController");
ignored_record_names_.emplace("HistoryURLProvider");
ignored_record_names_.emplace("MockTransaction");
ignored_record_names_.emplace("TestAnimationDelegate");
ignored_record_names_.emplace("PluginVersionInfo");
ignored_record_names_.emplace("QuadF");
ignored_base_classes_.emplace("IPC::NoParams");
}
bool ChromeClassTester::IsIgnoredType(std::string_view base_name) {
return ignored_record_names_.count(base_name) != 0u;
}
DiagnosticsEngine::Level ChromeClassTester::getErrorLevel() {
return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error
: DiagnosticsEngine::Warning;
}