1 //===---- NamespaceAliaserTest.cpp - clang-tidy 2 //----------------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "../clang-tidy/utils/NamespaceAliaser.h" 12 13 #include "ClangTidyTest.h" 14 #include "clang/ASTMatchers/ASTMatchFinder.h" 15 #include "clang/ASTMatchers/ASTMatchers.h" 16 #include "gtest/gtest.h" 17 18 namespace clang { 19 namespace tidy { 20 namespace utils { 21 // This checker is for testing only. It can only run on one test case 22 // (e.g. with one SourceManager). 23 class InsertAliasCheck : public ClangTidyCheck { 24 public: 25 InsertAliasCheck(StringRef Name, ClangTidyContext *Context) 26 :ClangTidyCheck(Name, Context) {} 27 void registerMatchers(ast_matchers::MatchFinder *Finder) override { 28 Finder->addMatcher(ast_matchers::callExpr().bind("foo"), this); 29 } 30 void check(const ast_matchers::MatchFinder::MatchResult &Result) override { 31 if (!Aliaser) 32 Aliaser.reset(new NamespaceAliaser(*Result.SourceManager)); 33 34 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("foo"); 35 assert(Call != nullptr && "Did not find node \"foo\""); 36 auto Hint = Aliaser->createAlias(*Result.Context, *Call, "::foo::bar", 37 {"b", "some_alias"}); 38 if (Hint.hasValue()) 39 diag(Call->getBeginLoc(), "Fix for testing") << Hint.getValue(); 40 41 diag(Call->getBeginLoc(), "insert call") << FixItHint::CreateInsertion( 42 Call->getBeginLoc(), 43 Aliaser->getNamespaceName(*Result.Context, *Call, "::foo::bar") + "::"); 44 } 45 46 private: 47 std::unique_ptr<NamespaceAliaser> Aliaser; 48 }; 49 50 template <typename Check> 51 std::string runChecker(StringRef Code, unsigned ExpectedWarningCount) { 52 std::map<StringRef, StringRef> AdditionalFileContents = {{"foo.h", 53 "namespace foo {\n" 54 "namespace bar {\n" 55 "}\n" 56 "void func() { }\n" 57 "}"}}; 58 std::vector<ClangTidyError> errors; 59 60 std::string result = 61 test::runCheckOnCode<Check>(Code, &errors, "foo.cc", None, 62 ClangTidyOptions(), AdditionalFileContents); 63 64 EXPECT_EQ(ExpectedWarningCount, errors.size()); 65 return result; 66 } 67 68 TEST(NamespaceAliaserTest, AddNewAlias) { 69 EXPECT_EQ("#include \"foo.h\"\n" 70 "void f() {\n" 71 "namespace b = ::foo::bar;" 72 " b::f(); }", 73 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 74 "void f() { f(); }", 75 2)); 76 } 77 78 TEST(NamespaceAliaserTest, ReuseAlias) { 79 EXPECT_EQ( 80 "#include \"foo.h\"\n" 81 "void f() { namespace x = foo::bar; x::f(); }", 82 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 83 "void f() { namespace x = foo::bar; f(); }", 84 1)); 85 } 86 87 TEST(NamespaceAliaserTest, AddsOnlyOneAlias) { 88 EXPECT_EQ("#include \"foo.h\"\n" 89 "void f() {\n" 90 "namespace b = ::foo::bar;" 91 " b::f(); b::f(); }", 92 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 93 "void f() { f(); f(); }", 94 3)); 95 } 96 97 TEST(NamespaceAliaserTest, LocalConflict) { 98 EXPECT_EQ("#include \"foo.h\"\n" 99 "void f() {\n" 100 "namespace some_alias = ::foo::bar;" 101 " namespace b = foo; some_alias::f(); }", 102 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 103 "void f() { namespace b = foo; f(); }", 104 2)); 105 } 106 107 TEST(NamespaceAliaserTest, GlobalConflict) { 108 EXPECT_EQ("#include \"foo.h\"\n" 109 "namespace b = foo;\n" 110 "void f() {\n" 111 "namespace some_alias = ::foo::bar;" 112 " some_alias::f(); }", 113 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 114 "namespace b = foo;\n" 115 "void f() { f(); }", 116 2)); 117 } 118 119 } // namespace utils 120 } // namespace tidy 121 } // namespace clang 122