14 #include "clang/Frontend/CompilerInstance.h" 15 #include "clang/Frontend/CompilerInvocation.h" 16 #include "clang/Frontend/FrontendActions.h" 17 #include "clang/Lex/PreprocessorOptions.h" 18 #include "llvm/Support/Path.h" 19 #include "gmock/gmock.h" 20 #include "gtest/gtest.h" 26 using ::testing::AllOf;
27 using ::testing::ElementsAre;
28 using ::testing::UnorderedElementsAre;
30 class HeadersTest :
public ::testing::Test {
40 std::unique_ptr<CompilerInstance> setupClang() {
42 assert(static_cast<bool>(Cmd));
43 auto VFS =
FS.getFileSystem();
44 VFS->setCurrentWorkingDirectory(Cmd->Directory);
47 PI.CompileCommand = *Cmd;
50 EXPECT_TRUE(static_cast<bool>(CI));
52 CI->getDiagnosticOpts().IgnoreWarnings =
true;
54 std::move(CI),
nullptr,
58 EXPECT_FALSE(Clang->getFrontendOpts().Inputs.empty());
63 IncludeStructure collectIncludes() {
64 auto Clang = setupClang();
65 PreprocessOnlyAction
Action;
67 Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
68 IncludeStructure Includes;
69 Clang->getPreprocessor().addPPCallbacks(
71 EXPECT_FALSE(Action.Execute());
72 Action.EndSourceFile();
79 const std::vector<Inclusion> &Inclusions = {}) {
80 auto Clang = setupClang();
81 PreprocessOnlyAction
Action;
83 Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
85 if (Preferred.empty())
87 auto ToHeaderFile = [](llvm::StringRef Header) {
88 return HeaderFile{Header,
89 !llvm::sys::path::is_absolute(Header)};
92 IncludeInserter Inserter(
MainFile,
"", format::getLLVMStyle(),
94 &Clang->getPreprocessor().getHeaderSearchInfo());
95 for (
const auto &Inc : Inclusions)
96 Inserter.addExisting(Inc);
97 auto Inserted = ToHeaderFile(Preferred);
98 if (!Inserter.shouldInsertInclude(Original, Inserted))
100 auto Path = Inserter.calculateIncludePath(Inserted,
MainFile);
101 Action.EndSourceFile();
102 return Path.getValueOr(
"");
105 llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) {
106 auto Clang = setupClang();
107 PreprocessOnlyAction
Action;
109 Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
111 IncludeInserter Inserter(
MainFile,
"", format::getLLVMStyle(),
113 &Clang->getPreprocessor().getHeaderSearchInfo());
114 auto Edit = Inserter.insert(VerbatimHeader);
115 Action.EndSourceFile();
120 MockCompilationDatabase
CDB;
129 MATCHER_P(IncludeLine, N,
"") {
return arg.R.start.line == N; }
131 MATCHER_P2(Distance,
File, D,
"") {
132 if (arg.getKey() !=
File)
133 *result_listener <<
"file =" << arg.getKey().str();
134 if (arg.getValue() != D)
135 *result_listener <<
"distance =" << arg.getValue();
136 return arg.getKey() ==
File && arg.getValue() == D;
139 TEST_F(HeadersTest, CollectRewrittenAndResolved) {
141 #include "sub/bar.h" // not shortest 143 std::string BarHeader = testPath("sub/bar.h");
144 FS.Files[BarHeader] =
"";
146 EXPECT_THAT(collectIncludes().MainFileIncludes,
147 UnorderedElementsAre(
148 AllOf(Written(
"\"sub/bar.h\""), Resolved(BarHeader))));
149 EXPECT_THAT(collectIncludes().includeDepth(MainFile),
150 UnorderedElementsAre(Distance(MainFile, 0u),
151 Distance(
testPath(
"sub/bar.h"), 1u)));
154 TEST_F(HeadersTest, OnlyCollectInclusionsInMain) {
155 std::string BazHeader =
testPath(
"sub/baz.h");
156 FS.Files[BazHeader] =
"";
157 std::string BarHeader =
testPath(
"sub/bar.h");
158 FS.Files[BarHeader] = R
"cpp( 165 collectIncludes().MainFileIncludes, 166 UnorderedElementsAre(AllOf(Written("\"bar.h\""), Resolved(BarHeader))));
167 EXPECT_THAT(collectIncludes().includeDepth(MainFile),
168 UnorderedElementsAre(Distance(MainFile, 0u),
169 Distance(
testPath(
"sub/bar.h"), 1u),
170 Distance(
testPath(
"sub/baz.h"), 2u)));
172 EXPECT_THAT(collectIncludes().includeDepth(
testPath(
"sub/bar.h")),
173 UnorderedElementsAre(Distance(
testPath(
"sub/bar.h"), 0u),
174 Distance(
testPath(
"sub/baz.h"), 1u)));
177 TEST_F(HeadersTest, PreambleIncludesPresentOnce) {
188 TU.HeaderFilename = "a.h";
189 EXPECT_THAT(TU.build().getIncludeStructure().MainFileIncludes,
190 ElementsAre(IncludeLine(1), IncludeLine(3), IncludeLine(5)));
193 TEST_F(HeadersTest, UnResolvedInclusion) {
198 EXPECT_THAT(collectIncludes().MainFileIncludes, 199 UnorderedElementsAre(AllOf(Written("\"foo.h\""), Resolved(
""))));
200 EXPECT_THAT(collectIncludes().includeDepth(MainFile),
201 UnorderedElementsAre(Distance(MainFile, 0u)));
204 TEST_F(HeadersTest, InsertInclude) {
207 EXPECT_EQ(calculate(Path),
"\"bar.h\"");
210 TEST_F(HeadersTest, DoNotInsertIfInSameFile) {
212 EXPECT_EQ(calculate(MainFile),
"");
215 TEST_F(HeadersTest, DoNotInsertOffIncludePath) {
216 MainFile =
testPath(
"sub/main.cpp");
217 EXPECT_EQ(calculate(
testPath(
"sub2/main.cpp")),
"");
220 TEST_F(HeadersTest, ShortenIncludesInSearchPath) {
221 std::string BarHeader =
testPath(
"sub/bar.h");
222 EXPECT_EQ(calculate(BarHeader),
"\"bar.h\"");
224 SearchDirArg = (llvm::Twine(
"-I") + Subdir +
"/..").str();
225 CDB.ExtraClangFlags = {SearchDirArg.c_str()};
227 EXPECT_EQ(calculate(BarHeader),
"\"sub/bar.h\"");
230 TEST_F(HeadersTest, ShortenedIncludeNotInSearchPath) {
231 std::string BarHeader =
232 llvm::sys::path::convert_to_slash(
testPath(
"sub-2/bar.h"));
233 EXPECT_EQ(calculate(BarHeader,
""),
"\"sub-2/bar.h\"");
236 TEST_F(HeadersTest, PreferredHeader) {
237 std::string BarHeader =
testPath(
"sub/bar.h");
238 EXPECT_EQ(calculate(BarHeader,
"<bar>"),
"<bar>");
240 std::string BazHeader =
testPath(
"sub/baz.h");
241 EXPECT_EQ(calculate(BarHeader, BazHeader),
"\"baz.h\"");
244 TEST_F(HeadersTest, DontInsertDuplicatePreferred) {
246 Inc.Written =
"\"bar.h\"";
248 EXPECT_EQ(calculate(
testPath(
"sub/bar.h"),
"\"bar.h\"", {Inc}),
"");
249 EXPECT_EQ(calculate(
"\"x.h\"",
"\"bar.h\"", {Inc}),
"");
252 TEST_F(HeadersTest, DontInsertDuplicateResolved) {
254 Inc.Written =
"fake-bar.h";
255 Inc.Resolved =
testPath(
"sub/bar.h");
256 EXPECT_EQ(calculate(Inc.Resolved,
"", {Inc}),
"");
258 EXPECT_EQ(calculate(Inc.Resolved,
"\"BAR.h\"", {Inc}),
"");
261 TEST_F(HeadersTest, PreferInserted) {
262 auto Edit = insert(
"<y>");
263 EXPECT_TRUE(Edit.hasValue());
264 EXPECT_TRUE(StringRef(Edit->newText).contains(
"<y>"));
267 TEST(Headers, NoHeaderSearchInfo) {
268 std::string MainFile =
testPath(
"main.cpp");
269 IncludeInserter Inserter(MainFile,
"", format::getLLVMStyle(),
272 auto HeaderPath =
testPath(
"sub/bar.h");
273 auto Inserting = HeaderFile{HeaderPath,
false};
274 auto Verbatim = HeaderFile{
"<x>",
true};
276 EXPECT_EQ(Inserter.calculateIncludePath(Inserting, MainFile),
277 std::string(
"\"sub/bar.h\""));
278 EXPECT_EQ(Inserter.shouldInsertInclude(HeaderPath, Inserting),
false);
280 EXPECT_EQ(Inserter.calculateIncludePath(Verbatim, MainFile),
282 EXPECT_EQ(Inserter.shouldInsertInclude(HeaderPath, Verbatim),
true);
284 EXPECT_EQ(Inserter.calculateIncludePath(Inserting,
"sub2/main2.cpp"),
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
Documents should not be synced at all.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
TEST(BackgroundQueueTest, Priority)
std::string testPath(PathRef File)
llvm::unique_function< void()> Action
std::string Path
A typedef to represent a file path.
static constexpr llvm::StringLiteral Name
static TestTU withCode(llvm::StringRef Code)
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.