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:
InsertAliasCheck(StringRef Name,ClangTidyContext * Context)24   InsertAliasCheck(StringRef Name, ClangTidyContext *Context)
25       :ClangTidyCheck(Name, Context) {}
registerMatchers(ast_matchers::MatchFinder * Finder)26   void registerMatchers(ast_matchers::MatchFinder *Finder) override {
27     Finder->addMatcher(ast_matchers::callExpr().bind("foo"), this);
28   }
check(const ast_matchers::MatchFinder::MatchResult & Result)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.hasValue())
38       diag(Call->getBeginLoc(), "Fix for testing") << Hint.getValue();
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>
runChecker(StringRef Code,unsigned ExpectedWarningCount)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 
TEST(NamespaceAliaserTest,AddNewAlias)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 
TEST(NamespaceAliaserTest,ReuseAlias)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 
TEST(NamespaceAliaserTest,AddsOnlyOneAlias)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 
TEST(NamespaceAliaserTest,LocalConflict)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 
TEST(NamespaceAliaserTest,GlobalConflict)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