| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // A general interface for filtering and only acting on classes in Chromium C++ | 5 // A general interface for filtering and only acting on classes in Chromium C++ |
| 6 // code. | 6 // code. |
| 7 | 7 |
| 8 #include "ChromeClassTester.h" | 8 #include "ChromeClassTester.h" |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 diagnostic_(instance.getDiagnostics()) { | 41 diagnostic_(instance.getDiagnostics()) { |
| 42 BuildBannedLists(); | 42 BuildBannedLists(); |
| 43 } | 43 } |
| 44 | 44 |
| 45 ChromeClassTester::~ChromeClassTester() {} | 45 ChromeClassTester::~ChromeClassTester() {} |
| 46 | 46 |
| 47 void ChromeClassTester::CheckTag(TagDecl* tag) { | 47 void ChromeClassTester::CheckTag(TagDecl* tag) { |
| 48 // We handle class types here where we have semantic information. We can only | 48 // We handle class types here where we have semantic information. We can only |
| 49 // check structs/classes/enums here, but we get a bunch of nice semantic | 49 // check structs/classes/enums here, but we get a bunch of nice semantic |
| 50 // information instead of just parsing information. | 50 // information instead of just parsing information. |
| 51 if (InBannedNamespace(tag)) |
| 52 return; |
| 53 |
| 54 SourceLocation location = tag->getInnerLocStart(); |
| 55 LocationType location_type = ClassifyLocation(location); |
| 56 if (location_type == LocationType::kThirdParty) |
| 57 return; |
| 51 | 58 |
| 52 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { | 59 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { |
| 53 if (InBannedNamespace(record)) | |
| 54 return; | |
| 55 | |
| 56 SourceLocation record_location = record->getInnerLocStart(); | |
| 57 if (InBannedDirectory(record_location)) | |
| 58 return; | |
| 59 | |
| 60 // We sadly need to maintain a blacklist of types that violate these | 60 // We sadly need to maintain a blacklist of types that violate these |
| 61 // rules, but do so for good reason or due to limitations of this | 61 // rules, but do so for good reason or due to limitations of this |
| 62 // checker (i.e., we don't handle extern templates very well). | 62 // checker (i.e., we don't handle extern templates very well). |
| 63 std::string base_name = record->getNameAsString(); | 63 std::string base_name = record->getNameAsString(); |
| 64 if (IsIgnoredType(base_name)) | 64 if (IsIgnoredType(base_name)) |
| 65 return; | 65 return; |
| 66 | 66 |
| 67 // We ignore all classes that end with "Matcher" because they're probably | 67 // We ignore all classes that end with "Matcher" because they're probably |
| 68 // GMock artifacts. | 68 // GMock artifacts. |
| 69 if (ends_with(base_name, "Matcher")) | 69 if (ends_with(base_name, "Matcher")) |
| 70 return; | 70 return; |
| 71 | 71 |
| 72 CheckChromeClass(record_location, record); | 72 CheckChromeClass(location_type, location, record); |
| 73 } else if (EnumDecl* enum_decl = dyn_cast<EnumDecl>(tag)) { | 73 } else if (EnumDecl* enum_decl = dyn_cast<EnumDecl>(tag)) { |
| 74 SourceLocation enum_location = enum_decl->getInnerLocStart(); | |
| 75 if (InBannedDirectory(enum_location)) | |
| 76 return; | |
| 77 | |
| 78 std::string base_name = enum_decl->getNameAsString(); | 74 std::string base_name = enum_decl->getNameAsString(); |
| 75 // TODO(dcheng): This should probably consult a separate list. |
| 79 if (IsIgnoredType(base_name)) | 76 if (IsIgnoredType(base_name)) |
| 80 return; | 77 return; |
| 81 | 78 |
| 82 CheckChromeEnum(enum_location, enum_decl); | 79 CheckChromeEnum(location_type, location, enum_decl); |
| 83 } | 80 } |
| 84 } | 81 } |
| 85 | 82 |
| 86 void ChromeClassTester::emitWarning(SourceLocation loc, | 83 void ChromeClassTester::emitWarning(SourceLocation loc, |
| 87 const char* raw_error) { | 84 const char* raw_error) { |
| 88 FullSourceLoc full(loc, instance().getSourceManager()); | 85 FullSourceLoc full(loc, instance().getSourceManager()); |
| 89 std::string err; | 86 std::string err; |
| 90 err = "[chromium-style] "; | 87 err = "[chromium-style] "; |
| 91 err += raw_error; | 88 err += raw_error; |
| 92 | 89 |
| 93 DiagnosticIDs::Level level = getErrorLevel() == DiagnosticsEngine::Error | 90 DiagnosticIDs::Level level = getErrorLevel() == DiagnosticsEngine::Error |
| 94 ? DiagnosticIDs::Error : DiagnosticIDs::Warning; | 91 ? DiagnosticIDs::Error : DiagnosticIDs::Warning; |
| 95 | 92 |
| 96 unsigned id = diagnostic().getDiagnosticIDs()->getCustomDiagID(level, err); | 93 unsigned id = diagnostic().getDiagnosticIDs()->getCustomDiagID(level, err); |
| 97 DiagnosticBuilder builder = diagnostic().Report(full, id); | 94 DiagnosticBuilder builder = diagnostic().Report(full, id); |
| 98 | 95 |
| 99 } | 96 } |
| 100 | 97 |
| 101 bool ChromeClassTester::InBannedDirectory(SourceLocation loc) { | 98 ChromeClassTester::LocationType ChromeClassTester::ClassifyLocation( |
| 99 SourceLocation loc) { |
| 102 if (instance().getSourceManager().isInSystemHeader(loc)) | 100 if (instance().getSourceManager().isInSystemHeader(loc)) |
| 103 return true; | 101 return LocationType::kThirdParty; |
| 104 | 102 |
| 105 std::string filename; | 103 std::string filename; |
| 106 if (!GetFilename(loc, &filename)) { | 104 if (!GetFilename(loc, &filename)) { |
| 107 // If the filename cannot be determined, simply treat this as a banned | 105 // If the filename cannot be determined, simply treat this as a banned |
| 108 // location, instead of going through the full lookup process. | 106 // location, instead of going through the full lookup process. |
| 109 return true; | 107 return LocationType::kThirdParty; |
| 110 } | 108 } |
| 111 | 109 |
| 112 // We need to special case scratch space; which is where clang does its | 110 // We need to special case scratch space; which is where clang does its |
| 113 // macro expansion. We explicitly want to allow people to do otherwise bad | 111 // macro expansion. We explicitly want to allow people to do otherwise bad |
| 114 // things through macros that were defined due to third party libraries. | 112 // things through macros that were defined due to third party libraries. |
| 115 if (filename == "<scratch space>") | 113 if (filename == "<scratch space>") |
| 116 return true; | 114 return LocationType::kThirdParty; |
| 117 | 115 |
| 118 // Don't complain about autogenerated protobuf files. | 116 // Don't complain about autogenerated protobuf files. |
| 119 if (ends_with(filename, ".pb.h")) { | 117 if (ends_with(filename, ".pb.h")) |
| 120 return true; | 118 return LocationType::kThirdParty; |
| 121 } | |
| 122 | 119 |
| 123 #if defined(LLVM_ON_UNIX) | 120 #if defined(LLVM_ON_UNIX) |
| 124 // Resolve the symlinktastic relative path and make it absolute. | 121 // Resolve the symlinktastic relative path and make it absolute. |
| 125 char resolvedPath[MAXPATHLEN]; | 122 char resolvedPath[MAXPATHLEN]; |
| 126 if (options_.no_realpath) { | 123 if (options_.no_realpath) { |
| 127 // Same reason as windows below, but we don't need to do | 124 // Same reason as windows below, but we don't need to do |
| 128 // the '\\' manipulation on linux. | 125 // the '\\' manipulation on linux. |
| 129 filename.insert(filename.begin(), '/'); | 126 filename.insert(filename.begin(), '/'); |
| 130 } else if (realpath(filename.c_str(), resolvedPath)) { | 127 } else if (realpath(filename.c_str(), resolvedPath)) { |
| 131 filename = resolvedPath; | 128 filename = resolvedPath; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 153 size_needed = WideCharToMultiByte(CP_UTF8, 0, full_utf16.data(), -1, | 150 size_needed = WideCharToMultiByte(CP_UTF8, 0, full_utf16.data(), -1, |
| 154 nullptr, 0, nullptr, nullptr); | 151 nullptr, 0, nullptr, nullptr); |
| 155 filename.resize(size_needed); | 152 filename.resize(size_needed); |
| 156 WideCharToMultiByte(CP_UTF8, 0, full_utf16.data(), -1, &filename[0], | 153 WideCharToMultiByte(CP_UTF8, 0, full_utf16.data(), -1, &filename[0], |
| 157 size_needed, nullptr, nullptr); | 154 size_needed, nullptr, nullptr); |
| 158 } | 155 } |
| 159 | 156 |
| 160 std::replace(filename.begin(), filename.end(), '\\', '/'); | 157 std::replace(filename.begin(), filename.end(), '\\', '/'); |
| 161 #endif | 158 #endif |
| 162 | 159 |
| 163 for (const std::string& allowed_dir : allowed_directories_) { | 160 for (const std::string& blink_dir : blink_directories_) { |
| 164 // If any of the allowed directories occur as a component in filename, | 161 // If any of the allowed directories occur as a component in filename, |
| 165 // this file is allowed. | 162 // this file is allowed. |
| 166 assert(allowed_dir.front() == '/' && "Allowed dir must start with '/'"); | 163 assert(blink_dir.front() == '/' && "Allowed dir must start with '/'"); |
| 167 assert(allowed_dir.back() == '/' && "Allowed dir must end with '/'"); | 164 assert(blink_dir.back() == '/' && "Allowed dir must end with '/'"); |
| 168 | 165 |
| 169 if (filename.find(allowed_dir) != std::string::npos) | 166 if (filename.find(blink_dir) != std::string::npos) |
| 170 return false; | 167 return LocationType::kBlink; |
| 171 } | 168 } |
| 172 | 169 |
| 173 for (const std::string& banned_dir : banned_directories_) { | 170 for (const std::string& banned_dir : banned_directories_) { |
| 174 // If any of the banned directories occur as a component in filename, | 171 // If any of the banned directories occur as a component in filename, |
| 175 // this file is rejected. | 172 // this file is rejected. |
| 176 assert(banned_dir.front() == '/' && "Banned dir must start with '/'"); | 173 assert(banned_dir.front() == '/' && "Banned dir must start with '/'"); |
| 177 assert(banned_dir.back() == '/' && "Banned dir must end with '/'"); | 174 assert(banned_dir.back() == '/' && "Banned dir must end with '/'"); |
| 178 | 175 |
| 179 if (filename.find(banned_dir) != std::string::npos) | 176 if (filename.find(banned_dir) != std::string::npos) |
| 180 return true; | 177 return LocationType::kThirdParty; |
| 181 } | 178 } |
| 182 | 179 |
| 183 return false; | 180 return LocationType::kChrome; |
| 184 } | 181 } |
| 185 | 182 |
| 186 bool ChromeClassTester::InBannedNamespace(const Decl* record) { | 183 bool ChromeClassTester::InBannedNamespace(const Decl* record) { |
| 187 std::string n = GetNamespace(record); | 184 std::string n = GetNamespace(record); |
| 188 if (!n.empty()) { | 185 if (!n.empty()) |
| 189 return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n) | 186 return banned_namespaces_.find(n) != banned_namespaces_.end(); |
| 190 != banned_namespaces_.end(); | |
| 191 } | |
| 192 | 187 |
| 193 return false; | 188 return false; |
| 194 } | 189 } |
| 195 | 190 |
| 196 std::string ChromeClassTester::GetNamespace(const Decl* record) { | 191 std::string ChromeClassTester::GetNamespace(const Decl* record) { |
| 197 return GetNamespaceImpl(record->getDeclContext(), ""); | 192 return GetNamespaceImpl(record->getDeclContext(), std::string()); |
| 198 } | 193 } |
| 199 | 194 |
| 200 bool ChromeClassTester::HasIgnoredBases(const CXXRecordDecl* record) { | 195 bool ChromeClassTester::HasIgnoredBases(const CXXRecordDecl* record) { |
| 201 for (const auto& base : record->bases()) { | 196 for (const auto& base : record->bases()) { |
| 202 CXXRecordDecl* base_record = base.getType()->getAsCXXRecordDecl(); | 197 CXXRecordDecl* base_record = base.getType()->getAsCXXRecordDecl(); |
| 203 if (!base_record) | 198 if (!base_record) |
| 204 continue; | 199 continue; |
| 205 | 200 |
| 206 const std::string& base_name = base_record->getQualifiedNameAsString(); | 201 const std::string& base_name = base_record->getQualifiedNameAsString(); |
| 207 if (ignored_base_classes_.count(base_name) > 0) | 202 if (ignored_base_classes_.count(base_name) > 0) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 231 source_manager.getImmediateExpansionRange(record_location).first; | 226 source_manager.getImmediateExpansionRange(record_location).first; |
| 232 } | 227 } |
| 233 | 228 |
| 234 return false; | 229 return false; |
| 235 } | 230 } |
| 236 | 231 |
| 237 void ChromeClassTester::BuildBannedLists() { | 232 void ChromeClassTester::BuildBannedLists() { |
| 238 banned_namespaces_.emplace("std"); | 233 banned_namespaces_.emplace("std"); |
| 239 banned_namespaces_.emplace("__gnu_cxx"); | 234 banned_namespaces_.emplace("__gnu_cxx"); |
| 240 | 235 |
| 241 if (options_.enforce_in_thirdparty_webkit) { | 236 blink_directories_.emplace("/third_party/WebKit/"); |
| 242 allowed_directories_.emplace("/third_party/WebKit/"); | |
| 243 } | |
| 244 | 237 |
| 245 banned_directories_.emplace("/third_party/"); | 238 banned_directories_.emplace("/third_party/"); |
| 246 banned_directories_.emplace("/native_client/"); | 239 banned_directories_.emplace("/native_client/"); |
| 247 banned_directories_.emplace("/breakpad/"); | 240 banned_directories_.emplace("/breakpad/"); |
| 248 banned_directories_.emplace("/courgette/"); | 241 banned_directories_.emplace("/courgette/"); |
| 249 banned_directories_.emplace("/ppapi/"); | 242 banned_directories_.emplace("/ppapi/"); |
| 250 banned_directories_.emplace("/testing/"); | 243 banned_directories_.emplace("/testing/"); |
| 251 banned_directories_.emplace("/v8/"); | 244 banned_directories_.emplace("/v8/"); |
| 252 banned_directories_.emplace("/sdch/"); | 245 banned_directories_.emplace("/sdch/"); |
| 253 banned_directories_.emplace("/frameworks/"); | 246 banned_directories_.emplace("/frameworks/"); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 } | 334 } |
| 342 | 335 |
| 343 *filename = ploc.getFilename(); | 336 *filename = ploc.getFilename(); |
| 344 return true; | 337 return true; |
| 345 } | 338 } |
| 346 | 339 |
| 347 DiagnosticsEngine::Level ChromeClassTester::getErrorLevel() { | 340 DiagnosticsEngine::Level ChromeClassTester::getErrorLevel() { |
| 348 return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error | 341 return diagnostic().getWarningsAsErrors() ? DiagnosticsEngine::Error |
| 349 : DiagnosticsEngine::Warning; | 342 : DiagnosticsEngine::Warning; |
| 350 } | 343 } |
| OLD | NEW |