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