blob: 05fb8905706b43b1edab774b37f462e7597c521d [file] [log] [blame]
Benjamin Kramer6b236262016-04-20 12:43:43 +00001//===-- IncludeFixerTest.cpp - Include fixer unit tests -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Benjamin Kramer6b236262016-04-20 12:43:43 +000010#include "InMemoryXrefsDB.h"
11#include "IncludeFixer.h"
Eric Liu692aca62016-05-04 08:22:35 +000012#include "XrefsDBManager.h"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000013#include "unittests/Tooling/RewriterTestContext.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000014#include "clang/Tooling/Tooling.h"
15#include "gtest/gtest.h"
16using namespace clang;
17
18namespace clang {
19namespace include_fixer {
20namespace {
21
22static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000023 StringRef FileName,
24 const std::vector<std::string> &ExtraArgs) {
Benjamin Kramer6b236262016-04-20 12:43:43 +000025 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
26 new vfs::InMemoryFileSystem);
27 llvm::IntrusiveRefCntPtr<FileManager> Files(
28 new FileManager(FileSystemOptions(), InMemoryFileSystem));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000029 std::vector<std::string> Args = {"include_fixer", "-fsyntax-only", FileName};
30 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
Benjamin Kramer6b236262016-04-20 12:43:43 +000031 tooling::ToolInvocation Invocation(
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000032 Args, ToolAction, Files.get(),
33 std::make_shared<PCHContainerOperations>());
Benjamin Kramer6b236262016-04-20 12:43:43 +000034
35 InMemoryFileSystem->addFile(FileName, 0,
36 llvm::MemoryBuffer::getMemBuffer(Code));
37
38 InMemoryFileSystem->addFile("foo.h", 0,
39 llvm::MemoryBuffer::getMemBuffer("\n"));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000040 InMemoryFileSystem->addFile("dir/bar.h", 0,
41 llvm::MemoryBuffer::getMemBuffer("\n"));
42 InMemoryFileSystem->addFile("dir/otherdir/qux.h", 0,
Benjamin Kramer6b236262016-04-20 12:43:43 +000043 llvm::MemoryBuffer::getMemBuffer("\n"));
44 return Invocation.run();
45}
46
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000047static std::string runIncludeFixer(
48 StringRef Code,
49 const std::vector<std::string> &ExtraArgs = std::vector<std::string>()) {
Benjamin Kramer6b236262016-04-20 12:43:43 +000050 std::map<std::string, std::vector<std::string>> XrefsMap = {
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000051 {"std::string", {"<string>"}},
52 {"std::string::size_type", {"<string>"}},
53 {"a::b::foo", {"dir/otherdir/qux.h"}},
54 };
Eric Liu692aca62016-05-04 08:22:35 +000055 auto XrefsDBMgr = llvm::make_unique<include_fixer::XrefsDBManager>();
56 XrefsDBMgr->addXrefsDB(
57 llvm::make_unique<include_fixer::InMemoryXrefsDB>(std::move(XrefsMap)));
58
Benjamin Kramer6b236262016-04-20 12:43:43 +000059 std::vector<clang::tooling::Replacement> Replacements;
Eric Liu692aca62016-05-04 08:22:35 +000060 IncludeFixerActionFactory Factory(*XrefsDBMgr, Replacements);
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000061 runOnCode(&Factory, Code, "input.cc", ExtraArgs);
Benjamin Kramer6b236262016-04-20 12:43:43 +000062 clang::RewriterTestContext Context;
63 clang::FileID ID = Context.createInMemoryFile("input.cc", Code);
64 clang::tooling::applyAllReplacements(Replacements, Context.Rewrite);
65 return Context.getRewrittenText(ID);
66}
67
68TEST(IncludeFixer, Typo) {
69 EXPECT_EQ("#include <string>\nstd::string foo;\n",
70 runIncludeFixer("std::string foo;\n"));
71
72 EXPECT_EQ(
73 "// comment\n#include <string>\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000074 "#include \"dir/bar.h\"\n",
Benjamin Kramer6b236262016-04-20 12:43:43 +000075 runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000076 "#include \"dir/bar.h\"\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000077
78 EXPECT_EQ("#include <string>\n#include \"foo.h\"\nstd::string foo;\n",
79 runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
80
81 EXPECT_EQ(
82 "#include <string>\n#include \"foo.h\"\nstd::string::size_type foo;\n",
83 runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
84
Eric Liu692aca62016-05-04 08:22:35 +000085 // string without "std::" can also be fixed since fixed db results go through
86 // XrefsDBManager, and XrefsDBManager matches unqualified identifiers too.
87 EXPECT_EQ("#include <string>\nstring foo;\n",
88 runIncludeFixer("string foo;\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000089}
90
91TEST(IncludeFixer, IncompleteType) {
92 EXPECT_EQ(
93 "#include <string>\n#include \"foo.h\"\n"
94 "namespace std {\nclass string;\n}\nstring foo;\n",
95 runIncludeFixer("#include \"foo.h\"\n"
96 "namespace std {\nclass string;\n}\nstring foo;\n"));
97}
98
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000099TEST(IncludeFixer, MinimizeInclude) {
100 std::vector<std::string> IncludePath = {"-Idir/"};
101 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
102 runIncludeFixer("a::b::foo bar;\n", IncludePath));
103
104 IncludePath = {"-isystemdir"};
105 EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
106 runIncludeFixer("a::b::foo bar;\n", IncludePath));
107
108 IncludePath = {"-iquotedir"};
109 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
110 runIncludeFixer("a::b::foo bar;\n", IncludePath));
111
112 IncludePath = {"-Idir", "-Idir/otherdir"};
113 EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
114 runIncludeFixer("a::b::foo bar;\n", IncludePath));
115}
116
Benjamin Kramer6b236262016-04-20 12:43:43 +0000117} // namespace
118} // namespace include_fixer
119} // namespace clang