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: | 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: | 12 // free functions and methods: |
| 13 // void doThisThenThat() => void DoThisAndThat() | 13 // void doThisThenThat() => void DoThisAndThat() |
| 14 | 14 |
| 15 #include <assert.h> | |
| 15 #include <algorithm> | 16 #include <algorithm> |
| 16 #include <memory> | 17 #include <memory> |
| 17 #include <string> | 18 #include <string> |
| 19 #include <unordered_set> | |
| 18 | 20 |
| 19 #include "clang/AST/ASTContext.h" | 21 #include "clang/AST/ASTContext.h" |
| 20 #include "clang/ASTMatchers/ASTMatchFinder.h" | 22 #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 21 #include "clang/ASTMatchers/ASTMatchers.h" | 23 #include "clang/ASTMatchers/ASTMatchers.h" |
| 22 #include "clang/ASTMatchers/ASTMatchersMacros.h" | 24 #include "clang/ASTMatchers/ASTMatchersMacros.h" |
| 23 #include "clang/Basic/CharInfo.h" | 25 #include "clang/Basic/CharInfo.h" |
| 24 #include "clang/Basic/SourceManager.h" | 26 #include "clang/Basic/SourceManager.h" |
| 25 #include "clang/Frontend/FrontendActions.h" | 27 #include "clang/Frontend/FrontendActions.h" |
| 26 #include "clang/Lex/Lexer.h" | 28 #include "clang/Lex/Lexer.h" |
| 27 #include "clang/Tooling/CommonOptionsParser.h" | 29 #include "clang/Tooling/CommonOptionsParser.h" |
| 28 #include "clang/Tooling/Refactoring.h" | 30 #include "clang/Tooling/Refactoring.h" |
| 29 #include "clang/Tooling/Tooling.h" | 31 #include "clang/Tooling/Tooling.h" |
| 30 #include "llvm/Support/CommandLine.h" | 32 #include "llvm/Support/CommandLine.h" |
| 31 #include "llvm/Support/TargetSelect.h" | 33 #include "llvm/Support/TargetSelect.h" |
| 32 | 34 |
| 33 using namespace clang::ast_matchers; | 35 using namespace clang::ast_matchers; |
| 34 using clang::tooling::CommonOptionsParser; | 36 using clang::tooling::CommonOptionsParser; |
| 35 using clang::tooling::Replacement; | 37 using clang::tooling::Replacement; |
| 36 using clang::tooling::Replacements; | 38 using clang::tooling::Replacements; |
| 37 using llvm::StringRef; | 39 using llvm::StringRef; |
| 38 | 40 |
| 39 namespace { | 41 namespace { |
| 40 | 42 |
| 43 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { | |
| 44 return Node.isOverloadedOperator(); | |
| 45 } | |
| 46 | |
| 41 constexpr char kBlinkFieldPrefix[] = "m_"; | 47 constexpr char kBlinkFieldPrefix[] = "m_"; |
| 42 constexpr char kBlinkStaticMemberPrefix[] = "s_"; | 48 constexpr char kBlinkStaticMemberPrefix[] = "s_"; |
| 43 | 49 |
| 44 bool GetNameForDecl(const clang::FunctionDecl& decl, | 50 bool GetNameForDecl(const clang::FunctionDecl& decl, std::string& name) { |
| 45 clang::ASTContext* context, | |
| 46 std::string& name) { | |
| 47 name = decl.getNameAsString(); | 51 name = decl.getNameAsString(); |
| 48 name[0] = clang::toUppercase(name[0]); | 52 name[0] = clang::toUppercase(name[0]); |
| 49 return true; | 53 return true; |
| 50 } | 54 } |
| 51 | 55 |
| 52 // Helper to convert from a camelCaseName to camel_case_name. It uses some | 56 // Helper to convert from a camelCaseName to camel_case_name. It uses some |
| 53 // heuristics to try to handle acronyms in camel case names correctly. | 57 // heuristics to try to handle acronyms in camel case names correctly. |
| 54 std::string CamelCaseToUnderscoreCase(StringRef input) { | 58 std::string CamelCaseToUnderscoreCase(StringRef input) { |
| 55 std::string output; | 59 std::string output; |
| 56 bool needs_underscore = false; | 60 bool needs_underscore = false; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 76 // needs a '_' in 'dL'. | 80 // needs a '_' in 'dL'. |
| 77 if (i != input.bytes_end() - 1 && was_lowercase && is_uppercase) | 81 if (i != input.bytes_end() - 1 && was_lowercase && is_uppercase) |
| 78 needs_underscore = true; | 82 needs_underscore = true; |
| 79 was_lowercase = is_lowercase; | 83 was_lowercase = is_lowercase; |
| 80 was_uppercase = is_uppercase; | 84 was_uppercase = is_uppercase; |
| 81 } | 85 } |
| 82 std::reverse(output.begin(), output.end()); | 86 std::reverse(output.begin(), output.end()); |
| 83 return output; | 87 return output; |
| 84 } | 88 } |
| 85 | 89 |
| 86 bool GetNameForDecl(const clang::FieldDecl& decl, | 90 bool GetNameForDecl(const clang::FieldDecl& decl, std::string& name) { |
| 87 clang::ASTContext* context, | |
| 88 std::string& name) { | |
| 89 StringRef original_name = decl.getName(); | 91 StringRef original_name = decl.getName(); |
| 90 // Blink style field names are prefixed with `m_`. If this prefix isn't | 92 // Blink style field names are prefixed with `m_`. If this prefix isn't |
| 91 // present, assume it's already been converted to Google style. | 93 // present, assume it's already been converted to Google style. |
| 92 if (original_name.size() < strlen(kBlinkFieldPrefix) || | 94 if (original_name.size() < strlen(kBlinkFieldPrefix) || |
| 93 !original_name.startswith(kBlinkFieldPrefix)) | 95 !original_name.startswith(kBlinkFieldPrefix)) |
| 94 return false; | 96 return false; |
| 95 name = CamelCaseToUnderscoreCase( | 97 name = CamelCaseToUnderscoreCase( |
| 96 original_name.substr(strlen(kBlinkFieldPrefix))); | 98 original_name.substr(strlen(kBlinkFieldPrefix))); |
| 97 // The few examples I could find used struct-style naming with no `_` suffix | 99 // The few examples I could find used struct-style naming with no `_` suffix |
| 98 // for unions. | 100 // for unions. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 return clang::isa<clang::CharacterLiteral>(initializer) || | 132 return clang::isa<clang::CharacterLiteral>(initializer) || |
| 131 clang::isa<clang::CompoundLiteralExpr>(initializer) || | 133 clang::isa<clang::CompoundLiteralExpr>(initializer) || |
| 132 clang::isa<clang::CXXBoolLiteralExpr>(initializer) || | 134 clang::isa<clang::CXXBoolLiteralExpr>(initializer) || |
| 133 clang::isa<clang::CXXNullPtrLiteralExpr>(initializer) || | 135 clang::isa<clang::CXXNullPtrLiteralExpr>(initializer) || |
| 134 clang::isa<clang::FloatingLiteral>(initializer) || | 136 clang::isa<clang::FloatingLiteral>(initializer) || |
| 135 clang::isa<clang::IntegerLiteral>(initializer) || | 137 clang::isa<clang::IntegerLiteral>(initializer) || |
| 136 clang::isa<clang::StringLiteral>(initializer) || | 138 clang::isa<clang::StringLiteral>(initializer) || |
| 137 clang::isa<clang::UserDefinedLiteral>(initializer); | 139 clang::isa<clang::UserDefinedLiteral>(initializer); |
| 138 } | 140 } |
| 139 | 141 |
| 140 bool GetNameForDecl(const clang::VarDecl& decl, | 142 bool GetNameForDecl(const clang::VarDecl& decl, std::string& name) { |
| 141 clang::ASTContext* context, | |
| 142 std::string& name) { | |
| 143 StringRef original_name = decl.getName(); | 143 StringRef original_name = decl.getName(); |
| 144 | 144 |
| 145 // Nothing to do for unnamed parameters. | 145 // Nothing to do for unnamed parameters. |
| 146 if (clang::isa<clang::ParmVarDecl>(decl) && original_name.empty()) | 146 if (clang::isa<clang::ParmVarDecl>(decl) && original_name.empty()) |
| 147 return false; | 147 return false; |
| 148 | 148 |
| 149 // static class members match against VarDecls. Blink style dictates that | 149 // static class members match against VarDecls. Blink style dictates that |
| 150 // these should be prefixed with `s_`, so strip that off. Also check for `m_` | 150 // these should be prefixed with `s_`, so strip that off. Also check for `m_` |
| 151 // and strip that off too, for code that accidentally uses the wrong prefix. | 151 // and strip that off too, for code that accidentally uses the wrong prefix. |
| 152 if (original_name.startswith(kBlinkStaticMemberPrefix)) | 152 if (original_name.startswith(kBlinkStaticMemberPrefix)) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 166 name = CamelCaseToUnderscoreCase(original_name); | 166 name = CamelCaseToUnderscoreCase(original_name); |
| 167 } | 167 } |
| 168 | 168 |
| 169 if (decl.isStaticDataMember()) { | 169 if (decl.isStaticDataMember()) { |
| 170 name += '_'; | 170 name += '_'; |
| 171 } | 171 } |
| 172 | 172 |
| 173 return true; | 173 return true; |
| 174 } | 174 } |
| 175 | 175 |
| 176 template <typename DeclNodeType, typename TargetTraits> | 176 template <typename Type> |
| 177 class RewriterCallbackBase : public MatchFinder::MatchCallback { | 177 struct TargetNodeTraits; |
| 178 | |
| 179 template <> | |
| 180 struct TargetNodeTraits<clang::NamedDecl> { | |
| 181 static constexpr char kName[] = "decl"; | |
| 182 static clang::CharSourceRange GetRange(const clang::NamedDecl& decl) { | |
| 183 return clang::CharSourceRange::getTokenRange(decl.getLocation()); | |
| 184 } | |
| 185 }; | |
| 186 constexpr char TargetNodeTraits<clang::NamedDecl>::kName[]; | |
| 187 | |
| 188 template <> | |
| 189 struct TargetNodeTraits<clang::MemberExpr> { | |
| 190 static constexpr char kName[] = "expr"; | |
| 191 static clang::CharSourceRange GetRange(const clang::MemberExpr& expr) { | |
| 192 return clang::CharSourceRange::getTokenRange(expr.getMemberLoc()); | |
| 193 } | |
| 194 }; | |
| 195 constexpr char TargetNodeTraits<clang::MemberExpr>::kName[]; | |
| 196 | |
| 197 template <> | |
| 198 struct TargetNodeTraits<clang::DeclRefExpr> { | |
| 199 static constexpr char kName[] = "expr"; | |
| 200 static clang::CharSourceRange GetRange(const clang::DeclRefExpr& expr) { | |
| 201 return clang::CharSourceRange::getTokenRange(expr.getLocation()); | |
| 202 } | |
| 203 }; | |
| 204 constexpr char TargetNodeTraits<clang::DeclRefExpr>::kName[]; | |
| 205 | |
| 206 template <> | |
| 207 struct TargetNodeTraits<clang::CXXCtorInitializer> { | |
| 208 static constexpr char kName[] = "initializer"; | |
| 209 static clang::CharSourceRange GetRange( | |
| 210 const clang::CXXCtorInitializer& init) { | |
| 211 return clang::CharSourceRange::getTokenRange(init.getSourceLocation()); | |
| 212 } | |
| 213 }; | |
| 214 constexpr char TargetNodeTraits<clang::CXXCtorInitializer>::kName[]; | |
| 215 | |
| 216 template <typename DeclNode, typename TargetNode> | |
| 217 class RewriterBase : public MatchFinder::MatchCallback { | |
| 178 public: | 218 public: |
| 179 explicit RewriterCallbackBase(Replacements* replacements) | 219 explicit RewriterBase(Replacements* replacements) |
| 180 : replacements_(replacements) {} | 220 : replacements_(replacements) {} |
| 181 virtual void run(const MatchFinder::MatchResult& result) override { | 221 |
| 222 void run(const MatchFinder::MatchResult& result) override { | |
| 182 std::string name; | 223 std::string name; |
| 183 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNodeType>("decl"), | 224 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNode>("decl"), name)) |
| 184 result.Context, name)) | |
| 185 return; | 225 return; |
| 186 replacements_->emplace( | 226 replacements_->emplace(*result.SourceManager, |
| 187 *result.SourceManager, | 227 TargetNodeTraits<TargetNode>::GetRange( |
| 188 TargetTraits::GetRange( | 228 *result.Nodes.getNodeAs<TargetNode>( |
| 189 *result.Nodes.getNodeAs<typename TargetTraits::NodeType>( | 229 TargetNodeTraits<TargetNode>::kName)), |
| 190 TargetTraits::kName)), | 230 name); |
| 191 name); | |
| 192 } | 231 } |
| 193 | 232 |
| 194 private: | 233 private: |
| 195 Replacements* const replacements_; | 234 Replacements* const replacements_; |
| 196 }; | 235 }; |
| 197 | 236 |
| 198 struct DeclTargetTraits { | 237 using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>; |
| 199 using NodeType = clang::NamedDecl; | 238 using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>; |
| 200 static constexpr char kName[] = "decl"; | 239 using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>; |
| 201 static clang::CharSourceRange GetRange(const NodeType& decl) { | 240 using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>; |
| 202 return clang::CharSourceRange::getTokenRange(decl.getLocation()); | 241 using FunctionDeclRewriter = |
| 242 RewriterBase<clang::FunctionDecl, clang::NamedDecl>; | |
| 243 using FunctionRefRewriter = | |
| 244 RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>; | |
| 245 using ConstructorInitializerRewriter = | |
| 246 RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>; | |
| 247 | |
| 248 // Helpers for rewriting methods. The tool needs to detect overrides of Blink | |
| 249 // methods, and uses two matchers to help accomplish this goal: | |
| 250 // - The first matcher matches all method declarations in Blink. When the | |
| 251 // callback rewrites the declaration, it also stores a pointer to the | |
| 252 // canonical declaration, to record it as a Blink method. | |
| 253 // - The second matcher matches all method declarations that are overrides. When | |
| 254 // the callback processes the match, it checks if its overriding a method that | |
| 255 // was marked as a Blink method. If so, it rewrites the declaration. | |
| 256 // - Because an override is determined based on inclusion in the set of Blink | |
| 257 // methods, the overridden methods matcher does not need to filter out special | |
| 258 // member functions: they get filtered out by virtue of the first matcher. | |
| 259 // | |
| 260 // This works because per the documentation on MatchFinder: | |
| 261 // The order of matches is guaranteed to be equivalent to doing a pre-order | |
| 262 // traversal on the AST, and applying the matchers in the order in which they | |
| 263 // were added to the MatchFinder. | |
| 264 // | |
| 265 // Since classes cannot forward declare their base classes, it is guaranteed | |
| 266 // that the base class methods will be seen before processing the overridden | |
| 267 // methods. | |
| 268 class MethodDeclRewriter | |
| 269 : public RewriterBase<clang::CXXMethodDecl, clang::NamedDecl> { | |
| 270 public: | |
| 271 explicit MethodDeclRewriter(Replacements* replacements) | |
| 272 : RewriterBase(replacements) {} | |
| 273 | |
| 274 void run(const MatchFinder::MatchResult& result) override { | |
| 275 const clang::CXXMethodDecl* method_decl = | |
| 276 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl"); | |
| 277 // TODO(dcheng): Does this need to check for the override attribute, or is | |
| 278 // this good enough? | |
| 279 if (method_decl->size_overridden_methods() > 0) { | |
| 280 if (!IsBlinkOverride(method_decl)) | |
| 281 return; | |
| 282 } else { | |
| 283 blink_methods_.emplace(method_decl->getCanonicalDecl()); | |
| 284 } | |
| 285 | |
| 286 RewriterBase::run(result); | |
| 203 } | 287 } |
| 288 | |
| 289 bool IsBlinkOverride(const clang::CXXMethodDecl* decl) const { | |
| 290 assert(decl->size_overridden_methods() > 0); | |
| 291 for (auto it = decl->begin_overridden_methods(); | |
| 292 it != decl->end_overridden_methods(); ++it) { | |
| 293 if (blink_methods_.find((*it)->getCanonicalDecl()) != | |
| 294 blink_methods_.end()) | |
| 295 return true; | |
| 296 } | |
| 297 return false; | |
| 298 } | |
| 299 | |
| 300 private: | |
| 301 std::unordered_set<const clang::CXXMethodDecl*> blink_methods_; | |
| 204 }; | 302 }; |
| 205 constexpr char DeclTargetTraits::kName[]; | |
| 206 | 303 |
| 207 struct ExprTargetTraits { | 304 template <typename RewriterBase> |
|
danakj
2016/01/08 02:02:52
This name is conflicty with a real type. The old n
dcheng
2016/01/08 02:14:01
I thought Base might be too vague, but I'll admit
| |
| 208 using NodeType = clang::Expr; | 305 class FilteringMethodRewriter : public RewriterBase { |
| 209 static constexpr char kName[] = "expr"; | 306 public: |
| 210 static clang::CharSourceRange GetRange(const NodeType& expr) { | 307 FilteringMethodRewriter(const MethodDeclRewriter& decl_rewriter, |
| 211 return clang::CharSourceRange::getTokenRange(expr.getExprLoc()); | 308 Replacements* replacements) |
| 309 : RewriterBase(replacements), decl_rewriter_(decl_rewriter) {} | |
| 310 | |
| 311 void run(const MatchFinder::MatchResult& result) override { | |
| 312 const clang::CXXMethodDecl* method_decl = | |
| 313 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl"); | |
| 314 if (method_decl->size_overridden_methods() > 0 && | |
| 315 !decl_rewriter_.IsBlinkOverride(method_decl)) | |
| 316 return; | |
| 317 RewriterBase::run(result); | |
| 212 } | 318 } |
| 319 | |
| 320 private: | |
| 321 const MethodDeclRewriter& decl_rewriter_; | |
| 213 }; | 322 }; |
| 214 constexpr char ExprTargetTraits::kName[]; | |
| 215 | 323 |
| 216 struct InitializerTargetTraits { | 324 using MethodRefRewriter = FilteringMethodRewriter< |
| 217 using NodeType = clang::CXXCtorInitializer; | 325 RewriterBase<clang::CXXMethodDecl, clang::DeclRefExpr>>; |
| 218 static constexpr char kName[] = "initializer"; | 326 using MethodMemberRewriter = FilteringMethodRewriter< |
| 219 static clang::CharSourceRange GetRange(const NodeType& init) { | 327 RewriterBase<clang::CXXMethodDecl, clang::MemberExpr>>; |
| 220 return clang::CharSourceRange::getTokenRange(init.getSourceLocation()); | |
| 221 } | |
| 222 }; | |
| 223 constexpr char InitializerTargetTraits::kName[]; | |
| 224 | |
| 225 using FunctionDeclRewriterCallback = | |
| 226 RewriterCallbackBase<clang::FunctionDecl, DeclTargetTraits>; | |
| 227 using FieldDeclRewriterCallback = | |
| 228 RewriterCallbackBase<clang::FieldDecl, DeclTargetTraits>; | |
| 229 using VarDeclRewriterCallback = | |
| 230 RewriterCallbackBase<clang::VarDecl, DeclTargetTraits>; | |
| 231 | |
| 232 using CallRewriterCallback = | |
| 233 RewriterCallbackBase<clang::FunctionDecl, ExprTargetTraits>; | |
| 234 using MemberRewriterCallback = | |
| 235 RewriterCallbackBase<clang::FieldDecl, ExprTargetTraits>; | |
| 236 using DeclRefRewriterCallback = | |
| 237 RewriterCallbackBase<clang::VarDecl, ExprTargetTraits>; | |
| 238 | |
| 239 using ConstructorInitializerRewriterCallback = | |
| 240 RewriterCallbackBase<clang::FieldDecl, InitializerTargetTraits>; | |
| 241 | 328 |
| 242 } // namespace | 329 } // namespace |
| 243 | 330 |
| 244 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 331 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
| 245 | 332 |
| 246 int main(int argc, const char* argv[]) { | 333 int main(int argc, const char* argv[]) { |
| 247 // TODO(dcheng): Clang tooling should do this itself. | 334 // TODO(dcheng): Clang tooling should do this itself. |
| 248 // http://llvm.org/bugs/show_bug.cgi?id=21627 | 335 // http://llvm.org/bugs/show_bug.cgi?id=21627 |
| 249 llvm::InitializeNativeTarget(); | 336 llvm::InitializeNativeTarget(); |
| 250 llvm::InitializeNativeTargetAsmParser(); | 337 llvm::InitializeNativeTargetAsmParser(); |
| 251 llvm::cl::OptionCategory category( | 338 llvm::cl::OptionCategory category( |
| 252 "rewrite_to_chrome_style: convert Blink style to Chrome style."); | 339 "rewrite_to_chrome_style: convert Blink style to Chrome style."); |
| 253 CommonOptionsParser options(argc, argv, category); | 340 CommonOptionsParser options(argc, argv, category); |
| 254 clang::tooling::ClangTool tool(options.getCompilations(), | 341 clang::tooling::ClangTool tool(options.getCompilations(), |
| 255 options.getSourcePathList()); | 342 options.getSourcePathList()); |
| 256 | 343 |
| 257 MatchFinder match_finder; | 344 MatchFinder match_finder; |
| 258 Replacements replacements; | 345 Replacements replacements; |
| 259 | 346 |
| 260 auto in_blink_namespace = | 347 auto in_blink_namespace = |
| 261 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); | 348 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); |
| 262 | 349 |
| 263 // Declaration handling (e.g. function definitions and variable definitions): | 350 // Field and variable declarations ======== |
| 264 | 351 // Given |
| 265 // Note: for now, only rewrite standalone functions until the question of JS | 352 // int x; |
| 266 // binding integration for class methods is resolved. | 353 // struct S { |
| 267 // TODO(dcheng): Since classes in public/ aren't directly web-exposed, just go | 354 // int y; |
| 268 // ahead and rewrite those. | 355 // }; |
| 269 auto function_decl_matcher = | 356 // matches |x| and |y|. |
| 270 id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace)); | |
| 271 | |
| 272 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); | 357 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); |
| 273 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); | 358 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); |
| 274 | 359 |
| 275 FunctionDeclRewriterCallback function_decl_rewriter(&replacements); | 360 FieldDeclRewriter field_decl_rewriter(&replacements); |
| 276 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); | |
| 277 FieldDeclRewriterCallback field_decl_rewriter(&replacements); | |
| 278 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); | 361 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); |
| 279 VarDeclRewriterCallback var_decl_rewriter(&replacements); | 362 |
| 363 VarDeclRewriter var_decl_rewriter(&replacements); | |
| 280 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); | 364 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); |
| 281 | 365 |
| 282 // Expression handling (e.g. calling a Blink function or referencing a | 366 // Field and variable references ======== |
| 283 // variable defined in Blink): | 367 // Given |
| 284 auto call_matcher = id("expr", callExpr(callee(function_decl_matcher))); | 368 // bool x = true; |
| 369 // if (x) { | |
| 370 // ... | |
| 371 // } | |
| 372 // matches |x| in if (x). | |
| 285 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); | 373 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); |
| 286 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); | 374 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); |
| 287 | 375 |
| 288 CallRewriterCallback call_rewriter(&replacements); | 376 MemberRewriter member_rewriter(&replacements); |
| 289 match_finder.addMatcher(call_matcher, &call_rewriter); | |
| 290 MemberRewriterCallback member_rewriter(&replacements); | |
| 291 match_finder.addMatcher(member_matcher, &member_rewriter); | 377 match_finder.addMatcher(member_matcher, &member_rewriter); |
| 292 DeclRefRewriterCallback decl_ref_rewriter(&replacements); | 378 |
| 379 DeclRefRewriter decl_ref_rewriter(&replacements); | |
| 293 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); | 380 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); |
| 294 | 381 |
| 295 // Function reference handling (e.g. getting a pointer to a function without | 382 // Non-method function declarations ======== |
| 296 // calling it): | 383 // Given |
| 384 // void f(); | |
| 385 // struct S { | |
| 386 // void g(); | |
| 387 // }; | |
| 388 // matches |f| but not |g|. | |
| 389 auto function_decl_matcher = | |
| 390 id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace)); | |
| 391 FunctionDeclRewriter function_decl_rewriter(&replacements); | |
| 392 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); | |
| 393 | |
| 394 // Non-method function references ======== | |
| 395 // Given | |
| 396 // f(); | |
| 397 // void (*p)() = &f; | |
| 398 // matches |f()| and |&f|. | |
| 297 auto function_ref_matcher = | 399 auto function_ref_matcher = |
| 298 id("expr", declRefExpr(to(function_decl_matcher))); | 400 id("expr", declRefExpr(to(function_decl_matcher))); |
| 299 match_finder.addMatcher(function_ref_matcher, &call_rewriter); | 401 FunctionRefRewriter function_ref_rewriter(&replacements); |
| 402 match_finder.addMatcher(function_ref_matcher, &function_ref_rewriter); | |
| 300 | 403 |
| 301 // Initializer handling: | 404 // Method declarations ======== |
|
danakj
2016/01/08 02:02:52
I like these comments much
| |
| 405 // Given | |
| 406 // struct S { | |
| 407 // void g(); | |
| 408 // }; | |
| 409 // matches |g|. | |
| 410 // | |
| 411 // Note: the AST matchers don't provide a good way to match against an | |
| 412 // override from a given base class. Instead, the rewriter uses two matchers: | |
| 413 // one that matches all method declarations in the Blink namespace, and | |
| 414 // another which matches all overridden methods not in the Blink namespace. | |
| 415 // The second list is filtered against the first list to determine which | |
| 416 // methods are inherited from Blink classes and need to be rewritten. | |
| 417 auto blink_method_decl_matcher = | |
| 418 id("decl", cxxMethodDecl(unless(anyOf( | |
| 419 // Overloaded operators have special names | |
| 420 // and should never be renamed. | |
| 421 isOverloadedOperator(), | |
| 422 // Similarly, constructors and destructors | |
| 423 // should not be considered for renaming. | |
| 424 cxxConstructorDecl(), cxxDestructorDecl())), | |
| 425 in_blink_namespace)); | |
| 426 // Note that the matcher for overridden methods doesn't need to filter for | |
| 427 // special member functions: see implementation of FunctionDeclRewriter for | |
| 428 // the full explanation. | |
| 429 auto non_blink_overridden_method_decl_matcher = | |
| 430 id("decl", cxxMethodDecl(isOverride(), unless(in_blink_namespace))); | |
| 431 MethodDeclRewriter method_decl_rewriter(&replacements); | |
| 432 match_finder.addMatcher(blink_method_decl_matcher, &method_decl_rewriter); | |
| 433 match_finder.addMatcher(non_blink_overridden_method_decl_matcher, | |
| 434 &method_decl_rewriter); | |
| 435 | |
| 436 // Method references in a non-member context ======== | |
| 437 // Given | |
| 438 // S s; | |
| 439 // s.g(); | |
| 440 // void (S::*p)() = &S::g; | |
| 441 // matches |&S::g| but not |s.g()|. | |
| 442 auto blink_method_ref_matcher = | |
| 443 id("expr", declRefExpr(to(blink_method_decl_matcher))); | |
| 444 auto non_blink_overridden_method_ref_matcher = | |
| 445 id("expr", declRefExpr(to(non_blink_overridden_method_decl_matcher))); | |
| 446 | |
| 447 MethodRefRewriter method_ref_rewriter(method_decl_rewriter, &replacements); | |
| 448 match_finder.addMatcher(blink_method_ref_matcher, &method_ref_rewriter); | |
| 449 match_finder.addMatcher(non_blink_overridden_method_ref_matcher, | |
| 450 &method_ref_rewriter); | |
| 451 | |
| 452 // Method references in a member context ======== | |
| 453 // Given | |
| 454 // S s; | |
| 455 // s.g(); | |
| 456 // void (S::*p)() = &S::g; | |
| 457 // matches |s.g()| but not |&S::g|. | |
| 458 auto blink_method_member_matcher = | |
| 459 id("expr", memberExpr(member(blink_method_decl_matcher))); | |
| 460 auto non_blink_overridden_method_member_matcher = | |
| 461 id("expr", memberExpr(member(non_blink_overridden_method_decl_matcher))); | |
| 462 | |
| 463 MethodMemberRewriter method_member_rewriter(method_decl_rewriter, | |
| 464 &replacements); | |
| 465 match_finder.addMatcher(blink_method_member_matcher, &method_member_rewriter); | |
| 466 match_finder.addMatcher(non_blink_overridden_method_member_matcher, | |
| 467 &method_member_rewriter); | |
| 468 | |
| 469 // Initializers ======== | |
| 470 // Given | |
| 471 // struct S { | |
| 472 // int x; | |
| 473 // S() : x(2) {} | |
| 474 // }; | |
| 475 // matches each initializer in the constructor for S. | |
| 302 auto constructor_initializer_matcher = | 476 auto constructor_initializer_matcher = |
| 303 cxxConstructorDecl(forEachConstructorInitializer( | 477 cxxConstructorDecl(forEachConstructorInitializer( |
| 304 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); | 478 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); |
| 305 | 479 |
| 306 ConstructorInitializerRewriterCallback constructor_initializer_rewriter( | 480 ConstructorInitializerRewriter constructor_initializer_rewriter( |
| 307 &replacements); | 481 &replacements); |
| 308 match_finder.addMatcher(constructor_initializer_matcher, | 482 match_finder.addMatcher(constructor_initializer_matcher, |
| 309 &constructor_initializer_rewriter); | 483 &constructor_initializer_rewriter); |
| 310 | 484 |
| 311 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = | 485 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = |
| 312 clang::tooling::newFrontendActionFactory(&match_finder); | 486 clang::tooling::newFrontendActionFactory(&match_finder); |
| 313 int result = tool.run(factory.get()); | 487 int result = tool.run(factory.get()); |
| 314 if (result != 0) | 488 if (result != 0) |
| 315 return result; | 489 return result; |
| 316 | 490 |
| 317 // Serialization format is documented in tools/clang/scripts/run_tool.py | 491 // Serialization format is documented in tools/clang/scripts/run_tool.py |
| 318 llvm::outs() << "==== BEGIN EDITS ====\n"; | 492 llvm::outs() << "==== BEGIN EDITS ====\n"; |
| 319 for (const auto& r : replacements) { | 493 for (const auto& r : replacements) { |
| 320 std::string replacement_text = r.getReplacementText().str(); | 494 std::string replacement_text = r.getReplacementText().str(); |
| 321 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); | 495 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); |
| 322 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 496 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() |
| 323 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; | 497 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; |
| 324 } | 498 } |
| 325 llvm::outs() << "==== END EDITS ====\n"; | 499 llvm::outs() << "==== END EDITS ====\n"; |
| 326 | 500 |
| 327 return 0; | 501 return 0; |
| 328 } | 502 } |
| OLD | NEW |