blob: 5b500687e4a7c91159427681efea780e32614ada [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"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000012#include "unittests/Tooling/RewriterTestContext.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000013#include "clang/Tooling/Tooling.h"
14#include "gtest/gtest.h"
15using namespace clang;
16
17namespace clang {
18namespace include_fixer {
19namespace {
20
21static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000022 StringRef FileName,
23 const std::vector<std::string> &ExtraArgs) {
Benjamin Kramer6b236262016-04-20 12:43:43 +000024 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
25 new vfs::InMemoryFileSystem);
26 llvm::IntrusiveRefCntPtr<FileManager> Files(
27 new FileManager(FileSystemOptions(), InMemoryFileSystem));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000028 std::vector<std::string> Args = {"include_fixer", "-fsyntax-only", FileName};
29 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
Benjamin Kramer6b236262016-04-20 12:43:43 +000030 tooling::ToolInvocation Invocation(
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000031 Args, ToolAction, Files.get(),
32 std::make_shared<PCHContainerOperations>());
Benjamin Kramer6b236262016-04-20 12:43:43 +000033
34 InMemoryFileSystem->addFile(FileName, 0,
35 llvm::MemoryBuffer::getMemBuffer(Code));
36
37 InMemoryFileSystem->addFile("foo.h", 0,
38 llvm::MemoryBuffer::getMemBuffer("\n"));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000039 InMemoryFileSystem->addFile("dir/bar.h", 0,
40 llvm::MemoryBuffer::getMemBuffer("\n"));
41 InMemoryFileSystem->addFile("dir/otherdir/qux.h", 0,
Benjamin Kramer6b236262016-04-20 12:43:43 +000042 llvm::MemoryBuffer::getMemBuffer("\n"));
43 return Invocation.run();
44}
45
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000046static std::string runIncludeFixer(
47 StringRef Code,
48 const std::vector<std::string> &ExtraArgs = std::vector<std::string>()) {
Benjamin Kramer6b236262016-04-20 12:43:43 +000049 std::map<std::string, std::vector<std::string>> XrefsMap = {
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000050 {"std::string", {"<string>"}},
51 {"std::string::size_type", {"<string>"}},
52 {"a::b::foo", {"dir/otherdir/qux.h"}},
53 };
Benjamin Kramer6b236262016-04-20 12:43:43 +000054 auto XrefsDB =
55 llvm::make_unique<include_fixer::InMemoryXrefsDB>(std::move(XrefsMap));
56 std::vector<clang::tooling::Replacement> Replacements;
57 IncludeFixerActionFactory Factory(*XrefsDB, Replacements);
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000058 runOnCode(&Factory, Code, "input.cc", ExtraArgs);
Benjamin Kramer6b236262016-04-20 12:43:43 +000059 clang::RewriterTestContext Context;
60 clang::FileID ID = Context.createInMemoryFile("input.cc", Code);
61 clang::tooling::applyAllReplacements(Replacements, Context.Rewrite);
62 return Context.getRewrittenText(ID);
63}
64
65TEST(IncludeFixer, Typo) {
66 EXPECT_EQ("#include <string>\nstd::string foo;\n",
67 runIncludeFixer("std::string foo;\n"));
68
69 EXPECT_EQ(
70 "// comment\n#include <string>\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000071 "#include \"dir/bar.h\"\n",
Benjamin Kramer6b236262016-04-20 12:43:43 +000072 runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000073 "#include \"dir/bar.h\"\n"));
Benjamin Kramer6b236262016-04-20 12:43:43 +000074
75 EXPECT_EQ("#include <string>\n#include \"foo.h\"\nstd::string foo;\n",
76 runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
77
78 EXPECT_EQ(
79 "#include <string>\n#include \"foo.h\"\nstd::string::size_type foo;\n",
80 runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
81
82 // The fixed xrefs db doesn't know how to handle string without std::.
83 EXPECT_EQ("string foo;\n", runIncludeFixer("string foo;\n"));
84}
85
86TEST(IncludeFixer, IncompleteType) {
87 EXPECT_EQ(
88 "#include <string>\n#include \"foo.h\"\n"
89 "namespace std {\nclass string;\n}\nstring foo;\n",
90 runIncludeFixer("#include \"foo.h\"\n"
91 "namespace std {\nclass string;\n}\nstring foo;\n"));
92}
93
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000094TEST(IncludeFixer, MinimizeInclude) {
95 std::vector<std::string> IncludePath = {"-Idir/"};
96 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
97 runIncludeFixer("a::b::foo bar;\n", IncludePath));
98
99 IncludePath = {"-isystemdir"};
100 EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
101 runIncludeFixer("a::b::foo bar;\n", IncludePath));
102
103 IncludePath = {"-iquotedir"};
104 EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
105 runIncludeFixer("a::b::foo bar;\n", IncludePath));
106
107 IncludePath = {"-Idir", "-Idir/otherdir"};
108 EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
109 runIncludeFixer("a::b::foo bar;\n", IncludePath));
110}
111
Benjamin Kramer6b236262016-04-20 12:43:43 +0000112} // namespace
113} // namespace include_fixer
114} // namespace clang