Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 // Changes Blink-style names to Chrome-style names. Currently transforms: | 5 // Changes Blink-style names to Chrome-style names. Currently transforms: |
| 6 // fields: | 6 // fields: |
| 7 // int m_operationCount => int operation_count_ | 7 // int m_operationCount => int operation_count_ |
| 8 // variables (including parameters): | 8 // variables (including parameters): |
| 9 // int mySuperVariable => int my_super_variable | 9 // int mySuperVariable => int my_super_variable |
| 10 // constants: | 10 // constants: |
| 11 // const int maxThings => const int kMaxThings | 11 // const int maxThings => const int kMaxThings |
| 12 // free functions and methods: | 12 // free functions and methods: |
| 13 // void doThisThenThat() => void DoThisAndThat() | 13 // void doThisThenThat() => void DoThisAndThat() |
| 14 | 14 |
| 15 #include <assert.h> | 15 #include <assert.h> |
| 16 #include <algorithm> | 16 #include <algorithm> |
| 17 #include <fstream> | |
| 17 #include <memory> | 18 #include <memory> |
| 18 #include <set> | 19 #include <set> |
| 20 #include <sstream> | |
| 19 #include <string> | 21 #include <string> |
| 20 | 22 |
| 21 #include "clang/AST/ASTContext.h" | 23 #include "clang/AST/ASTContext.h" |
| 22 #include "clang/ASTMatchers/ASTMatchFinder.h" | 24 #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 23 #include "clang/ASTMatchers/ASTMatchers.h" | 25 #include "clang/ASTMatchers/ASTMatchers.h" |
| 24 #include "clang/ASTMatchers/ASTMatchersMacros.h" | 26 #include "clang/ASTMatchers/ASTMatchersMacros.h" |
| 25 #include "clang/Basic/CharInfo.h" | 27 #include "clang/Basic/CharInfo.h" |
| 26 #include "clang/Basic/SourceManager.h" | 28 #include "clang/Basic/SourceManager.h" |
| 27 #include "clang/Frontend/FrontendActions.h" | 29 #include "clang/Frontend/FrontendActions.h" |
| 28 #include "clang/Lex/Lexer.h" | 30 #include "clang/Lex/Lexer.h" |
| 29 #include "clang/Tooling/CommonOptionsParser.h" | 31 #include "clang/Tooling/CommonOptionsParser.h" |
| 30 #include "clang/Tooling/Refactoring.h" | 32 #include "clang/Tooling/Refactoring.h" |
| 31 #include "clang/Tooling/Tooling.h" | 33 #include "clang/Tooling/Tooling.h" |
| 32 #include "llvm/Support/CommandLine.h" | 34 #include "llvm/Support/CommandLine.h" |
| 33 #include "llvm/Support/TargetSelect.h" | 35 #include "llvm/Support/TargetSelect.h" |
| 34 | 36 |
| 35 #include "EditTracker.h" | 37 #include "EditTracker.h" |
| 36 | 38 |
| 37 using namespace clang::ast_matchers; | 39 using namespace clang::ast_matchers; |
| 38 using clang::tooling::CommonOptionsParser; | 40 using clang::tooling::CommonOptionsParser; |
| 39 using clang::tooling::Replacement; | 41 using clang::tooling::Replacement; |
| 40 using llvm::StringRef; | 42 using llvm::StringRef; |
| 41 | 43 |
| 42 namespace { | 44 namespace { |
| 43 | 45 |
| 44 const char kBlinkFieldPrefix[] = "m_"; | 46 const char kBlinkFieldPrefix[] = "m_"; |
| 45 const char kBlinkStaticMemberPrefix[] = "s_"; | 47 const char kBlinkStaticMemberPrefix[] = "s_"; |
| 46 const char kGeneratedFileRegex[] = "^gen/|/gen/"; | 48 const char kGeneratedFileRegex[] = "^gen/|/gen/"; |
| 49 const char kIdlMethodsParamName[] = "idl-methods"; | |
| 47 | 50 |
| 48 template <typename MatcherType, typename NodeType> | 51 template <typename MatcherType, typename NodeType> |
| 49 bool IsMatching(const MatcherType& matcher, | 52 bool IsMatching(const MatcherType& matcher, |
| 50 const NodeType& node, | 53 const NodeType& node, |
| 51 clang::ASTContext& context) { | 54 clang::ASTContext& context) { |
| 52 return !match(matcher, node, context).empty(); | 55 return !match(matcher, node, context).empty(); |
| 53 } | 56 } |
| 54 | 57 |
| 55 const clang::ast_matchers::internal:: | 58 const clang::ast_matchers::internal:: |
| 56 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> | 59 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 72 return Node.isInstance(); | 75 return Node.isInstance(); |
| 73 } | 76 } |
| 74 | 77 |
| 75 AST_MATCHER_P(clang::FunctionTemplateDecl, | 78 AST_MATCHER_P(clang::FunctionTemplateDecl, |
| 76 templatedDecl, | 79 templatedDecl, |
| 77 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>, | 80 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>, |
| 78 InnerMatcher) { | 81 InnerMatcher) { |
| 79 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder); | 82 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder); |
| 80 } | 83 } |
| 81 | 84 |
| 85 class IdlMatcherState { | |
|
dcheng
2017/01/12 11:00:58
Nit: MethodBlocklist
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
| |
| 86 public: | |
| 87 explicit IdlMatcherState(const std::string& filepath) { | |
| 88 if (filepath.empty()) { | |
| 89 // 1. test_tool.py will run the clang tool without --idl-methods argument. | |
| 90 // 2. If --idl-methods is empty in a normal run, the test-only entries | |
| 91 // should be okay / shouldn't conflict with real Blink methods. | |
|
dcheng
2017/01/12 11:00:58
Perhaps test_tool.py should understand how to pars
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
test_tool.py will look for a file named run
| |
| 92 SetupTestBlacklist(); | |
| 93 } else { | |
| 94 ParseInputFile(filepath); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 bool IsMatching(const clang::CXXMethodDecl& method) const { | |
|
dcheng
2017/01/12 11:00:58
Nit: Contains / Matches / Has
Łukasz Anforowicz
2017/01/12 23:32:01
Done (Contains).
| |
| 99 auto it = method_to_class_to_args_.find(method.getName()); | |
| 100 if (it == method_to_class_to_args_.end()) | |
| 101 return false; | |
| 102 | |
| 103 const clang::CXXRecordDecl* actual_class = method.getParent(); | |
| 104 // Hopefully |getParent()| can find the class even for non-inlined method | |
| 105 // definitions (where CXXRecordDecl is not a parent AST node of | |
| 106 // CXXMethodDecl). | |
| 107 assert(actual_class); | |
| 108 | |
| 109 const std::map<std::string, std::set<int>>& class_to_args = it->second; | |
| 110 auto it2 = class_to_args.find(actual_class->getName()); | |
| 111 if (it2 == class_to_args.end()) | |
| 112 return false; | |
| 113 | |
| 114 std::set<int> expected_number_of_args = it2->second; | |
| 115 int actual_number_of_args = method.param_size(); | |
| 116 if (0 == expected_number_of_args.count(-1) && | |
| 117 0 == expected_number_of_args.count(actual_number_of_args)) | |
| 118 return false; | |
| 119 | |
| 120 // No need to verify here that |actual_class| is in the |blink| namespace - | |
| 121 // this will be done by other matchers elsewhere. | |
| 122 | |
| 123 // TODO(lukasza): Do we need to consider return type and/or param types? | |
| 124 | |
| 125 return true; | |
| 126 } | |
| 127 | |
| 128 private: | |
| 129 void SetupTestBlacklist() { | |
| 130 std::istringstream stream( | |
| 131 "IdlTestClass:::idlTestMethodNoParams:::0\n" | |
| 132 "IdlTestClass:::idlTestMethodOneParam:::1\n" | |
| 133 "IdlTestClass:::idlTestMethodTwoOrThreeParams:::2\n" | |
| 134 "IdlTestClass:::idlTestMethodTwoOrThreeParams:::3\n" | |
| 135 "IdlTestClass:::idlTestMethodAnyNumberOfParams:::-1\n" | |
| 136 "IdlTestClass:::path:::0\n"); // "Get" prefix test. | |
| 137 | |
| 138 ParseInputStream("<test input>", stream); | |
| 139 } | |
| 140 | |
| 141 void ParseInputFile(const std::string& filepath) { | |
| 142 std::ifstream stream(filepath); | |
|
dcheng
2017/01/12 11:00:58
Since this is LLVM/clang code, let's go with the L
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
I like how I automagically/effortlessly got
| |
| 143 ParseInputStream(filepath, stream); | |
| 144 } | |
| 145 | |
| 146 void ParseInputStream(const std::string& filepath, std::istream& stream) { | |
| 147 if (stream.fail()) { | |
| 148 llvm::errs() << "ERROR: Cannot open the file specified in --" | |
| 149 << kIdlMethodsParamName << " argument: " << filepath << "\n"; | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 // Each line is expected to have the following format: | |
| 154 // <class name>:::<method name>:::<number of arguments> | |
| 155 std::string line; | |
| 156 int line_number = 0; | |
| 157 while (std::getline(stream, line)) { | |
| 158 // Split the line into ':::'-delimited parts. | |
| 159 const size_t kExpectedNumberOfParts = 3; | |
| 160 llvm::SmallVector<llvm::StringRef, kExpectedNumberOfParts + 1> parts; | |
|
dcheng
2017/01/12 11:00:58
Why + 1?
Łukasz Anforowicz
2017/01/12 23:32:01
You are right, I should remove it. I tried to be
| |
| 161 llvm::StringRef(line).split(parts, ":::"); | |
| 162 line_number++; | |
| 163 if (parts.size() < kExpectedNumberOfParts) { | |
| 164 llvm::errs() << "ERROR: Parsing error - less than " | |
| 165 << kExpectedNumberOfParts | |
| 166 << " ':::'-delimited parts: " << filepath << ":" | |
| 167 << line_number << ": " << line << "\n"; | |
| 168 continue; | |
| 169 } | |
| 170 | |
| 171 // Parse individual parts. | |
| 172 llvm::StringRef class_name = parts[0]; | |
| 173 llvm::StringRef method_name = parts[1]; | |
| 174 int number_of_method_args; | |
|
Łukasz Anforowicz
2017/01/12 23:32:01
I stopped allowing -1 here as a way to say "any nu
| |
| 175 if (parts[2].getAsInteger(0, number_of_method_args)) { | |
| 176 llvm::errs() << "ERROR: Parsing error - " | |
| 177 << "'" << parts[2] << "' is not an integer: " << filepath | |
| 178 << ":" << line_number << ": " << line << "\n"; | |
|
dcheng
2017/01/12 11:00:59
Should we make errors fatal?
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
I am not sure if asserts are the right way
| |
| 179 continue; | |
| 180 } | |
| 181 | |
| 182 // Store the new entry. | |
| 183 method_to_class_to_args_[method_name][class_name].insert( | |
| 184 number_of_method_args); | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 // Stores methods to blacklist in a map: | |
| 189 // method name -> class name -> set of all allowed numbers of arguments. | |
| 190 std::map<std::string, std::map<std::string, std::set<int>>> | |
|
dcheng
2017/01/12 11:00:58
Perhaps consider StringMap<StringMap<std::set<int>
Łukasz Anforowicz
2017/01/12 23:32:01
Good point. Done.
| |
| 191 method_to_class_to_args_; | |
| 192 }; | |
| 193 | |
| 194 AST_MATCHER_P(clang::CXXMethodDecl, | |
| 195 internalIdlMethod, | |
| 196 IdlMatcherState, | |
| 197 MatcherState) { | |
| 198 return MatcherState.IsMatching(Node); | |
| 199 } | |
| 200 | |
| 201 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl> idlMethod( | |
|
dcheng
2017/01/12 11:00:58
idlMethod => isBlocklistedMethod per the other nit
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
| |
| 202 const std::string& idl_methods_filepath) { | |
| 203 return internalIdlMethod(IdlMatcherState(idl_methods_filepath)); | |
| 204 } | |
| 205 | |
| 82 // If |InnerMatcher| matches |top|, then the returned matcher will match: | 206 // If |InnerMatcher| matches |top|, then the returned matcher will match: |
| 83 // - |top::function| | 207 // - |top::function| |
| 84 // - |top::Class::method| | 208 // - |top::Class::method| |
| 85 // - |top::internal::Class::method| | 209 // - |top::internal::Class::method| |
| 86 AST_MATCHER_P( | 210 AST_MATCHER_P( |
| 87 clang::NestedNameSpecifier, | 211 clang::NestedNameSpecifier, |
| 88 hasTopLevelPrefix, | 212 hasTopLevelPrefix, |
| 89 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>, | 213 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>, |
| 90 InnerMatcher) { | 214 InnerMatcher) { |
| 91 const clang::NestedNameSpecifier* NodeToMatch = &Node; | 215 const clang::NestedNameSpecifier* NodeToMatch = &Node; |
| (...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1024 | 1148 |
| 1025 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 1149 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
| 1026 | 1150 |
| 1027 int main(int argc, const char* argv[]) { | 1151 int main(int argc, const char* argv[]) { |
| 1028 // TODO(dcheng): Clang tooling should do this itself. | 1152 // TODO(dcheng): Clang tooling should do this itself. |
| 1029 // http://llvm.org/bugs/show_bug.cgi?id=21627 | 1153 // http://llvm.org/bugs/show_bug.cgi?id=21627 |
| 1030 llvm::InitializeNativeTarget(); | 1154 llvm::InitializeNativeTarget(); |
| 1031 llvm::InitializeNativeTargetAsmParser(); | 1155 llvm::InitializeNativeTargetAsmParser(); |
| 1032 llvm::cl::OptionCategory category( | 1156 llvm::cl::OptionCategory category( |
| 1033 "rewrite_to_chrome_style: convert Blink style to Chrome style."); | 1157 "rewrite_to_chrome_style: convert Blink style to Chrome style."); |
| 1158 llvm::cl::opt<std::string> idl_methods_file( | |
| 1159 kIdlMethodsParamName, llvm::cl::value_desc("filepath"), | |
| 1160 llvm::cl::desc("file listing method names derived from Web IDL")); | |
|
dcheng
2017/01/12 11:00:58
Nit: let's use a more generic name to indicate wha
Łukasz Anforowicz
2017/01/12 23:32:01
Done.
| |
| 1034 CommonOptionsParser options(argc, argv, category); | 1161 CommonOptionsParser options(argc, argv, category); |
| 1035 clang::tooling::ClangTool tool(options.getCompilations(), | 1162 clang::tooling::ClangTool tool(options.getCompilations(), |
| 1036 options.getSourcePathList()); | 1163 options.getSourcePathList()); |
| 1037 | 1164 |
| 1038 MatchFinder match_finder; | 1165 MatchFinder match_finder; |
| 1039 std::set<Replacement> replacements; | 1166 std::set<Replacement> replacements; |
| 1040 | 1167 |
| 1041 // Blink namespace matchers ======== | 1168 // Blink namespace matchers ======== |
| 1042 auto blink_namespace_decl = | 1169 auto blink_namespace_decl = |
| 1043 namespaceDecl(anyOf(hasName("blink"), hasName("WTF")), | 1170 namespaceDecl(anyOf(hasName("blink"), hasName("WTF")), |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 // struct S { | 1302 // struct S { |
| 1176 // void g(); | 1303 // void g(); |
| 1177 // }; | 1304 // }; |
| 1178 // matches |g|. | 1305 // matches |g|. |
| 1179 // For a method to be considered for rewrite, it must not override something | 1306 // For a method to be considered for rewrite, it must not override something |
| 1180 // that we're not rewriting. Any methods that we would not normally consider | 1307 // that we're not rewriting. Any methods that we would not normally consider |
| 1181 // but that override something we are rewriting should also be rewritten. So | 1308 // but that override something we are rewriting should also be rewritten. So |
| 1182 // we use includeAllOverriddenMethods() to check these rules not just for the | 1309 // we use includeAllOverriddenMethods() to check these rules not just for the |
| 1183 // method being matched but for the methods it overrides also. | 1310 // method being matched but for the methods it overrides also. |
| 1184 auto is_blink_method = includeAllOverriddenMethods( | 1311 auto is_blink_method = includeAllOverriddenMethods( |
| 1185 allOf(in_blink_namespace, unless(isBlacklistedMethod()))); | 1312 allOf(in_blink_namespace, unless(isBlacklistedMethod()), |
| 1313 unless(idlMethod(idl_methods_file)))); | |
| 1186 auto method_decl_matcher = id( | 1314 auto method_decl_matcher = id( |
| 1187 "decl", | 1315 "decl", |
| 1188 cxxMethodDecl( | 1316 cxxMethodDecl( |
| 1189 unless(anyOf( | 1317 unless(anyOf( |
| 1190 // Overloaded operators have special names and should never be | 1318 // Overloaded operators have special names and should never be |
| 1191 // renamed. | 1319 // renamed. |
| 1192 isOverloadedOperator(), | 1320 isOverloadedOperator(), |
| 1193 // Similarly, constructors, destructors, and conversion | 1321 // Similarly, constructors, destructors, and conversion |
| 1194 // functions should not be considered for renaming. | 1322 // functions should not be considered for renaming. |
| 1195 cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())), | 1323 cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())), |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1409 for (const auto& r : replacements) { | 1537 for (const auto& r : replacements) { |
| 1410 std::string replacement_text = r.getReplacementText().str(); | 1538 std::string replacement_text = r.getReplacementText().str(); |
| 1411 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); | 1539 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); |
| 1412 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 1540 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() |
| 1413 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; | 1541 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; |
| 1414 } | 1542 } |
| 1415 llvm::outs() << "==== END EDITS ====\n"; | 1543 llvm::outs() << "==== END EDITS ====\n"; |
| 1416 | 1544 |
| 1417 return 0; | 1545 return 0; |
| 1418 } | 1546 } |
| OLD | NEW |