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 <memory> | 17 #include <memory> |
| 18 #include <set> | 18 #include <set> |
| 19 #include <string> | 19 #include <string> |
| 20 | 20 |
| 21 #include "clang/AST/ASTContext.h" | 21 #include "clang/AST/ASTContext.h" |
| 22 #include "clang/ASTMatchers/ASTMatchFinder.h" | 22 #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 23 #include "clang/ASTMatchers/ASTMatchers.h" | 23 #include "clang/ASTMatchers/ASTMatchers.h" |
| 24 #include "clang/ASTMatchers/ASTMatchersMacros.h" | 24 #include "clang/ASTMatchers/ASTMatchersMacros.h" |
| 25 #include "clang/Basic/CharInfo.h" | 25 #include "clang/Basic/CharInfo.h" |
| 26 #include "clang/Basic/SourceManager.h" | 26 #include "clang/Basic/SourceManager.h" |
| 27 #include "clang/Frontend/CompilerInstance.h" | |
| 27 #include "clang/Frontend/FrontendActions.h" | 28 #include "clang/Frontend/FrontendActions.h" |
| 29 #include "clang/Lex/MacroArgs.h" | |
| 28 #include "clang/Lex/Lexer.h" | 30 #include "clang/Lex/Lexer.h" |
| 31 #include "clang/Lex/PPCallbacks.h" | |
| 32 #include "clang/Lex/Preprocessor.h" | |
| 29 #include "clang/Tooling/CommonOptionsParser.h" | 33 #include "clang/Tooling/CommonOptionsParser.h" |
| 30 #include "clang/Tooling/Refactoring.h" | 34 #include "clang/Tooling/Refactoring.h" |
| 31 #include "clang/Tooling/Tooling.h" | 35 #include "clang/Tooling/Tooling.h" |
| 32 #include "llvm/Support/CommandLine.h" | 36 #include "llvm/Support/CommandLine.h" |
| 33 #include "llvm/Support/TargetSelect.h" | 37 #include "llvm/Support/TargetSelect.h" |
| 34 | 38 |
| 35 #include "EditTracker.h" | 39 #include "EditTracker.h" |
| 36 | 40 |
| 37 using namespace clang::ast_matchers; | 41 using namespace clang::ast_matchers; |
| 38 using clang::tooling::CommonOptionsParser; | 42 using clang::tooling::CommonOptionsParser; |
| 39 using clang::tooling::Replacement; | 43 using clang::tooling::Replacement; |
| 40 using llvm::StringRef; | 44 using llvm::StringRef; |
| 41 | 45 |
| 42 namespace { | 46 namespace { |
| 43 | 47 |
| 44 const char kBlinkFieldPrefix[] = "m_"; | 48 const char kBlinkFieldPrefix[] = "m_"; |
| 45 const char kBlinkStaticMemberPrefix[] = "s_"; | 49 const char kBlinkStaticMemberPrefix[] = "s_"; |
| 46 const char kGeneratedFileRegex[] = "^gen/|/gen/"; | 50 const char kGeneratedFileRegex[] = "^gen/|/gen/"; |
| 51 const char kGMockMethodNamePrefix[] = "gmock_"; | |
| 47 | 52 |
| 48 template <typename MatcherType, typename NodeType> | 53 template <typename MatcherType, typename NodeType> |
| 49 bool IsMatching(const MatcherType& matcher, | 54 bool IsMatching(const MatcherType& matcher, |
| 50 const NodeType& node, | 55 const NodeType& node, |
| 51 clang::ASTContext& context) { | 56 clang::ASTContext& context) { |
| 52 return !match(matcher, node, context).empty(); | 57 return !match(matcher, node, context).empty(); |
| 53 } | 58 } |
| 54 | 59 |
| 55 const clang::ast_matchers::internal:: | 60 const clang::ast_matchers::internal:: |
| 56 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> | 61 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 72 return Node.isInstance(); | 77 return Node.isInstance(); |
| 73 } | 78 } |
| 74 | 79 |
| 75 AST_MATCHER_P(clang::FunctionTemplateDecl, | 80 AST_MATCHER_P(clang::FunctionTemplateDecl, |
| 76 templatedDecl, | 81 templatedDecl, |
| 77 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>, | 82 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>, |
| 78 InnerMatcher) { | 83 InnerMatcher) { |
| 79 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder); | 84 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder); |
| 80 } | 85 } |
| 81 | 86 |
| 87 // Matches a CXXMethodDecl of a method declared via MOCK_METHODx macro if such | |
| 88 // method mocks a method matched by the InnerMatcher. For example if "foo" | |
| 89 // matcher matches "interfaceMethod", then mocksMethod(foo()) will match | |
| 90 // "gmock_interfaceMethod" declared by MOCK_METHOD_x(interfaceMethod). | |
| 91 AST_MATCHER_P(clang::CXXMethodDecl, | |
| 92 mocksMethod, | |
| 93 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>, | |
| 94 InnerMatcher) { | |
| 95 if (!Node.getDeclName().isIdentifier()) | |
| 96 return false; | |
| 97 | |
| 98 llvm::StringRef method_name = Node.getName(); | |
| 99 if (!method_name.startswith(kGMockMethodNamePrefix)) | |
| 100 return false; | |
| 101 | |
| 102 llvm::StringRef mocked_method_name = | |
| 103 method_name.substr(strlen(kGMockMethodNamePrefix)); | |
| 104 for (const auto& potentially_mocked_method : Node.getParent()->methods()) { | |
| 105 if (!potentially_mocked_method->isVirtual()) | |
| 106 continue; | |
| 107 | |
| 108 clang::DeclarationName decl_name = potentially_mocked_method->getDeclName(); | |
| 109 if (!decl_name.isIdentifier() || | |
| 110 potentially_mocked_method->getName() != mocked_method_name) | |
| 111 continue; | |
| 112 if (potentially_mocked_method->getNumParams() != Node.getNumParams()) | |
| 113 continue; | |
| 114 | |
| 115 if (InnerMatcher.matches(*potentially_mocked_method, Finder, Builder)) | |
| 116 return true; | |
| 117 } | |
| 118 | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 82 // If |InnerMatcher| matches |top|, then the returned matcher will match: | 122 // If |InnerMatcher| matches |top|, then the returned matcher will match: |
| 83 // - |top::function| | 123 // - |top::function| |
| 84 // - |top::Class::method| | 124 // - |top::Class::method| |
| 85 // - |top::internal::Class::method| | 125 // - |top::internal::Class::method| |
| 86 AST_MATCHER_P( | 126 AST_MATCHER_P( |
| 87 clang::NestedNameSpecifier, | 127 clang::NestedNameSpecifier, |
| 88 hasTopLevelPrefix, | 128 hasTopLevelPrefix, |
| 89 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>, | 129 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>, |
| 90 InnerMatcher) { | 130 InnerMatcher) { |
| 91 const clang::NestedNameSpecifier* NodeToMatch = &Node; | 131 const clang::NestedNameSpecifier* NodeToMatch = &Node; |
| (...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 template <> | 759 template <> |
| 720 struct TargetNodeTraits<clang::UnresolvedUsingValueDecl> { | 760 struct TargetNodeTraits<clang::UnresolvedUsingValueDecl> { |
| 721 static clang::SourceLocation GetLoc( | 761 static clang::SourceLocation GetLoc( |
| 722 const clang::UnresolvedUsingValueDecl& decl) { | 762 const clang::UnresolvedUsingValueDecl& decl) { |
| 723 return decl.getNameInfo().getLoc(); | 763 return decl.getNameInfo().getLoc(); |
| 724 } | 764 } |
| 725 static const char* GetName() { return "decl"; } | 765 static const char* GetName() { return "decl"; } |
| 726 static const char* GetType() { return "UnresolvedUsingValueDecl"; } | 766 static const char* GetType() { return "UnresolvedUsingValueDecl"; } |
| 727 }; | 767 }; |
| 728 | 768 |
| 769 bool JumpAboveMacroScratchSpace(const clang::SourceManager& source_manager, | |
| 770 clang::SourceLocation* loc) { | |
| 771 if (loc->isMacroID()) { | |
| 772 // Try to jump "above" the scratch buffer if |loc| is inside | |
| 773 // token##Concatenation. | |
| 774 const int kMaxJumps = 5; | |
| 775 bool verified_out_of_scratch_space = false; | |
| 776 for (int i = 0; i < kMaxJumps && !verified_out_of_scratch_space; i++) { | |
| 777 clang::SourceLocation spell = source_manager.getSpellingLoc(*loc); | |
| 778 verified_out_of_scratch_space = | |
| 779 source_manager.getBufferName(spell) != "<scratch space>"; | |
| 780 if (!verified_out_of_scratch_space) | |
| 781 *loc = source_manager.getImmediateMacroCallerLoc(*loc); | |
| 782 } | |
| 783 if (!verified_out_of_scratch_space) | |
| 784 return false; | |
| 785 } | |
| 786 | |
| 787 return true; | |
| 788 } | |
| 789 | |
| 729 template <typename TargetNode> | 790 template <typename TargetNode> |
| 730 class RewriterBase : public MatchFinder::MatchCallback { | 791 class RewriterBase : public MatchFinder::MatchCallback { |
| 731 public: | 792 public: |
| 732 explicit RewriterBase(std::set<Replacement>* replacements) | 793 explicit RewriterBase(std::set<Replacement>* replacements) |
| 733 : replacements_(replacements) {} | 794 : replacements_(replacements) {} |
| 734 | 795 |
| 735 const TargetNode& GetTargetNode(const MatchFinder::MatchResult& result) { | 796 const TargetNode& GetTargetNode(const MatchFinder::MatchResult& result) { |
| 736 const TargetNode* target_node = result.Nodes.getNodeAs<TargetNode>( | 797 const TargetNode* target_node = result.Nodes.getNodeAs<TargetNode>( |
| 737 TargetNodeTraits<TargetNode>::GetName()); | 798 TargetNodeTraits<TargetNode>::GetName()); |
| 738 assert(target_node); | 799 assert(target_node); |
| 739 return *target_node; | 800 return *target_node; |
| 740 } | 801 } |
| 741 | 802 |
| 742 bool GenerateReplacement(const MatchFinder::MatchResult& result, | 803 bool GenerateReplacement(const MatchFinder::MatchResult& result, |
| 743 clang::SourceLocation loc, | 804 clang::SourceLocation loc, |
| 744 llvm::StringRef old_name, | 805 llvm::StringRef old_name, |
| 745 std::string new_name, | 806 std::string new_name, |
| 746 Replacement* replacement) { | 807 Replacement* replacement) { |
| 747 const clang::ASTContext& context = *result.Context; | 808 const clang::ASTContext& context = *result.Context; |
| 748 const clang::SourceManager& source_manager = *result.SourceManager; | 809 const clang::SourceManager& source_manager = *result.SourceManager; |
| 749 | 810 |
| 750 if (loc.isMacroID()) { | 811 if (!JumpAboveMacroScratchSpace(source_manager, &loc)) |
| 751 // Try to jump "above" the scratch buffer if |loc| is inside | 812 return false; |
| 752 // token##Concatenation. | |
| 753 const int kMaxJumps = 5; | |
| 754 bool verified_out_of_scratch_space = false; | |
| 755 for (int i = 0; i < kMaxJumps && !verified_out_of_scratch_space; i++) { | |
| 756 clang::SourceLocation spell = source_manager.getSpellingLoc(loc); | |
| 757 verified_out_of_scratch_space = | |
| 758 source_manager.getBufferName(spell) != "<scratch space>"; | |
| 759 if (!verified_out_of_scratch_space) | |
| 760 loc = source_manager.getImmediateMacroCallerLoc(loc); | |
| 761 } | |
| 762 if (!verified_out_of_scratch_space) | |
| 763 return false; | |
| 764 } | |
| 765 | 813 |
| 766 // If the edit affects only the first character of the identifier, then | 814 // If the edit affects only the first character of the identifier, then |
| 767 // narrow down the edit to only this single character. This is important | 815 // narrow down the edit to only this single character. This is important |
| 768 // for dealing with toFooBar -> ToFooBar method renaming when the method | 816 // for dealing with toFooBar -> ToFooBar method renaming when the method |
| 769 // name is built using macro token concatenation like to##macroArgument - in | 817 // name is built using macro token concatenation like to##macroArgument - in |
| 770 // this case we should only rewrite "t" -> "T" and leave "o##macroArgument" | 818 // this case we should only rewrite "t" -> "T" and leave "o##macroArgument" |
| 771 // untouched. | 819 // untouched. |
| 772 llvm::StringRef expected_old_text = old_name; | 820 llvm::StringRef expected_old_text = old_name; |
| 773 llvm::StringRef new_text = new_name; | 821 llvm::StringRef new_text = new_name; |
| 774 if (loc.isMacroID() && expected_old_text.substr(1) == new_text.substr(1)) { | 822 if (loc.isMacroID() && expected_old_text.substr(1) == new_text.substr(1)) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 786 StringRef actual_old_text = clang::Lexer::getSourceText( | 834 StringRef actual_old_text = clang::Lexer::getSourceText( |
| 787 range, source_manager, context.getLangOpts()); | 835 range, source_manager, context.getLangOpts()); |
| 788 if (actual_old_text != expected_old_text) | 836 if (actual_old_text != expected_old_text) |
| 789 return false; | 837 return false; |
| 790 | 838 |
| 791 if (replacement) | 839 if (replacement) |
| 792 *replacement = Replacement(source_manager, range, new_text); | 840 *replacement = Replacement(source_manager, range, new_text); |
| 793 return true; | 841 return true; |
| 794 } | 842 } |
| 795 | 843 |
| 844 virtual clang::SourceLocation GetTargetLoc( | |
| 845 const MatchFinder::MatchResult& result) { | |
| 846 return TargetNodeTraits<TargetNode>::GetLoc(GetTargetNode(result)); | |
| 847 } | |
| 848 | |
| 796 void AddReplacement(const MatchFinder::MatchResult& result, | 849 void AddReplacement(const MatchFinder::MatchResult& result, |
| 797 llvm::StringRef old_name, | 850 llvm::StringRef old_name, |
| 798 std::string new_name) { | 851 std::string new_name) { |
| 799 if (old_name == new_name) | 852 if (old_name == new_name) |
| 800 return; | 853 return; |
| 801 | 854 |
| 802 clang::SourceLocation loc = | 855 clang::SourceLocation loc = GetTargetLoc(result); |
| 803 TargetNodeTraits<TargetNode>::GetLoc(GetTargetNode(result)); | 856 if (loc.isInvalid()) |
| 857 return; | |
| 804 | 858 |
| 805 Replacement replacement; | 859 Replacement replacement; |
| 806 if (!GenerateReplacement(result, loc, old_name, new_name, &replacement)) | 860 if (!GenerateReplacement(result, loc, old_name, new_name, &replacement)) |
| 807 return; | 861 return; |
| 808 | 862 |
| 809 replacements_->insert(std::move(replacement)); | 863 replacements_->insert(std::move(replacement)); |
| 810 edit_tracker_.Add(*result.SourceManager, loc, old_name, new_name); | 864 edit_tracker_.Add(*result.SourceManager, loc, old_name, new_name); |
| 811 } | 865 } |
| 812 | 866 |
| 813 const EditTracker& edit_tracker() const { return edit_tracker_; } | 867 const EditTracker& edit_tracker() const { return edit_tracker_; } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 876 using EnumConstantDeclRefRewriter = | 930 using EnumConstantDeclRefRewriter = |
| 877 DeclRewriterBase<clang::EnumConstantDecl, clang::DeclRefExpr>; | 931 DeclRewriterBase<clang::EnumConstantDecl, clang::DeclRefExpr>; |
| 878 | 932 |
| 879 using UnresolvedLookupRewriter = | 933 using UnresolvedLookupRewriter = |
| 880 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedLookupExpr>; | 934 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedLookupExpr>; |
| 881 using UnresolvedMemberRewriter = | 935 using UnresolvedMemberRewriter = |
| 882 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedMemberExpr>; | 936 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedMemberExpr>; |
| 883 | 937 |
| 884 using UsingDeclRewriter = DeclRewriterBase<clang::UsingDecl, clang::NamedDecl>; | 938 using UsingDeclRewriter = DeclRewriterBase<clang::UsingDecl, clang::NamedDecl>; |
| 885 | 939 |
| 940 class GMockMemberRewriter | |
| 941 : public DeclRewriterBase<clang::CXXMethodDecl, clang::MemberExpr> { | |
| 942 public: | |
| 943 using Base = DeclRewriterBase<clang::CXXMethodDecl, clang::MemberExpr>; | |
| 944 | |
| 945 explicit GMockMemberRewriter(std::set<Replacement>* replacements) | |
| 946 : Base(replacements) {} | |
| 947 | |
| 948 std::unique_ptr<clang::PPCallbacks> CreatePreprocessorCallbacks() { | |
| 949 return llvm::make_unique<GMockMemberRewriter::PPCallbacks>(this); | |
| 950 } | |
| 951 | |
| 952 clang::SourceLocation GetTargetLoc( | |
| 953 const MatchFinder::MatchResult& result) override { | |
| 954 // Find location of the gmock_##MockedMethod identifier. | |
| 955 clang::SourceLocation target_loc = Base::GetTargetLoc(result); | |
| 956 | |
| 957 // Find location of EXPECT_CALL macro invocation. | |
| 958 clang::SourceLocation macro_call_loc = target_loc; | |
| 959 if (!JumpAboveMacroScratchSpace(*result.SourceManager, ¯o_call_loc)) | |
| 960 return clang::SourceLocation(); | |
| 961 macro_call_loc = result.SourceManager->getExpansionLoc(macro_call_loc); | |
| 962 | |
| 963 // Map |macro_call_loc| to argument location (location of the method name). | |
| 964 auto it = expect_call_to_2nd_arg.find(macro_call_loc); | |
| 965 if (it == expect_call_to_2nd_arg.end()) | |
| 966 return clang::SourceLocation(); | |
| 967 return it->second; | |
| 968 } | |
| 969 | |
| 970 private: | |
| 971 std::map<clang::SourceLocation, clang::SourceLocation> expect_call_to_2nd_arg; | |
| 972 | |
| 973 // Called from PPCallbacks with the locations of EXPECT_CALL macro invocation: | |
| 974 // Example: | |
| 975 // EXPECT_CALL(my_mock, myMethod(123, 456)); | |
| 976 // ^- expansion_loc ^- actual_arg_loc | |
| 977 void RecordExpectCallMacroInvocation(clang::SourceLocation expansion_loc, | |
| 978 clang::SourceLocation second_arg_loc) { | |
| 979 expect_call_to_2nd_arg[expansion_loc] = second_arg_loc; | |
| 980 } | |
| 981 | |
| 982 class PPCallbacks : public clang::PPCallbacks { | |
| 983 public: | |
| 984 PPCallbacks(GMockMemberRewriter* rewriter) : rewriter_(rewriter) {} | |
| 985 ~PPCallbacks() override {} | |
| 986 void MacroExpands(const clang::Token& name, | |
| 987 const clang::MacroDefinition& def, | |
| 988 clang::SourceRange range, | |
| 989 const clang::MacroArgs* args) override { | |
| 990 clang::IdentifierInfo* id = name.getIdentifierInfo(); | |
| 991 if (!id) | |
| 992 return; | |
| 993 | |
| 994 if (id->getName() != "EXPECT_CALL") | |
| 995 return; | |
| 996 | |
| 997 if (def.getMacroInfo()->getNumArgs() != 2) | |
| 998 return; | |
| 999 | |
| 1000 // TODO(lukasza): Should check if def.getMacroInfo()->getDefinitionLoc() | |
| 1001 // is in testing/gmock/include/gmock/gmock-spec-builders.h but I don't | |
| 1002 // know how to get clang::SourceManager to call getFileName. | |
|
Łukasz Anforowicz
2017/01/07 01:16:29
This inaccuracy is probably okay - even if there a
| |
| 1003 | |
| 1004 rewriter_->RecordExpectCallMacroInvocation( | |
| 1005 name.getLocation(), args->getUnexpArgument(1)->getLocation()); | |
| 1006 } | |
| 1007 | |
| 1008 private: | |
| 1009 GMockMemberRewriter* rewriter_; | |
| 1010 }; | |
| 1011 }; | |
| 1012 | |
| 886 clang::DeclarationName GetUnresolvedName( | 1013 clang::DeclarationName GetUnresolvedName( |
| 887 const clang::UnresolvedMemberExpr& expr) { | 1014 const clang::UnresolvedMemberExpr& expr) { |
| 888 return expr.getMemberName(); | 1015 return expr.getMemberName(); |
| 889 } | 1016 } |
| 890 | 1017 |
| 891 clang::DeclarationName GetUnresolvedName( | 1018 clang::DeclarationName GetUnresolvedName( |
| 892 const clang::DependentScopeDeclRefExpr& expr) { | 1019 const clang::DependentScopeDeclRefExpr& expr) { |
| 893 return expr.getDeclName(); | 1020 return expr.getDeclName(); |
| 894 } | 1021 } |
| 895 | 1022 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 | 1140 |
| 1014 using UnresolvedUsingValueDeclRewriter = | 1141 using UnresolvedUsingValueDeclRewriter = |
| 1015 UnresolvedRewriterBase<clang::UnresolvedUsingValueDecl>; | 1142 UnresolvedRewriterBase<clang::UnresolvedUsingValueDecl>; |
| 1016 | 1143 |
| 1017 using DependentScopeDeclRefExprRewriter = | 1144 using DependentScopeDeclRefExprRewriter = |
| 1018 UnresolvedRewriterBase<clang::DependentScopeDeclRefExpr>; | 1145 UnresolvedRewriterBase<clang::DependentScopeDeclRefExpr>; |
| 1019 | 1146 |
| 1020 using CXXDependentScopeMemberExprRewriter = | 1147 using CXXDependentScopeMemberExprRewriter = |
| 1021 UnresolvedRewriterBase<clang::CXXDependentScopeMemberExpr>; | 1148 UnresolvedRewriterBase<clang::CXXDependentScopeMemberExpr>; |
| 1022 | 1149 |
| 1150 class SourceFileCallbacks : public clang::tooling::SourceFileCallbacks { | |
| 1151 public: | |
| 1152 SourceFileCallbacks() : source_counter_(0) {} | |
| 1153 ~SourceFileCallbacks() override {} | |
| 1154 | |
| 1155 void AddPPCallbacks(std::unique_ptr<clang::PPCallbacks> new_callbacks) { | |
| 1156 if (!pp_callbacks_) { | |
| 1157 pp_callbacks_ = std::move(new_callbacks); | |
| 1158 } else { | |
| 1159 pp_callbacks_ = llvm::make_unique<clang::PPChainedCallbacks>( | |
| 1160 std::move(new_callbacks), std::move(pp_callbacks_)); | |
| 1161 } | |
| 1162 } | |
| 1163 | |
| 1164 // clang::tooling::SourceFileCallbacks override: | |
| 1165 bool handleBeginSource(clang::CompilerInstance& compiler, | |
| 1166 llvm::StringRef Filename) override { | |
| 1167 source_counter_++; | |
| 1168 assert(source_counter_ == 1); // We only have *one* pp_callbacks_. | |
| 1169 | |
| 1170 compiler.getPreprocessor().addPPCallbacks(std::move(pp_callbacks_)); | |
| 1171 return true; | |
| 1172 } | |
| 1173 | |
| 1174 private: | |
| 1175 int source_counter_; | |
| 1176 std::unique_ptr<clang::PPCallbacks> pp_callbacks_; | |
| 1177 }; | |
| 1178 | |
| 1023 } // namespace | 1179 } // namespace |
| 1024 | 1180 |
| 1025 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 1181 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
| 1026 | 1182 |
| 1027 int main(int argc, const char* argv[]) { | 1183 int main(int argc, const char* argv[]) { |
| 1028 // TODO(dcheng): Clang tooling should do this itself. | 1184 // TODO(dcheng): Clang tooling should do this itself. |
| 1029 // http://llvm.org/bugs/show_bug.cgi?id=21627 | 1185 // http://llvm.org/bugs/show_bug.cgi?id=21627 |
| 1030 llvm::InitializeNativeTarget(); | 1186 llvm::InitializeNativeTarget(); |
| 1031 llvm::InitializeNativeTargetAsmParser(); | 1187 llvm::InitializeNativeTargetAsmParser(); |
| 1032 llvm::cl::OptionCategory category( | 1188 llvm::cl::OptionCategory category( |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1198 // same method. | 1354 // same method. |
| 1199 is_blink_method)); | 1355 is_blink_method)); |
| 1200 MethodDeclRewriter method_decl_rewriter(&replacements); | 1356 MethodDeclRewriter method_decl_rewriter(&replacements); |
| 1201 match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter); | 1357 match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter); |
| 1202 | 1358 |
| 1203 // Method references in a non-member context ======== | 1359 // Method references in a non-member context ======== |
| 1204 // Given | 1360 // Given |
| 1205 // S s; | 1361 // S s; |
| 1206 // s.g(); | 1362 // s.g(); |
| 1207 // void (S::*p)() = &S::g; | 1363 // void (S::*p)() = &S::g; |
| 1208 // matches |&S::g| but not |s.g()|. | 1364 // matches |&S::g| but not |s.g|. |
| 1209 auto method_ref_matcher = id( | 1365 auto method_ref_matcher = id( |
| 1210 "expr", declRefExpr(to(method_decl_matcher), | 1366 "expr", declRefExpr(to(method_decl_matcher), |
| 1211 // Ignore template substitutions. | 1367 // Ignore template substitutions. |
| 1212 unless(hasAncestor(substNonTypeTemplateParmExpr())))); | 1368 unless(hasAncestor(substNonTypeTemplateParmExpr())))); |
| 1213 | 1369 |
| 1214 MethodRefRewriter method_ref_rewriter(&replacements); | 1370 MethodRefRewriter method_ref_rewriter(&replacements); |
| 1215 match_finder.addMatcher(method_ref_matcher, &method_ref_rewriter); | 1371 match_finder.addMatcher(method_ref_matcher, &method_ref_rewriter); |
| 1216 | 1372 |
| 1217 // Method references in a member context ======== | 1373 // Method references in a member context ======== |
| 1218 // Given | 1374 // Given |
| 1219 // S s; | 1375 // S s; |
| 1220 // s.g(); | 1376 // s.g(); |
| 1221 // void (S::*p)() = &S::g; | 1377 // void (S::*p)() = &S::g; |
| 1222 // matches |s.g()| but not |&S::g|. | 1378 // matches |s.g| but not |&S::g|. |
| 1223 auto method_member_matcher = | 1379 auto method_member_matcher = |
| 1224 id("expr", memberExpr(member(method_decl_matcher))); | 1380 id("expr", memberExpr(member(method_decl_matcher))); |
| 1225 | 1381 |
| 1226 MethodMemberRewriter method_member_rewriter(&replacements); | 1382 MethodMemberRewriter method_member_rewriter(&replacements); |
| 1227 match_finder.addMatcher(method_member_matcher, &method_member_rewriter); | 1383 match_finder.addMatcher(method_member_matcher, &method_member_rewriter); |
| 1228 | 1384 |
| 1229 // Initializers ======== | 1385 // Initializers ======== |
| 1230 // Given | 1386 // Given |
| 1231 // struct S { | 1387 // struct S { |
| 1232 // int x; | 1388 // int x; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1381 // }; | 1537 // }; |
| 1382 // matches |T::foo| and |x.bar|. | 1538 // matches |T::foo| and |x.bar|. |
| 1383 auto cxx_dependent_scope_member_expr_matcher = | 1539 auto cxx_dependent_scope_member_expr_matcher = |
| 1384 expr(id("expr", cxxDependentScopeMemberExpr( | 1540 expr(id("expr", cxxDependentScopeMemberExpr( |
| 1385 hasMemberFromType(blink_qual_type_matcher)))); | 1541 hasMemberFromType(blink_qual_type_matcher)))); |
| 1386 CXXDependentScopeMemberExprRewriter cxx_dependent_scope_member_expr_rewriter( | 1542 CXXDependentScopeMemberExprRewriter cxx_dependent_scope_member_expr_rewriter( |
| 1387 &replacements); | 1543 &replacements); |
| 1388 match_finder.addMatcher(cxx_dependent_scope_member_expr_matcher, | 1544 match_finder.addMatcher(cxx_dependent_scope_member_expr_matcher, |
| 1389 &cxx_dependent_scope_member_expr_rewriter); | 1545 &cxx_dependent_scope_member_expr_rewriter); |
| 1390 | 1546 |
| 1547 // GMock calls lookup ======== | |
| 1548 // Given | |
| 1549 // EXPECT_CALL(obj, myMethod(...)) | |
| 1550 // will match obj.gmock_myMethod(...) call generated by the macro | |
| 1551 // (but only if it mocks a Blink method). | |
| 1552 auto gmock_member_matcher = | |
| 1553 id("expr", memberExpr(hasDeclaration( | |
| 1554 decl(cxxMethodDecl(mocksMethod(method_decl_matcher)))))); | |
| 1555 GMockMemberRewriter gmock_member_rewriter(&replacements); | |
| 1556 match_finder.addMatcher(gmock_member_matcher, &gmock_member_rewriter); | |
| 1557 | |
| 1558 // Run all the matchers. | |
| 1559 SourceFileCallbacks source_file_callbacks; | |
| 1560 source_file_callbacks.AddPPCallbacks( | |
| 1561 gmock_member_rewriter.CreatePreprocessorCallbacks()); | |
| 1391 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = | 1562 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = |
| 1392 clang::tooling::newFrontendActionFactory(&match_finder); | 1563 clang::tooling::newFrontendActionFactory(&match_finder, |
| 1564 &source_file_callbacks); | |
| 1393 int result = tool.run(factory.get()); | 1565 int result = tool.run(factory.get()); |
| 1394 if (result != 0) | 1566 if (result != 0) |
| 1395 return result; | 1567 return result; |
| 1396 | 1568 |
| 1397 // Supplemental data for the Blink rename rebase helper. | 1569 // Supplemental data for the Blink rename rebase helper. |
| 1398 // TODO(dcheng): There's a lot of match rewriters missing from this list. | 1570 // TODO(dcheng): There's a lot of match rewriters missing from this list. |
| 1399 llvm::outs() << "==== BEGIN TRACKED EDITS ====\n"; | 1571 llvm::outs() << "==== BEGIN TRACKED EDITS ====\n"; |
| 1400 field_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); | 1572 field_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); |
| 1401 var_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); | 1573 var_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); |
| 1402 enum_member_decl_rewriter.edit_tracker().SerializeTo("enu", llvm::outs()); | 1574 enum_member_decl_rewriter.edit_tracker().SerializeTo("enu", llvm::outs()); |
| 1403 function_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); | 1575 function_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); |
| 1404 method_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); | 1576 method_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); |
| 1405 llvm::outs() << "==== END TRACKED EDITS ====\n"; | 1577 llvm::outs() << "==== END TRACKED EDITS ====\n"; |
| 1406 | 1578 |
| 1407 // Serialization format is documented in tools/clang/scripts/run_tool.py | 1579 // Serialization format is documented in tools/clang/scripts/run_tool.py |
| 1408 llvm::outs() << "==== BEGIN EDITS ====\n"; | 1580 llvm::outs() << "==== BEGIN EDITS ====\n"; |
| 1409 for (const auto& r : replacements) { | 1581 for (const auto& r : replacements) { |
| 1410 std::string replacement_text = r.getReplacementText().str(); | 1582 std::string replacement_text = r.getReplacementText().str(); |
| 1411 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); | 1583 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); |
| 1412 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 1584 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() |
| 1413 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; | 1585 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; |
| 1414 } | 1586 } |
| 1415 llvm::outs() << "==== END EDITS ====\n"; | 1587 llvm::outs() << "==== END EDITS ====\n"; |
| 1416 | 1588 |
| 1417 return 0; | 1589 return 0; |
| 1418 } | 1590 } |
| OLD | NEW |