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 = test::runCheckOnCode<Check>( 60 Code, &errors, "foo.cc", {}, ClangTidyOptions(), AdditionalFileContents); 61 62 EXPECT_EQ(ExpectedWarningCount, errors.size()); 63 return result; 64 } 65 66 TEST(NamespaceAliaserTest, AddNewAlias) { 67 EXPECT_EQ("#include \"foo.h\"\n" 68 "void f() {\n" 69 "namespace b = ::foo::bar;" 70 " b::f(); }", 71 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 72 "void f() { f(); }", 73 2)); 74 } 75 76 TEST(NamespaceAliaserTest, ReuseAlias) { 77 EXPECT_EQ( 78 "#include \"foo.h\"\n" 79 "void f() { namespace x = foo::bar; x::f(); }", 80 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 81 "void f() { namespace x = foo::bar; f(); }", 82 1)); 83 } 84 85 TEST(NamespaceAliaserTest, AddsOnlyOneAlias) { 86 EXPECT_EQ("#include \"foo.h\"\n" 87 "void f() {\n" 88 "namespace b = ::foo::bar;" 89 " b::f(); b::f(); }", 90 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 91 "void f() { f(); f(); }", 92 3)); 93 } 94 95 TEST(NamespaceAliaserTest, LocalConflict) { 96 EXPECT_EQ("#include \"foo.h\"\n" 97 "void f() {\n" 98 "namespace some_alias = ::foo::bar;" 99 " namespace b = foo; some_alias::f(); }", 100 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 101 "void f() { namespace b = foo; f(); }", 102 2)); 103 } 104 105 TEST(NamespaceAliaserTest, GlobalConflict) { 106 EXPECT_EQ("#include \"foo.h\"\n" 107 "namespace b = foo;\n" 108 "void f() {\n" 109 "namespace some_alias = ::foo::bar;" 110 " some_alias::f(); }", 111 runChecker<InsertAliasCheck>("#include \"foo.h\"\n" 112 "namespace b = foo;\n" 113 "void f() { f(); }", 114 2)); 115 } 116 117 } // namespace utils 118 } // namespace tidy 119 } // namespace clang 120