blob: a9b123ae278e50fb0dd9e4f5173f73463683cd94 [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>"}},
Benjamin Kramerc3459a52016-05-10 08:25:28 +000052 {"std::sting", {"\"sting\""}},
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000053 {"std::string::size_type", {"<string>"}},
54 {"a::b::foo", {"dir/otherdir/qux.h"}},
55 };
Eric Liu692aca62016-05-04 08:22:35 +000056 auto XrefsDBMgr = llvm::make_unique<include_fixer::XrefsDBManager>();
57 XrefsDBMgr->addXrefsDB(
58 llvm::make_unique<include_fixer::InMemoryXrefsDB>(std::move(XrefsMap)));
59
Benjamin Kramer6b236262016-04-20 12:43:43 +000060 std::vector<clang::tooling::Replacement> Replacements;
Eric Liu692aca62016-05-04 08:22:35 +000061 IncludeFixerActionFactory Factory(*XrefsDBMgr, Replacements);
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000062 runOnCode(&Factory, Code, "input.cc", ExtraArgs);
Benjamin Kramer6b236262016-04-20 12:43:43 +000063 clang::RewriterTestContext Context;
64 clang::FileID ID = Context.createInMemoryFile("input.cc", Code);
65 clang::tooling::applyAllReplacements(Replacements, Context.Rewrite);
66 return Context.getRewrittenText(ID);
67}
68
69TEST(IncludeFixer, Typo) {
70 EXPECT_EQ("#include <string>\nstd::string foo;\n",
71 runIncludeFixer("std::string foo;\n"));
72
73 EXPECT_EQ(
74 "// comment\n#include <string>\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000075 "#include \"dir/bar.h\"\n",
Benjamin Kramer6b236262016-04-20 12:43:43 +000076 runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000077 "#include \"dir/bar.h\"\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000078
79 EXPECT_EQ("#include <string>\n#include \"foo.h\"\nstd::string foo;\n",
80 runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
81
82 EXPECT_EQ(
83 "#include <string>\n#include \"foo.h\"\nstd::string::size_type foo;\n",
84 runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
85
Eric Liu692aca62016-05-04 08:22:35 +000086 // string without "std::" can also be fixed since fixed db results go through
87 // XrefsDBManager, and XrefsDBManager matches unqualified identifiers too.
88 EXPECT_EQ("#include <string>\nstring foo;\n",
89 runIncludeFixer("string foo;\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000090}
91
92TEST(IncludeFixer, IncompleteType) {
93 EXPECT_EQ(
94 "#include <string>\n#include \"foo.h\"\n"
95 "namespace std {\nclass string;\n}\nstring foo;\n",
96 runIncludeFixer("#include \"foo.h\"\n"
97 "namespace std {\nclass string;\n}\nstring foo;\n"));
98}
99
Benjamin Kramer3a45fab2016-04-28 11:21:29 +0000100TEST(IncludeFixer, MinimizeInclude) {
101 std::vector<std::string> IncludePath = {"-Idir/"};
102 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
103 runIncludeFixer("a::b::foo bar;\n", IncludePath));
104
105 IncludePath = {"-isystemdir"};
106 EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
107 runIncludeFixer("a::b::foo bar;\n", IncludePath));
108
109 IncludePath = {"-iquotedir"};
110 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
111 runIncludeFixer("a::b::foo bar;\n", IncludePath));
112
113 IncludePath = {"-Idir", "-Idir/otherdir"};
114 EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
115 runIncludeFixer("a::b::foo bar;\n", IncludePath));
116}
117
NAKAMURA Takumic92b8e52016-05-10 22:46:32 +0000118#if 0
119// It doesn't pass for targeting win32. Investigating.
Benjamin Kramerad935002016-05-10 08:25:31 +0000120TEST(IncludeFixer, NestedName) {
121 EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
122 "namespace a {}\nint a = a::b::foo(0);\n",
123 runIncludeFixer("namespace a {}\nint a = a::b::foo(0);\n"));
124}
NAKAMURA Takumic92b8e52016-05-10 22:46:32 +0000125#endif
Benjamin Kramerad935002016-05-10 08:25:31 +0000126
Benjamin Kramerc3459a52016-05-10 08:25:28 +0000127TEST(IncludeFixer, MultipleMissingSymbols) {
128 EXPECT_EQ("#include <string>\nstd::string bar;\nstd::sting foo;\n",
129 runIncludeFixer("std::string bar;\nstd::sting foo;\n"));
130}
131
Benjamin Kramer6b236262016-04-20 12:43:43 +0000132} // namespace
133} // namespace include_fixer
134} // namespace clang