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 CallExpr *Call = 35 Result.Nodes.getNodeAs<CallExpr>("foo"); 36 assert(Call != nullptr && "Did not find node \"foo\""); 37 auto Hint = Aliaser->createAlias(*Result.Context, *Call, "::foo::bar", 38 {"b", "some_alias"}); 39 if (Hint.hasValue()) 40 diag(Call->getLocStart(), "Fix for testing") << Hint.getValue(); 41 42 diag(Call->getLocStart(), "insert call") 43 << FixItHint::CreateInsertion( 44 Call->getLocStart(), 45 Aliaser->getNamespaceName(*Result.Context, *Call, "::foo::bar") + 46 "::"); 47 } 48 49 private: 50 std::unique_ptr<NamespaceAliaser> Aliaser; 51 }; 52 53 template <typename Check> 54 std::string runChecker(StringRef Code, int ExpectedWarningCount) { 55 std::map<StringRef, StringRef> AdditionalFileContents = {{"foo.h", 56 "namespace foo {\n" 57 "namespace bar {\n" 58 "}\n" 59 "void func() { }\n" 60 "}"}}; 61 std::vector<ClangTidyError> errors; 62 63 std::string result = 64 test::runCheckOnCode<Check>(Code, &errors, "foo.cc", None, 65 ClangTidyOptions(), AdditionalFileContents); 66 67 EXPECT_EQ(ExpectedWarningCount, errors.size()); 68 return result; 69 } 70 71 TEST(NamespaceAliaserTest, AddNewAlias) { 72 EXPECT_EQ("#include \"foo.h\"\n" 73 "void f() {\n" 74 "namespace b = ::foo::bar;" 75 " b::f(); }", 76 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 77 "void f() { f(); }", 78 2)); 79 } 80 81 TEST(NamespaceAliaserTest, ReuseAlias) { 82 EXPECT_EQ( 83 "#include \"foo.h\"\n" 84 "void f() { namespace x = foo::bar; x::f(); }", 85 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 86 "void f() { namespace x = foo::bar; f(); }", 87 1)); 88 } 89 90 TEST(NamespaceAliaserTest, AddsOnlyOneAlias) { 91 EXPECT_EQ("#include \"foo.h\"\n" 92 "void f() {\n" 93 "namespace b = ::foo::bar;" 94 " b::f(); b::f(); }", 95 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 96 "void f() { f(); f(); }", 97 3)); 98 } 99 100 TEST(NamespaceAliaserTest, LocalConflict) { 101 EXPECT_EQ("#include \"foo.h\"\n" 102 "void f() {\n" 103 "namespace some_alias = ::foo::bar;" 104 " namespace b = foo; some_alias::f(); }", 105 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 106 "void f() { namespace b = foo; f(); }", 107 2)); 108 } 109 110 TEST(NamespaceAliaserTest, GlobalConflict) { 111 EXPECT_EQ("#include \"foo.h\"\n" 112 "namespace b = foo;\n" 113 "void f() {\n" 114 "namespace some_alias = ::foo::bar;" 115 " some_alias::f(); }", 116 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 117 "namespace b = foo;\n" 118 "void f() { f(); }", 119 2)); 120 } 121 122 } // namespace utils 123 } // namespace tidy 124 } // namespace clang 125