//===---- UsingInserterTest.cpp - clang-tidy ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "../clang-tidy/utils/UsingInserter.h" #include "ClangTidyTest.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "gtest/gtest.h" namespace clang { namespace tidy { namespace utils { // Replace all function calls with calls to foo::func. Inserts using // declarations as necessary. This checker is for testing only. It // can only run on one test case (e.g. wih one SourceManager). class InsertUsingCheck : public clang::tidy::ClangTidyCheck { public: InsertUsingCheck(StringRef Name, ClangTidyContext *Context) :ClangTidyCheck(Name, Context) {} void registerMatchers(clang::ast_matchers::MatchFinder *Finder) override { Finder->addMatcher(clang::ast_matchers::callExpr().bind("foo"), this); } void check(const clang::ast_matchers::MatchFinder::MatchResult &Result) override { if (!Inserter) Inserter.reset(new UsingInserter(*Result.SourceManager)); const auto *Call = Result.Nodes.getNodeAs("foo"); assert(Call != nullptr && "Did not find node \"foo\""); auto Hint = Inserter->createUsingDeclaration(*Result.Context, *Call, "::foo::func"); if (Hint.hasValue()) diag(Call->getBeginLoc(), "Fix for testing") << Hint.getValue(); diag(Call->getBeginLoc(), "insert call") << clang::FixItHint::CreateReplacement( Call->getCallee()->getSourceRange(), Inserter->getShortName(*Result.Context, *Call, "::foo::func")); } private: std::unique_ptr Inserter; }; template std::string runChecker(StringRef Code, unsigned ExpectedWarningCount) { std::map AdditionalFileContents = {{"foo.h", "namespace foo {\n" "namespace bar {\n" "}\n" "void func() { }\n" "}"}}; std::vector errors; std::string result = test::runCheckOnCode(Code, &errors, "foo.cc", None, ClangTidyOptions(), AdditionalFileContents); EXPECT_EQ(ExpectedWarningCount, errors.size()); return result; } TEST(UsingInserterTest, ReusesExisting) { EXPECT_EQ("#include \"foo.h\"\n" "namespace {" "using ::foo::func;\n" "void f() { func(); }" "}", runChecker("#include \"foo.h\"\n" "namespace {" "using ::foo::func;\n" "void f() { f(); }" "}", 1)); } TEST(UsingInserterTest, ReusesExistingGlobal) { EXPECT_EQ("#include \"foo.h\"\n" "using ::foo::func;\n" "namespace {" "void f() { func(); }" "}", runChecker("#include \"foo.h\"\n" "using ::foo::func;\n" "namespace {" "void f() { f(); }" "}", 1)); } TEST(UsingInserterTest, AvoidsConflict) { EXPECT_EQ("#include \"foo.h\"\n" "namespace {" "void f() { int func; ::foo::func(); }" "}", runChecker("#include \"foo.h\"\n" "namespace {" "void f() { int func; f(); }" "}", 1)); } } // namespace utils } // namespace tidy } // namespace clang