xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/NamespaceAliaserTest.cpp (revision fc5de0af33b7fb9b9f745e70dcd351f2de4211cb)
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