blob: 8f6304fcb8e4da5f322f9ffb5c3cbb4ab2a56e3d [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 Kramera3d82332016-05-13 09:27:54 +000010#include "InMemorySymbolIndex.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000011#include "IncludeFixer.h"
Benjamin Kramera3d82332016-05-13 09:27:54 +000012#include "SymbolIndexManager.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 Kramera3d82332016-05-13 09:27:54 +000050 std::map<std::string, std::vector<std::string>> SymbolsMap = {
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 };
Benjamin Kramera3d82332016-05-13 09:27:54 +000056 auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
57 SymbolIndexMgr->addSymbolIndex(
58 llvm::make_unique<include_fixer::InMemorySymbolIndex>(
59 std::move(SymbolsMap)));
Eric Liu692aca62016-05-04 08:22:35 +000060
Benjamin Kramer6b236262016-04-20 12:43:43 +000061 std::vector<clang::tooling::Replacement> Replacements;
Benjamin Kramera3d82332016-05-13 09:27:54 +000062 IncludeFixerActionFactory Factory(*SymbolIndexMgr, Replacements);
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000063 runOnCode(&Factory, Code, "input.cc", ExtraArgs);
Benjamin Kramer6b236262016-04-20 12:43:43 +000064 clang::RewriterTestContext Context;
65 clang::FileID ID = Context.createInMemoryFile("input.cc", Code);
66 clang::tooling::applyAllReplacements(Replacements, Context.Rewrite);
67 return Context.getRewrittenText(ID);
68}
69
70TEST(IncludeFixer, Typo) {
71 EXPECT_EQ("#include <string>\nstd::string foo;\n",
72 runIncludeFixer("std::string foo;\n"));
73
74 EXPECT_EQ(
75 "// comment\n#include <string>\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 runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000078 "#include \"dir/bar.h\"\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000079
80 EXPECT_EQ("#include <string>\n#include \"foo.h\"\nstd::string foo;\n",
81 runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
82
83 EXPECT_EQ(
84 "#include <string>\n#include \"foo.h\"\nstd::string::size_type foo;\n",
85 runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
86
Eric Liu692aca62016-05-04 08:22:35 +000087 // string without "std::" can also be fixed since fixed db results go through
Benjamin Kramera3d82332016-05-13 09:27:54 +000088 // SymbolIndexManager, and SymbolIndexManager matches unqualified identifiers
89 // too.
Eric Liu692aca62016-05-04 08:22:35 +000090 EXPECT_EQ("#include <string>\nstring foo;\n",
91 runIncludeFixer("string foo;\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000092}
93
94TEST(IncludeFixer, IncompleteType) {
95 EXPECT_EQ(
96 "#include <string>\n#include \"foo.h\"\n"
97 "namespace std {\nclass string;\n}\nstring foo;\n",
98 runIncludeFixer("#include \"foo.h\"\n"
99 "namespace std {\nclass string;\n}\nstring foo;\n"));
100}
101
Benjamin Kramer3a45fab2016-04-28 11:21:29 +0000102TEST(IncludeFixer, MinimizeInclude) {
103 std::vector<std::string> IncludePath = {"-Idir/"};
104 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
105 runIncludeFixer("a::b::foo bar;\n", IncludePath));
106
107 IncludePath = {"-isystemdir"};
108 EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
109 runIncludeFixer("a::b::foo bar;\n", IncludePath));
110
111 IncludePath = {"-iquotedir"};
112 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
113 runIncludeFixer("a::b::foo bar;\n", IncludePath));
114
115 IncludePath = {"-Idir", "-Idir/otherdir"};
116 EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
117 runIncludeFixer("a::b::foo bar;\n", IncludePath));
118}
119
NAKAMURA Takumic92b8e52016-05-10 22:46:32 +0000120#if 0
121// It doesn't pass for targeting win32. Investigating.
Benjamin Kramerad935002016-05-10 08:25:31 +0000122TEST(IncludeFixer, NestedName) {
123 EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
124 "namespace a {}\nint a = a::b::foo(0);\n",
125 runIncludeFixer("namespace a {}\nint a = a::b::foo(0);\n"));
126}
NAKAMURA Takumic92b8e52016-05-10 22:46:32 +0000127#endif
Benjamin Kramerad935002016-05-10 08:25:31 +0000128
Benjamin Kramerc3459a52016-05-10 08:25:28 +0000129TEST(IncludeFixer, MultipleMissingSymbols) {
130 EXPECT_EQ("#include <string>\nstd::string bar;\nstd::sting foo;\n",
131 runIncludeFixer("std::string bar;\nstd::sting foo;\n"));
132}
133
Benjamin Kramer6b236262016-04-20 12:43:43 +0000134} // namespace
135} // namespace include_fixer
136} // namespace clang