1d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks// Use of this source code is governed by a BSD-style license that can be
3d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks// found in the LICENSE file.
4d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
5d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks// A general interface for filtering and only acting on classes in Chromium C++
6d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks// code.
7d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
8d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks#include "ChromeClassTester.h"
9d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
10d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks#include <sys/param.h>
11d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
12d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks#include "clang/AST/AST.h"
13d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks#include "clang/Basic/FileManager.h"
14d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks#include "clang/Basic/SourceManager.h"
15d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruthusing namespace clang;
17d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
18d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksnamespace {
19d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
20d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool starts_with(const std::string& one, const std::string& two) {
21d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return one.compare(0, two.size(), two) == 0;
22d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
23d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
24d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksstd::string lstrip(const std::string& one, const std::string& two) {
25d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (starts_with(one, two))
26d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    return one.substr(two.size());
27d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return one;
2865bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose}
29d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
30d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ends_with(const std::string& one, const std::string& two) {
31d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (two.size() > one.size())
32d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    return false;
33d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
34d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return one.compare(one.size() - two.size(), two.size(), two) == 0;
35d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
36d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
371f03a8a0334924719ff85c993d652480e93fda98Jordan Rose}  // namespace
381f03a8a0334924719ff85c993d652480e93fda98Jordan Rose
39d699ade396154238d2fa89bb09fdcfb79e5587d2Anna ZaksChromeClassTester::ChromeClassTester(CompilerInstance& instance)
40d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    : instance_(instance),
4196479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose      diagnostic_(instance.getDiagnostics()) {
4296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  BuildBannedLists();
43d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
44d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
45d699ade396154238d2fa89bb09fdcfb79e5587d2Anna ZaksChromeClassTester::~ChromeClassTester() {}
46d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
47344c77aac25e5d960aced3f45fbaa09853383f6dAnna Zaksvoid ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
48d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  pending_class_decls_.push_back(tag);
49d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
50d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
51d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) {
52d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  for (size_t i = 0; i < pending_class_decls_.size(); ++i)
53d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    CheckTag(pending_class_decls_[i]);
54bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  pending_class_decls_.clear();
55123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks
56d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return true;  // true means continue parsing.
57d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
58d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
59d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksvoid ChromeClassTester::CheckTag(TagDecl* tag) {
60d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // We handle class types here where we have semantic information. We can only
61d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // check structs/classes/enums here, but we get a bunch of nice semantic
62d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // information instead of just parsing information.
63d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
64d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
65d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // If this is a POD or a class template or a type dependent on a
66d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // templated class, assume there's no ctor/dtor/virtual method
67d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // optimization that we can do.
68d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    if (record->isPOD() ||
69d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks        record->getDescribedClassTemplate() ||
701f03a8a0334924719ff85c993d652480e93fda98Jordan Rose        record->getTemplateSpecializationKind() ||
711f03a8a0334924719ff85c993d652480e93fda98Jordan Rose        record->isDependentType())
72d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      return;
73d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
74d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    if (InBannedNamespace(record))
75d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      return;
76d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
77d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    SourceLocation record_location = record->getInnerLocStart();
78d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    if (InBannedDirectory(record_location))
79d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      return;
801f03a8a0334924719ff85c993d652480e93fda98Jordan Rose
811f03a8a0334924719ff85c993d652480e93fda98Jordan Rose    // We sadly need to maintain a blacklist of types that violate these
82d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // rules, but do so for good reason or due to limitations of this
8396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    // checker (i.e., we don't handle extern templates very well).
8496479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    std::string base_name = record->getNameAsString();
8596479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    if (IsIgnoredType(base_name))
8696479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose      return;
878919e688dc610d1f632a4d43f7f1489f67255476Jordan Rose
8896479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    // We ignore all classes that end with "Matcher" because they're probably
8996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    // GMock artifacts.
90de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose    if (ends_with(base_name, "Matcher"))
91d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks        return;
9296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
9396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    CheckChromeClass(record_location, record);
9496479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  } else if (EnumDecl* enum_decl = dyn_cast<EnumDecl>(tag)) {
9596479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    SourceLocation enum_location = enum_decl->getInnerLocStart();
96de507eaf3cb54d3cb234dc14499c10ab3373d15fJordan Rose    if (InBannedDirectory(enum_location))
97d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      return;
9896479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
9996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    std::string base_name = enum_decl->getNameAsString();
10096479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    if (IsIgnoredType(base_name))
10196479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose      return;
10296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
10396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose    CheckChromeEnum(enum_location, enum_decl);
1041f03a8a0334924719ff85c993d652480e93fda98Jordan Rose  }
1051f03a8a0334924719ff85c993d652480e93fda98Jordan Rose}
10696479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
10796479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rosevoid ChromeClassTester::emitWarning(SourceLocation loc,
10896479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose                                    const char* raw_error) {
10996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  FullSourceLoc full(loc, instance().getSourceManager());
11096479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  std::string err;
11196479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  err = "[chromium-style] ";
11296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  err += raw_error;
11396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  DiagnosticIDs::Level level =
11496479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose      diagnostic().getWarningsAsErrors() ?
11596479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose      DiagnosticIDs::Error :
116d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      DiagnosticIDs::Warning;
117d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  unsigned id = diagnostic().getDiagnosticIDs()->getCustomDiagID(level, err);
118d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  DiagnosticBuilder builder = diagnostic().Report(full, id);
119d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
120d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
121d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ChromeClassTester::InBannedNamespace(const Decl* record) {
122d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  std::string n = GetNamespace(record);
123d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (!n.empty()) {
124d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
125d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks        != banned_namespaces_.end();
126d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  }
127d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
128d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return false;
12981c16fc757fe7b68cbd035765e3be92281625663James Dennett}
130d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
131d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksstd::string ChromeClassTester::GetNamespace(const Decl* record) {
132d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return GetNamespaceImpl(record->getDeclContext(), "");
133d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
134d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
135d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ChromeClassTester::InImplementationFile(SourceLocation record_location) {
136d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  std::string filename;
137d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (!GetFilename(record_location, &filename))
13881c16fc757fe7b68cbd035765e3be92281625663James Dennett    return false;
139d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
140d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (ends_with(filename, ".cc") || ends_with(filename, ".cpp") ||
141d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks      ends_with(filename, ".mm")) {
142d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    return true;
143d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  }
144d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
145d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return false;
146d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
147d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
148d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksvoid ChromeClassTester::BuildBannedLists() {
149d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_namespaces_.push_back("std");
150d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_namespaces_.push_back("__gnu_cxx");
151d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
152d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_namespaces_.push_back("blink");
153d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_namespaces_.push_back("WTF");
154d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
155d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/third_party/");
156d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/native_client/");
157344c77aac25e5d960aced3f45fbaa09853383f6dAnna Zaks  banned_directories_.push_back("/breakpad/");
15865bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  banned_directories_.push_back("/courgette/");
159d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/pdf/");
160344c77aac25e5d960aced3f45fbaa09853383f6dAnna Zaks  banned_directories_.push_back("/ppapi/");
161344c77aac25e5d960aced3f45fbaa09853383f6dAnna Zaks  banned_directories_.push_back("/usr/");
162d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/testing/");
163d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/v8/");
164d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/dart/");
165d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/sdch/");
166d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/icu4c/");
167d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/frameworks/");
168d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
169d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Don't check autogenerated headers.
170d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Make puts them below $(builddir_name)/.../gen and geni.
171d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Ninja puts them below OUTPUT_DIR/.../gen
172d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Xcode has a fixed output directory for everything.
173d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/gen/");
174d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/geni/");
175d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/xcodebuild/");
176d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
177d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // You are standing in a mazy of twisty dependencies, all resolved by
178d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // putting everything in the header.
179e8018f24f0f0e1cb1490c37b158da5d5c456e577Anton Yartsev  banned_directories_.push_back("/automation/");
180e8018f24f0f0e1cb1490c37b158da5d5c456e577Anton Yartsev
181e8018f24f0f0e1cb1490c37b158da5d5c456e577Anton Yartsev  // Don't check system headers.
182d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  banned_directories_.push_back("/Developer/");
183d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
184d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Used in really low level threading code that probably shouldn't be out of
185d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // lined.
186d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("ThreadLocalBoolean");
187d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
188d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // A complicated pickle derived struct that is all packed integers.
189d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("Header");
190d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
191d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Part of the GPU system that uses multiple included header
192d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // weirdness. Never getting this right.
193872db39510372c4acd8851a3b956e1a135cfcd41Duncan Sands  ignored_record_names_.insert("Validators");
194d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
195d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
196d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("AutocompleteController");
197d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("HistoryURLProvider");
198d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
199d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Because of chrome frame
200d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("ReliabilityTestSuite");
201d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
202d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Used over in the net unittests. A large enough bundle of integers with 1
203d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // non-pod class member. Probably harmless.
204d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("MockTransaction");
205d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
206d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Enum type with _LAST members where _LAST doesn't mean last enum value.
2078bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ignored_record_names_.insert("ServerFieldType");
208d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
209d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Used heavily in ui_unittests and once in views_unittests. Fixing this
210d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // isn't worth the overhead of an additional library.
211d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("TestAnimationDelegate");
212d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
213d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Part of our public interface that nacl and friends use. (Arguably, this
214d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // should mean that this is a higher priority but fixing this looks hard.)
215d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  ignored_record_names_.insert("PluginVersionInfo");
2168bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek
217d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // Measured performance improvement on cc_perftests. See
21865bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  // https://codereview.chromium.org/11299290/
21965bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  ignored_record_names_.insert("QuadF");
22065bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose
22165bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  // Enum type with _LAST members where _LAST doesn't mean last enum value.
22265bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  ignored_record_names_.insert("ViewID");
22365bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose}
2248bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek
22566c40400e7d6272b0cd675ada18dd62c1f0362c7Anna Zaksstd::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
22665bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose                                                const std::string& candidate) {
22765bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  switch (context->getDeclKind()) {
22865bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose    case Decl::TranslationUnit: {
22965bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose      return candidate;
23065bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose    }
23181c16fc757fe7b68cbd035765e3be92281625663James Dennett    case Decl::Namespace: {
23281c16fc757fe7b68cbd035765e3be92281625663James Dennett      const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
23381c16fc757fe7b68cbd035765e3be92281625663James Dennett      std::string name_str;
23466c40400e7d6272b0cd675ada18dd62c1f0362c7Anna Zaks      llvm::raw_string_ostream OS(name_str);
23565bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose      if (decl->isAnonymousNamespace())
23665bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose        OS << "<anonymous namespace>";
23765bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose      else
23865bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose        OS << *decl;
23965bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose      return GetNamespaceImpl(context->getParent(),
24065bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose                              OS.str());
24165bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose    }
24265bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose    default: {
24365bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose      return GetNamespaceImpl(context->getParent(), candidate);
24465bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose    }
24565bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose  }
24665bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose}
24781c16fc757fe7b68cbd035765e3be92281625663James Dennett
24881c16fc757fe7b68cbd035765e3be92281625663James Dennettbool ChromeClassTester::InBannedDirectory(SourceLocation loc) {
2498bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  std::string filename;
2508bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  if (!GetFilename(loc, &filename)) {
251bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks    // If the filename cannot be determined, simply treat this as a banned
252d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // location, instead of going through the full lookup process.
25366c40400e7d6272b0cd675ada18dd62c1f0362c7Anna Zaks    return true;
254740d490593e0de8732a697c9f77b90ddd463863bJordan Rose  }
255d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
256d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // We need to special case scratch space; which is where clang does its
257d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  // macro expansion. We explicitly want to allow people to do otherwise bad
258bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // things through macros that were defined due to third party libraries.
259bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  if (filename == "<scratch space>")
260bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks    return true;
2611655bcd052a67a3050fc55df8ecce57342352e68Anna Zaks
262bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // Don't complain about autogenerated protobuf files.
263bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  if (ends_with(filename, ".pb.h")) {
264bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks    return true;
265bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  }
266bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks
267bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // We need to munge the paths so that they are relative to the repository
268bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // srcroot. We first resolve the symlinktastic relative path and then
269233e26acc0ff2a1098f4c813f69286fce840a422Anna Zaks  // remove our known srcroot from it if needed.
270bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  char resolvedPath[MAXPATHLEN];
271bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  if (realpath(filename.c_str(), resolvedPath)) {
272bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks    filename = resolvedPath;
273233e26acc0ff2a1098f4c813f69286fce840a422Anna Zaks  }
274233e26acc0ff2a1098f4c813f69286fce840a422Anna Zaks
275bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // On linux, chrome is often checked out to /usr/local/google. Due to the
276bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // "usr" rule in banned_directories_, all diagnostics would be suppressed
277bf53dfac8195835028bd6347433f7dbebcc29fc1Anna Zaks  // in that case. As a workaround, strip that prefix.
278123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks  filename = lstrip(filename, "/usr/local/google");
279123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks
280123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks  for (size_t i = 0; i < banned_directories_.size(); ++i) {
281123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    // If any of the banned directories occur as a component in filename,
282123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    // this file is rejected.
283123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    const std::string& banned_dir = banned_directories_[i];
284123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    assert(banned_dir.front() == '/' && "Banned dir must start with '/'");
285123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    assert(banned_dir.back() == '/' && "Banned dir must end with '/'");
286123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks
287123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks    if (filename.find(banned_dir) != std::string::npos)
288123243cfd80f790a27edd1b829cd190a85f6c006Anna Zaks      return true;
289d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  }
290d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
291d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return false;
292d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
293d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
294d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
295d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return ignored_record_names_.find(base_name) != ignored_record_names_.end();
296d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks}
297d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
298d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaksbool ChromeClassTester::GetFilename(SourceLocation loc,
299d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks                                    std::string* filename) {
300d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  const SourceManager& source_manager = instance_.getSourceManager();
301d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  SourceLocation spelling_location = source_manager.getSpellingLoc(loc);
302d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
303d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  if (ploc.isInvalid()) {
304d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // If we're in an invalid location, we're looking at things that aren't
305d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks    // actually stated in the source.
3061f03a8a0334924719ff85c993d652480e93fda98Jordan Rose    return false;
307d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  }
308d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks
309d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  *filename = ploc.getFilename();
310d699ade396154238d2fa89bb09fdcfb79e5587d2Anna Zaks  return true;
31165bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose}
31265bc6537509fcfb9e7e724e7d40546eea931e07fJordan Rose