1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Changes Blink-style names to Chrome-style names. Currently transforms:
6 // fields:
7 // int m_operationCount => int operation_count_
8 // variables (including parameters):
9 // int mySuperVariable => int my_super_variable
10 // constants:
11 // const int maxThings => const int kMaxThings
12 // free functions and methods:
13 // void doThisThenThat() => void DoThisAndThat()
14
15 #include <assert.h>
16 #include <algorithm>
17 #include <fstream>
18 #include <memory>
19 #include <string>
20 #include <unordered_map>
21
22 #include "clang/AST/ASTContext.h"
23 #include "clang/ASTMatchers/ASTMatchFinder.h"
24 #include "clang/ASTMatchers/ASTMatchers.h"
25 #include "clang/ASTMatchers/ASTMatchersMacros.h"
26 #include "clang/Basic/CharInfo.h"
27 #include "clang/Basic/SourceManager.h"
28 #include "clang/Frontend/FrontendActions.h"
29 #include "clang/Lex/Lexer.h"
30 #include "clang/Tooling/CommonOptionsParser.h"
31 #include "clang/Tooling/Refactoring.h"
32 #include "clang/Tooling/Tooling.h"
33 #include "llvm/Support/CommandLine.h"
34 #include "llvm/Support/TargetSelect.h"
35
36 #if defined(_WIN32)
37 #include <windows.h>
38 #else
39 #include <sys/file.h>
40 #include <unistd.h>
41 #endif
42
43 using namespace clang::ast_matchers;
44 using clang::tooling::CommonOptionsParser;
45 using clang::tooling::Replacement;
46 using llvm::StringRef;
47
48 namespace {
49
50 const char kBlinkFieldPrefix[] = "m_";
51 const char kBlinkStaticMemberPrefix[] = "s_";
52 const char kGeneratedFileRegex[] = "^gen/|/gen/";
53
54 const clang::ast_matchers::internal::
55 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr>
56 unresolvedMemberExpr;
57
AST_MATCHER(clang::FunctionDecl,isOverloadedOperator)58 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) {
59 return Node.isOverloadedOperator();
60 }
61
AST_MATCHER(clang::CXXMethodDecl,isInstanceMethod)62 AST_MATCHER(clang::CXXMethodDecl, isInstanceMethod) {
63 return Node.isInstance();
64 }
65
AST_MATCHER_P(clang::FunctionTemplateDecl,templatedDecl,clang::ast_matchers::internal::Matcher<clang::FunctionDecl>,InnerMatcher)66 AST_MATCHER_P(clang::FunctionTemplateDecl,
67 templatedDecl,
68 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>,
69 InnerMatcher) {
70 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder);
71 }
72
73 // If |InnerMatcher| matches |top|, then the returned matcher will match:
74 // - |top::function|
75 // - |top::Class::method|
76 // - |top::internal::Class::method|
AST_MATCHER_P(clang::NestedNameSpecifier,hasTopLevelPrefix,clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>,InnerMatcher)77 AST_MATCHER_P(
78 clang::NestedNameSpecifier,
79 hasTopLevelPrefix,
80 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>,
81 InnerMatcher) {
82 const clang::NestedNameSpecifier* NodeToMatch = &Node;
83 while (NodeToMatch->getPrefix())
84 NodeToMatch = NodeToMatch->getPrefix();
85 return InnerMatcher.matches(*NodeToMatch, Finder, Builder);
86 }
87
88 // This will narrow CXXCtorInitializers down for both FieldDecls and
89 // IndirectFieldDecls (ie. anonymous unions and such). In both cases
90 // getAnyMember() will return a FieldDecl which we can match against.
AST_MATCHER_P(clang::CXXCtorInitializer,forAnyField,clang::ast_matchers::internal::Matcher<clang::FieldDecl>,InnerMatcher)91 AST_MATCHER_P(clang::CXXCtorInitializer,
92 forAnyField,
93 clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
94 InnerMatcher) {
95 const clang::FieldDecl* NodeAsDecl = Node.getAnyMember();
96 return (NodeAsDecl != nullptr &&
97 InnerMatcher.matches(*NodeAsDecl, Finder, Builder));
98 }
99
100 // Matches if all the overloads in the lookup set match the provided matcher.
AST_MATCHER_P(clang::OverloadExpr,allOverloadsMatch,clang::ast_matchers::internal::Matcher<clang::NamedDecl>,InnerMatcher)101 AST_MATCHER_P(clang::OverloadExpr,
102 allOverloadsMatch,
103 clang::ast_matchers::internal::Matcher<clang::NamedDecl>,
104 InnerMatcher) {
105 if (Node.getNumDecls() == 0)
106 return false;
107
108 for (clang::NamedDecl* decl : Node.decls()) {
109 if (!InnerMatcher.matches(*decl, Finder, Builder))
110 return false;
111 }
112 return true;
113 }
114
115 template <typename T>
MatchAllOverriddenMethods(const clang::CXXMethodDecl & decl,T && inner_matcher,clang::ast_matchers::internal::ASTMatchFinder * finder,clang::ast_matchers::internal::BoundNodesTreeBuilder * builder)116 bool MatchAllOverriddenMethods(
117 const clang::CXXMethodDecl& decl,
118 T&& inner_matcher,
119 clang::ast_matchers::internal::ASTMatchFinder* finder,
120 clang::ast_matchers::internal::BoundNodesTreeBuilder* builder) {
121 bool override_matches = false;
122 bool override_not_matches = false;
123
124 for (auto it = decl.begin_overridden_methods();
125 it != decl.end_overridden_methods(); ++it) {
126 if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder))
127 override_matches = true;
128 else
129 override_not_matches = true;
130 }
131
132 // If this fires we have a class overriding a method that matches, and a
133 // method that does not match the inner matcher. In that case we will match
134 // one ancestor method but not the other. If we rename one of the and not the
135 // other it will break what this class overrides, disconnecting it from the
136 // one we did not rename which creates a behaviour change. So assert and
137 // demand the user to fix the code first (or add the method to our
138 // blacklist T_T).
139 if (override_matches || override_not_matches)
140 assert(override_matches != override_not_matches);
141
142 // If the method overrides something that doesn't match, so the method itself
143 // doesn't match.
144 if (override_not_matches)
145 return false;
146 // If the method overrides something that matches, so the method ifself
147 // matches.
148 if (override_matches)
149 return true;
150
151 return inner_matcher.matches(decl, finder, builder);
152 }
153
AST_MATCHER_P(clang::CXXMethodDecl,includeAllOverriddenMethods,clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,InnerMatcher)154 AST_MATCHER_P(clang::CXXMethodDecl,
155 includeAllOverriddenMethods,
156 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,
157 InnerMatcher) {
158 return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder);
159 }
160
IsMethodOverrideOf(const clang::CXXMethodDecl & decl,const char * class_name)161 bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl,
162 const char* class_name) {
163 if (decl.getParent()->getQualifiedNameAsString() == class_name)
164 return true;
165 for (auto it = decl.begin_overridden_methods();
166 it != decl.end_overridden_methods(); ++it) {
167 if (IsMethodOverrideOf(**it, class_name))
168 return true;
169 }
170 return false;
171 }
172
IsBlacklistedFunction(const clang::FunctionDecl & decl)173 bool IsBlacklistedFunction(const clang::FunctionDecl& decl) {
174 // swap() functions should match the signature of std::swap for ADL tricks.
175 return decl.getName() == "swap";
176 }
177
IsBlacklistedMethod(const clang::CXXMethodDecl & decl)178 bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) {
179 if (decl.isStatic())
180 return false;
181
182 clang::StringRef name = decl.getName();
183
184 // These methods should never be renamed.
185 static const char* kBlacklistMethods[] = {"trace", "traceImpl", "lock",
186 "unlock", "try_lock"};
187 for (const auto& b : kBlacklistMethods) {
188 if (name == b)
189 return true;
190 }
191
192 // Iterator methods shouldn't be renamed to work with stl and range-for
193 // loops.
194 std::string ret_type = decl.getReturnType().getAsString();
195 if (ret_type.find("iterator") != std::string::npos ||
196 ret_type.find("Iterator") != std::string::npos) {
197 static const char* kIteratorBlacklist[] = {"begin", "end", "rbegin",
198 "rend"};
199 for (const auto& b : kIteratorBlacklist) {
200 if (name == b)
201 return true;
202 }
203 }
204
205 // Subclasses of InspectorAgent will subclass "disable()" from both blink and
206 // from gen/, which is problematic, but DevTools folks don't want to rename
207 // it or split this up. So don't rename it at all.
208 if (name.equals("disable") &&
209 IsMethodOverrideOf(decl, "blink::InspectorAgent"))
210 return true;
211
212 return false;
213 }
214
AST_MATCHER(clang::FunctionDecl,isBlacklistedFunction)215 AST_MATCHER(clang::FunctionDecl, isBlacklistedFunction) {
216 return IsBlacklistedFunction(Node);
217 }
218
AST_MATCHER(clang::CXXMethodDecl,isBlacklistedMethod)219 AST_MATCHER(clang::CXXMethodDecl, isBlacklistedMethod) {
220 return IsBlacklistedMethod(Node);
221 }
222
223 // Helper to convert from a camelCaseName to camel_case_name. It uses some
224 // heuristics to try to handle acronyms in camel case names correctly.
CamelCaseToUnderscoreCase(StringRef input)225 std::string CamelCaseToUnderscoreCase(StringRef input) {
226 std::string output;
227 bool needs_underscore = false;
228 bool was_lowercase = false;
229 bool was_uppercase = false;
230 bool first_char = true;
231 // Iterate in reverse to minimize the amount of backtracking.
232 for (const unsigned char* i = input.bytes_end() - 1; i >= input.bytes_begin();
233 --i) {
234 char c = *i;
235 bool is_lowercase = clang::isLowercase(c);
236 bool is_uppercase = clang::isUppercase(c);
237 c = clang::toLowercase(c);
238 // Transitioning from upper to lower case requires an underscore. This is
239 // needed to handle names with acronyms, e.g. handledHTTPRequest needs a '_'
240 // in 'dH'. This is a complement to the non-acronym case further down.
241 if (was_uppercase && is_lowercase)
242 needs_underscore = true;
243 if (needs_underscore) {
244 output += '_';
245 needs_underscore = false;
246 }
247 output += c;
248 // Handles the non-acronym case: transitioning from lower to upper case
249 // requires an underscore when emitting the next character, e.g. didLoad
250 // needs a '_' in 'dL'.
251 if (!first_char && was_lowercase && is_uppercase)
252 needs_underscore = true;
253 was_lowercase = is_lowercase;
254 was_uppercase = is_uppercase;
255 first_char = false;
256 }
257 std::reverse(output.begin(), output.end());
258 return output;
259 }
260
IsProbablyConst(const clang::VarDecl & decl,const clang::ASTContext & context)261 bool IsProbablyConst(const clang::VarDecl& decl,
262 const clang::ASTContext& context) {
263 clang::QualType type = decl.getType();
264 if (!type.isConstQualified())
265 return false;
266
267 if (type.isVolatileQualified())
268 return false;
269
270 // http://google.github.io/styleguide/cppguide.html#Constant_Names
271 // Static variables that are const-qualified should use kConstantStyle naming.
272 if (decl.getStorageDuration() == clang::SD_Static)
273 return true;
274
275 const clang::Expr* initializer = decl.getInit();
276 if (!initializer)
277 return false;
278
279 // If the expression is dependent on a template input, then we are not
280 // sure if it can be compile-time generated as calling isEvaluatable() is
281 // not valid on |initializer|.
282 // TODO(crbug.com/581218): We could probably look at each compiled
283 // instantiation of the template and see if they are all compile-time
284 // isEvaluable().
285 if (initializer->isInstantiationDependent())
286 return false;
287
288 // If the expression can be evaluated at compile time, then it should have a
289 // kFoo style name. Otherwise, not.
290 return initializer->isEvaluatable(context);
291 }
292
AST_MATCHER_P(clang::QualType,hasString,std::string,ExpectedString)293 AST_MATCHER_P(clang::QualType, hasString, std::string, ExpectedString) {
294 return ExpectedString == Node.getAsString();
295 }
296
GetNameForDecl(const clang::FunctionDecl & decl,clang::ASTContext & context,std::string & name)297 bool GetNameForDecl(const clang::FunctionDecl& decl,
298 clang::ASTContext& context,
299 std::string& name) {
300 name = decl.getName().str();
301 name[0] = clang::toUppercase(name[0]);
302
303 // Given
304 // class Foo {};
305 // using Bar = Foo;
306 // Bar f1(); // <- |Bar| would be matched by hasString("Bar") below.
307 // Bar f2(); // <- |Bar| would be matched by hasName("Foo") below.
308 // |type_with_same_name_as_function| matcher matches Bar and Foo return types.
309 auto type_with_same_name_as_function = qualType(anyOf(
310 hasString(name), // hasString matches the type as spelled (Bar above).
311 hasDeclaration(namedDecl(hasName(name))))); // hasDeclaration matches
312 // resolved type (Foo above).
313 // |type_containing_same_name_as_function| matcher will match all of the
314 // return types below:
315 // - Foo foo() // Direct application of |type_with_same_name_as_function|.
316 // - Foo* foo() // |hasDescendant| traverses references/pointers.
317 // - RefPtr<Foo> foo() // |hasDescendant| traverses template arguments.
318 auto type_containing_same_name_as_function =
319 qualType(anyOf(type_with_same_name_as_function,
320 hasDescendant(type_with_same_name_as_function)));
321 // https://crbug.com/582312: Prepend "Get" if method name conflicts with
322 // return type.
323 auto conflict_matcher =
324 functionDecl(returns(type_containing_same_name_as_function));
325 if (!match(conflict_matcher, decl, context).empty())
326 name = "Get" + name;
327
328 return true;
329 }
330
GetNameForDecl(const clang::EnumConstantDecl & decl,clang::ASTContext & context,std::string & name)331 bool GetNameForDecl(const clang::EnumConstantDecl& decl,
332 clang::ASTContext& context,
333 std::string& name) {
334 StringRef original_name = decl.getName();
335
336 // If it's already correct leave it alone.
337 if (original_name.size() >= 2 && original_name[0] == 'k' &&
338 clang::isUppercase(original_name[1]))
339 return false;
340
341 bool is_shouty = true;
342 for (char c : original_name) {
343 if (!clang::isUppercase(c) && !clang::isDigit(c) && c != '_') {
344 is_shouty = false;
345 break;
346 }
347 }
348
349 if (is_shouty)
350 return false;
351
352 name = 'k'; // k prefix on enum values.
353 name += original_name;
354 name[1] = clang::toUppercase(name[1]);
355 return true;
356 }
357
GetNameForDecl(const clang::FieldDecl & decl,clang::ASTContext & context,std::string & name)358 bool GetNameForDecl(const clang::FieldDecl& decl,
359 clang::ASTContext& context,
360 std::string& name) {
361 StringRef original_name = decl.getName();
362 bool member_prefix = original_name.startswith(kBlinkFieldPrefix);
363
364 StringRef rename_part = !member_prefix
365 ? original_name
366 : original_name.substr(strlen(kBlinkFieldPrefix));
367 name = CamelCaseToUnderscoreCase(rename_part);
368
369 // Assume that prefix of m_ was intentional and always replace it with a
370 // suffix _.
371 if (member_prefix && name.back() != '_')
372 name += '_';
373
374 return true;
375 }
376
GetNameForDecl(const clang::VarDecl & decl,clang::ASTContext & context,std::string & name)377 bool GetNameForDecl(const clang::VarDecl& decl,
378 clang::ASTContext& context,
379 std::string& name) {
380 StringRef original_name = decl.getName();
381
382 // Nothing to do for unnamed parameters.
383 if (clang::isa<clang::ParmVarDecl>(decl)) {
384 if (original_name.empty())
385 return false;
386
387 // Check if |decl| and |decl.getLocation| are in sync. We need to skip
388 // out-of-sync ParmVarDecls to avoid renaming buggy ParmVarDecls that
389 // 1) have decl.getLocation() pointing at a parameter declaration without a
390 // name, but 2) have decl.getName() retained from a template specialization
391 // of a method. See also: https://llvm.org/bugs/show_bug.cgi?id=29145
392 clang::SourceLocation loc =
393 context.getSourceManager().getSpellingLoc(decl.getLocation());
394 auto parents = context.getParents(decl);
395 bool is_child_location_within_parent_source_range = std::all_of(
396 parents.begin(), parents.end(),
397 [&loc](const clang::ast_type_traits::DynTypedNode& parent) {
398 clang::SourceLocation begin = parent.getSourceRange().getBegin();
399 clang::SourceLocation end = parent.getSourceRange().getEnd();
400 return (begin < loc) && (loc < end);
401 });
402 if (!is_child_location_within_parent_source_range)
403 return false;
404 }
405
406 // static class members match against VarDecls. Blink style dictates that
407 // these should be prefixed with `s_`, so strip that off. Also check for `m_`
408 // and strip that off too, for code that accidentally uses the wrong prefix.
409 if (original_name.startswith(kBlinkStaticMemberPrefix))
410 original_name = original_name.substr(strlen(kBlinkStaticMemberPrefix));
411 else if (original_name.startswith(kBlinkFieldPrefix))
412 original_name = original_name.substr(strlen(kBlinkFieldPrefix));
413
414 bool is_const = IsProbablyConst(decl, context);
415 if (is_const) {
416 // Don't try to rename constants that already conform to Chrome style.
417 if (original_name.size() >= 2 && original_name[0] == 'k' &&
418 clang::isUppercase(original_name[1]))
419 return false;
420
421 name = 'k';
422 name.append(original_name.data(), original_name.size());
423 name[1] = clang::toUppercase(name[1]);
424 } else {
425 name = CamelCaseToUnderscoreCase(original_name);
426
427 // Non-const variables with static storage duration at namespace scope are
428 // prefixed with `g_' to reduce the likelihood of a naming collision.
429 const clang::DeclContext* decl_context = decl.getDeclContext();
430 if (name.find("g_") != 0 && decl.hasGlobalStorage() &&
431 decl_context->isNamespace())
432 name.insert(0, "g_");
433 }
434
435 // Static members end with _ just like other members, but constants should
436 // not.
437 if (!is_const && decl.isStaticDataMember()) {
438 name += '_';
439 }
440
441 return true;
442 }
443
GetNameForDecl(const clang::FunctionTemplateDecl & decl,clang::ASTContext & context,std::string & name)444 bool GetNameForDecl(const clang::FunctionTemplateDecl& decl,
445 clang::ASTContext& context,
446 std::string& name) {
447 clang::FunctionDecl* templated_function = decl.getTemplatedDecl();
448 return GetNameForDecl(*templated_function, context, name);
449 }
450
GetNameForDecl(const clang::NamedDecl & decl,clang::ASTContext & context,std::string & name)451 bool GetNameForDecl(const clang::NamedDecl& decl,
452 clang::ASTContext& context,
453 std::string& name) {
454 if (auto* function = clang::dyn_cast<clang::FunctionDecl>(&decl))
455 return GetNameForDecl(*function, context, name);
456 if (auto* var = clang::dyn_cast<clang::VarDecl>(&decl))
457 return GetNameForDecl(*var, context, name);
458 if (auto* field = clang::dyn_cast<clang::FieldDecl>(&decl))
459 return GetNameForDecl(*field, context, name);
460 if (auto* function_template =
461 clang::dyn_cast<clang::FunctionTemplateDecl>(&decl))
462 return GetNameForDecl(*function_template, context, name);
463 if (auto* enumc = clang::dyn_cast<clang::EnumConstantDecl>(&decl))
464 return GetNameForDecl(*enumc, context, name);
465
466 return false;
467 }
468
GetNameForDecl(const clang::UsingDecl & decl,clang::ASTContext & context,std::string & name)469 bool GetNameForDecl(const clang::UsingDecl& decl,
470 clang::ASTContext& context,
471 std::string& name) {
472 assert(decl.shadow_size() > 0);
473
474 // If a using declaration's targeted declaration is a set of overloaded
475 // functions, it can introduce multiple shadowed declarations. Just using the
476 // first one is OK, since overloaded functions have the same name, by
477 // definition.
478 return GetNameForDecl(*decl.shadow_begin()->getTargetDecl(), context, name);
479 }
480
481 template <typename Type>
482 struct TargetNodeTraits;
483
484 template <>
485 struct TargetNodeTraits<clang::NamedDecl> {
GetLoc__anonac2fe4870111::TargetNodeTraits486 static clang::SourceLocation GetLoc(const clang::NamedDecl& decl) {
487 return decl.getLocation();
488 }
GetName__anonac2fe4870111::TargetNodeTraits489 static const char* GetName() { return "decl"; }
GetType__anonac2fe4870111::TargetNodeTraits490 static const char* GetType() { return "NamedDecl"; }
491 };
492
493 template <>
494 struct TargetNodeTraits<clang::MemberExpr> {
GetLoc__anonac2fe4870111::TargetNodeTraits495 static clang::SourceLocation GetLoc(const clang::MemberExpr& expr) {
496 return expr.getMemberLoc();
497 }
GetName__anonac2fe4870111::TargetNodeTraits498 static const char* GetName() { return "expr"; }
GetType__anonac2fe4870111::TargetNodeTraits499 static const char* GetType() { return "MemberExpr"; }
500 };
501
502 template <>
503 struct TargetNodeTraits<clang::DeclRefExpr> {
GetLoc__anonac2fe4870111::TargetNodeTraits504 static clang::SourceLocation GetLoc(const clang::DeclRefExpr& expr) {
505 return expr.getLocation();
506 }
GetName__anonac2fe4870111::TargetNodeTraits507 static const char* GetName() { return "expr"; }
GetType__anonac2fe4870111::TargetNodeTraits508 static const char* GetType() { return "DeclRefExpr"; }
509 };
510
511 template <>
512 struct TargetNodeTraits<clang::CXXCtorInitializer> {
GetLoc__anonac2fe4870111::TargetNodeTraits513 static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) {
514 assert(init.isWritten());
515 return init.getSourceLocation();
516 }
GetName__anonac2fe4870111::TargetNodeTraits517 static const char* GetName() { return "initializer"; }
GetType__anonac2fe4870111::TargetNodeTraits518 static const char* GetType() { return "CXXCtorInitializer"; }
519 };
520
521 template <>
522 struct TargetNodeTraits<clang::UnresolvedLookupExpr> {
GetLoc__anonac2fe4870111::TargetNodeTraits523 static clang::SourceLocation GetLoc(const clang::UnresolvedLookupExpr& expr) {
524 return expr.getNameLoc();
525 }
GetName__anonac2fe4870111::TargetNodeTraits526 static const char* GetName() { return "expr"; }
GetType__anonac2fe4870111::TargetNodeTraits527 static const char* GetType() { return "UnresolvedLookupExpr"; }
528 };
529
530 template <>
531 struct TargetNodeTraits<clang::UnresolvedMemberExpr> {
GetLoc__anonac2fe4870111::TargetNodeTraits532 static clang::SourceLocation GetLoc(const clang::UnresolvedMemberExpr& expr) {
533 return expr.getMemberLoc();
534 }
GetName__anonac2fe4870111::TargetNodeTraits535 static const char* GetName() { return "expr"; }
GetType__anonac2fe4870111::TargetNodeTraits536 static const char* GetType() { return "UnresolvedMemberExpr"; }
537 };
538
539 template <typename DeclNode, typename TargetNode>
540 class RewriterBase : public MatchFinder::MatchCallback {
541 public:
RewriterBase(std::set<Replacement> * replacements)542 explicit RewriterBase(std::set<Replacement>* replacements)
543 : replacements_(replacements) {}
544
run(const MatchFinder::MatchResult & result)545 void run(const MatchFinder::MatchResult& result) override {
546 const DeclNode* decl = result.Nodes.getNodeAs<DeclNode>("decl");
547 // If false, there's no name to be renamed.
548 if (!decl->getIdentifier())
549 return;
550 clang::SourceLocation decl_loc =
551 TargetNodeTraits<clang::NamedDecl>::GetLoc(*decl);
552 if (decl_loc.isMacroID()) {
553 // Get the location of the spelling of the declaration. If token pasting
554 // was used this will be in "scratch space" and we don't know how to get
555 // from there back to/ the actual macro with the foo##bar text. So just
556 // don't replace in that case.
557 clang::SourceLocation spell =
558 result.SourceManager->getSpellingLoc(decl_loc);
559 if (strcmp(result.SourceManager->getBufferName(spell),
560 "<scratch space>") == 0)
561 return;
562 }
563 clang::ASTContext* context = result.Context;
564 std::string new_name;
565 if (!GetNameForDecl(*decl, *context, new_name))
566 return; // If false, the name was not suitable for renaming.
567 llvm::StringRef old_name = decl->getName();
568 if (old_name == new_name)
569 return;
570 clang::SourceLocation loc = TargetNodeTraits<TargetNode>::GetLoc(
571 *result.Nodes.getNodeAs<TargetNode>(
572 TargetNodeTraits<TargetNode>::GetName()));
573 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(loc);
574 replacements_->emplace(*result.SourceManager, range, new_name);
575 replacement_names_.emplace(old_name.str(), std::move(new_name));
576 }
577
replacement_names() const578 const std::unordered_map<std::string, std::string>& replacement_names()
579 const {
580 return replacement_names_;
581 }
582
583 private:
584 std::set<Replacement>* const replacements_;
585 std::unordered_map<std::string, std::string> replacement_names_;
586 };
587
588 using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>;
589 using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>;
590 using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>;
591 using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>;
592 using FieldDeclRefRewriter = RewriterBase<clang::FieldDecl, clang::DeclRefExpr>;
593 using FunctionDeclRewriter =
594 RewriterBase<clang::FunctionDecl, clang::NamedDecl>;
595 using FunctionRefRewriter =
596 RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>;
597 using ConstructorInitializerRewriter =
598 RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>;
599
600 using MethodDeclRewriter = RewriterBase<clang::CXXMethodDecl, clang::NamedDecl>;
601 using MethodRefRewriter =
602 RewriterBase<clang::CXXMethodDecl, clang::DeclRefExpr>;
603 using MethodMemberRewriter =
604 RewriterBase<clang::CXXMethodDecl, clang::MemberExpr>;
605
606 using EnumConstantDeclRewriter =
607 RewriterBase<clang::EnumConstantDecl, clang::NamedDecl>;
608 using EnumConstantDeclRefRewriter =
609 RewriterBase<clang::EnumConstantDecl, clang::DeclRefExpr>;
610
611 using UnresolvedLookupRewriter =
612 RewriterBase<clang::NamedDecl, clang::UnresolvedLookupExpr>;
613 using UnresolvedMemberRewriter =
614 RewriterBase<clang::NamedDecl, clang::UnresolvedMemberExpr>;
615
616 using UsingDeclRewriter = RewriterBase<clang::UsingDecl, clang::NamedDecl>;
617
618 } // namespace
619
620 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
621
main(int argc,const char * argv[])622 int main(int argc, const char* argv[]) {
623 // TODO(dcheng): Clang tooling should do this itself.
624 // http://llvm.org/bugs/show_bug.cgi?id=21627
625 llvm::InitializeNativeTarget();
626 llvm::InitializeNativeTargetAsmParser();
627 llvm::cl::OptionCategory category(
628 "rewrite_to_chrome_style: convert Blink style to Chrome style.");
629 CommonOptionsParser options(argc, argv, category);
630 clang::tooling::ClangTool tool(options.getCompilations(),
631 options.getSourcePathList());
632
633 MatchFinder match_finder;
634 std::set<Replacement> replacements;
635
636 // Blink namespace matchers ========
637 auto blink_namespace_decl =
638 namespaceDecl(anyOf(hasName("blink"), hasName("WTF")),
639 hasParent(translationUnitDecl()));
640
641 // Given top-level compilation unit:
642 // namespace WTF {
643 // void foo() {}
644 // }
645 // matches |foo|.
646 auto decl_under_blink_namespace = decl(hasAncestor(blink_namespace_decl));
647
648 // Given top-level compilation unit:
649 // void WTF::function() {}
650 // void WTF::Class::method() {}
651 // matches |WTF::function| and |WTF::Class::method| decls.
652 auto decl_has_qualifier_to_blink_namespace =
653 declaratorDecl(has(nestedNameSpecifier(
654 hasTopLevelPrefix(specifiesNamespace(blink_namespace_decl)))));
655
656 auto in_blink_namespace = decl(
657 anyOf(decl_under_blink_namespace, decl_has_qualifier_to_blink_namespace,
658 hasAncestor(decl_has_qualifier_to_blink_namespace)),
659 unless(isExpansionInFileMatching(kGeneratedFileRegex)));
660
661 // Field, variable, and enum declarations ========
662 // Given
663 // int x;
664 // struct S {
665 // int y;
666 // enum { VALUE };
667 // };
668 // matches |x|, |y|, and |VALUE|.
669 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace));
670 auto is_type_trait_value =
671 varDecl(hasName("value"), hasStaticStorageDuration(), isPublic(),
672 hasType(isConstQualified()), hasType(type(anyOf(
673 booleanType(), enumType()))),
674 unless(hasAncestor(recordDecl(
675 has(cxxMethodDecl(isUserProvided(), isInstanceMethod()))))));
676 auto var_decl_matcher =
677 id("decl", varDecl(in_blink_namespace, unless(is_type_trait_value)));
678 auto enum_member_decl_matcher =
679 id("decl", enumConstantDecl(in_blink_namespace));
680
681 FieldDeclRewriter field_decl_rewriter(&replacements);
682 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter);
683
684 VarDeclRewriter var_decl_rewriter(&replacements);
685 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter);
686
687 EnumConstantDeclRewriter enum_member_decl_rewriter(&replacements);
688 match_finder.addMatcher(enum_member_decl_matcher, &enum_member_decl_rewriter);
689
690 // Field, variable, and enum references ========
691 // Given
692 // bool x = true;
693 // if (x) {
694 // ...
695 // }
696 // matches |x| in if (x).
697 auto member_matcher = id(
698 "expr",
699 memberExpr(
700 member(field_decl_matcher),
701 // Needed to avoid matching member references in functions (which will
702 // be an ancestor of the member reference) synthesized by the
703 // compiler, such as a synthesized copy constructor.
704 // This skips explicitly defaulted functions as well, but that's OK:
705 // there's nothing interesting to rewrite in those either.
706 unless(hasAncestor(functionDecl(isDefaulted())))));
707 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher)));
708 auto enum_member_ref_matcher =
709 id("expr", declRefExpr(to(enum_member_decl_matcher)));
710
711 MemberRewriter member_rewriter(&replacements);
712 match_finder.addMatcher(member_matcher, &member_rewriter);
713
714 DeclRefRewriter decl_ref_rewriter(&replacements);
715 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter);
716
717 EnumConstantDeclRefRewriter enum_member_ref_rewriter(&replacements);
718 match_finder.addMatcher(enum_member_ref_matcher, &enum_member_ref_rewriter);
719
720 // Member references in a non-member context ========
721 // Given
722 // struct S {
723 // typedef int U::*UnspecifiedBoolType;
724 // operator UnspecifiedBoolType() { return s_ ? &U::s_ : 0; }
725 // int s_;
726 // };
727 // matches |&U::s_| but not |s_|.
728 auto member_ref_matcher = id("expr", declRefExpr(to(field_decl_matcher)));
729
730 FieldDeclRefRewriter member_ref_rewriter(&replacements);
731 match_finder.addMatcher(member_ref_matcher, &member_ref_rewriter);
732
733 // Non-method function declarations ========
734 // Given
735 // void f();
736 // struct S {
737 // void g();
738 // };
739 // matches |f| but not |g|.
740 auto function_decl_matcher = id(
741 "decl",
742 functionDecl(
743 unless(anyOf(
744 // Methods are covered by the method matchers.
745 cxxMethodDecl(),
746 // Out-of-line overloaded operators have special names and should
747 // never be renamed.
748 isOverloadedOperator(),
749 // Must be checked after filtering out overloaded operators to
750 // prevent asserts about the identifier not being a simple name.
751 isBlacklistedFunction())),
752 in_blink_namespace));
753 FunctionDeclRewriter function_decl_rewriter(&replacements);
754 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter);
755
756 // Non-method function references ========
757 // Given
758 // f();
759 // void (*p)() = &f;
760 // matches |f()| and |&f|.
761 auto function_ref_matcher = id(
762 "expr", declRefExpr(to(function_decl_matcher),
763 // Ignore template substitutions.
764 unless(hasAncestor(substNonTypeTemplateParmExpr()))));
765 FunctionRefRewriter function_ref_rewriter(&replacements);
766 match_finder.addMatcher(function_ref_matcher, &function_ref_rewriter);
767
768 // Method declarations ========
769 // Given
770 // struct S {
771 // void g();
772 // };
773 // matches |g|.
774 // For a method to be considered for rewrite, it must not override something
775 // that we're not rewriting. Any methods that we would not normally consider
776 // but that override something we are rewriting should also be rewritten. So
777 // we use includeAllOverriddenMethods() to check these rules not just for the
778 // method being matched but for the methods it overrides also.
779 auto is_blink_method = includeAllOverriddenMethods(
780 allOf(in_blink_namespace, unless(isBlacklistedMethod())));
781 auto method_decl_matcher = id(
782 "decl",
783 cxxMethodDecl(
784 unless(anyOf(
785 // Overloaded operators have special names and should never be
786 // renamed.
787 isOverloadedOperator(),
788 // Similarly, constructors, destructors, and conversion
789 // functions should not be considered for renaming.
790 cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())),
791 // Check this last after excluding things, to avoid
792 // asserts about overriding non-blink and blink for the
793 // same method.
794 is_blink_method));
795 MethodDeclRewriter method_decl_rewriter(&replacements);
796 match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter);
797
798 // Method references in a non-member context ========
799 // Given
800 // S s;
801 // s.g();
802 // void (S::*p)() = &S::g;
803 // matches |&S::g| but not |s.g()|.
804 auto method_ref_matcher = id(
805 "expr", declRefExpr(to(method_decl_matcher),
806 // Ignore template substitutions.
807 unless(hasAncestor(substNonTypeTemplateParmExpr()))));
808
809 MethodRefRewriter method_ref_rewriter(&replacements);
810 match_finder.addMatcher(method_ref_matcher, &method_ref_rewriter);
811
812 // Method references in a member context ========
813 // Given
814 // S s;
815 // s.g();
816 // void (S::*p)() = &S::g;
817 // matches |s.g()| but not |&S::g|.
818 auto method_member_matcher =
819 id("expr", memberExpr(member(method_decl_matcher)));
820
821 MethodMemberRewriter method_member_rewriter(&replacements);
822 match_finder.addMatcher(method_member_matcher, &method_member_rewriter);
823
824 // Initializers ========
825 // Given
826 // struct S {
827 // int x;
828 // S() : x(2) {}
829 // };
830 // matches each initializer in the constructor for S.
831 auto constructor_initializer_matcher =
832 cxxConstructorDecl(forEachConstructorInitializer(id(
833 "initializer",
834 cxxCtorInitializer(forAnyField(field_decl_matcher), isWritten()))));
835
836 ConstructorInitializerRewriter constructor_initializer_rewriter(
837 &replacements);
838 match_finder.addMatcher(constructor_initializer_matcher,
839 &constructor_initializer_rewriter);
840
841 // Unresolved lookup expressions ========
842 // Given
843 // template<typename T> void F(T) { }
844 // template<void G(T)> H(T) { }
845 // H<F<int>>(...);
846 // matches |F| in |H<F<int>>|.
847 //
848 // UnresolvedLookupExprs are similar to DeclRefExprs that reference a
849 // FunctionDecl, but are used when a candidate FunctionDecl can't be selected.
850 // This commonly happens inside uninstantiated template definitions for one of
851 // two reasons:
852 //
853 // 1. If the candidate declaration is a dependent FunctionTemplateDecl, the
854 // actual overload can't be selected until template instantiation time.
855 // 2. Alternatively, there might be multiple declarations in the candidate set
856 // if the candidate function has overloads. If any of the function
857 // arguments has a dependent type, then the actual overload can't be
858 // selected until instantiation time either.
859 //
860 // Another instance where UnresolvedLookupExprs can appear is in a template
861 // argument list, like the provided example.
862 auto function_template_decl_matcher =
863 id("decl", functionTemplateDecl(templatedDecl(function_decl_matcher)));
864 auto method_template_decl_matcher =
865 id("decl", functionTemplateDecl(templatedDecl(method_decl_matcher)));
866 auto unresolved_lookup_matcher = expr(id(
867 "expr",
868 unresolvedLookupExpr(
869 // In order to automatically rename an unresolved lookup, the lookup
870 // candidates must either all be Blink functions/function templates or
871 // all be Blink methods/method templates. Otherwise, we might end up
872 // in a situation where the naming could change depending on the
873 // selected candidate.
874 anyOf(allOverloadsMatch(anyOf(function_decl_matcher,
875 function_template_decl_matcher)),
876 // Note: this matches references to methods in a non-member
877 // context, e.g. Template<&Class::Method>. This and the
878 // UnresolvedMemberExpr matcher below are analogous to how the
879 // rewriter has both a MemberRefRewriter matcher to rewrite
880 // &T::method and a MethodMemberRewriter matcher to rewriter
881 // t.method().
882 allOverloadsMatch(anyOf(method_decl_matcher,
883 method_template_decl_matcher))))));
884 UnresolvedLookupRewriter unresolved_lookup_rewriter(&replacements);
885 match_finder.addMatcher(unresolved_lookup_matcher,
886 &unresolved_lookup_rewriter);
887
888 // Unresolved member expressions ========
889 // Similar to unresolved lookup expressions, but for methods in a member
890 // context, e.g. var_with_templated_type.Method().
891 auto unresolved_member_matcher = expr(id(
892 "expr",
893 unresolvedMemberExpr(
894 // Similar to UnresolvedLookupExprs, all the candidate methods must be
895 // Blink methods/method templates.
896 allOverloadsMatch(
897 anyOf(method_decl_matcher, method_template_decl_matcher)))));
898 UnresolvedMemberRewriter unresolved_member_rewriter(&replacements);
899 match_finder.addMatcher(unresolved_member_matcher,
900 &unresolved_member_rewriter);
901
902 // Using declarations ========
903 // Given
904 // using blink::X;
905 // matches |using blink::X|.
906 auto using_decl_matcher = id(
907 "decl", usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(anyOf(
908 var_decl_matcher, field_decl_matcher, function_decl_matcher,
909 method_decl_matcher, function_template_decl_matcher,
910 method_template_decl_matcher, enum_member_decl_matcher)))));
911 UsingDeclRewriter using_decl_rewriter(&replacements);
912 match_finder.addMatcher(using_decl_matcher, &using_decl_rewriter);
913
914 std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
915 clang::tooling::newFrontendActionFactory(&match_finder);
916 int result = tool.run(factory.get());
917 if (result != 0)
918 return result;
919
920 #if defined(_WIN32)
921 HANDLE lockfd = CreateFile("rewrite-sym.lock", GENERIC_READ, FILE_SHARE_READ,
922 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
923 OVERLAPPED overlapped = {};
924 LockFileEx(lockfd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &overlapped);
925 #else
926 int lockfd = open("rewrite-sym.lock", O_RDWR | O_CREAT, 0666);
927 while (flock(lockfd, LOCK_EX)) { // :D
928 }
929 #endif
930
931 std::ofstream replacement_db_file("rewrite-sym.txt",
932 std::ios_base::out | std::ios_base::app);
933 for (const auto& p : field_decl_rewriter.replacement_names())
934 replacement_db_file << "var:" << p.first << ":" << p.second << "\n";
935 for (const auto& p : var_decl_rewriter.replacement_names())
936 replacement_db_file << "var:" << p.first << ":" << p.second << "\n";
937 for (const auto& p : enum_member_decl_rewriter.replacement_names())
938 replacement_db_file << "enu:" << p.first << ":" << p.second << "\n";
939 for (const auto& p : function_decl_rewriter.replacement_names())
940 replacement_db_file << "fun:" << p.first << ":" << p.second << "\n";
941 for (const auto& p : method_decl_rewriter.replacement_names())
942 replacement_db_file << "fun:" << p.first << ":" << p.second << "\n";
943 replacement_db_file.close();
944
945 #if defined(_WIN32)
946 UnlockFileEx(lockfd, 0, 1, 0, &overlapped);
947 CloseHandle(lockfd);
948 #else
949 flock(lockfd, LOCK_UN);
950 close(lockfd);
951 #endif
952
953 // Serialization format is documented in tools/clang/scripts/run_tool.py
954 llvm::outs() << "==== BEGIN EDITS ====\n";
955 for (const auto& r : replacements) {
956 std::string replacement_text = r.getReplacementText().str();
957 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
958 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset()
959 << ":::" << r.getLength() << ":::" << replacement_text << "\n";
960 }
961 llvm::outs() << "==== END EDITS ====\n";
962
963 return 0;
964 }
965