|
9 | 9 | #include "clang/Frontend/CompilerInstance.h"
|
10 | 10 | #include "clang/Basic/FileManager.h"
|
11 | 11 | #include "clang/Frontend/CompilerInvocation.h"
|
| 12 | +#include "clang/Frontend/FrontendActions.h" |
12 | 13 | #include "clang/Frontend/TextDiagnosticPrinter.h"
|
| 14 | +#include "llvm/ADT/IntrusiveRefCntPtr.h" |
13 | 15 | #include "llvm/Support/FileSystem.h"
|
14 | 16 | #include "llvm/Support/Format.h"
|
| 17 | +#include "llvm/Support/MemoryBuffer.h" |
15 | 18 | #include "llvm/Support/ToolOutputFile.h"
|
16 | 19 | #include "llvm/Support/VirtualFileSystem.h"
|
17 | 20 | #include "gtest/gtest.h"
|
@@ -97,4 +100,52 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
|
97 | 100 | ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n");
|
98 | 101 | }
|
99 | 102 |
|
| 103 | +TEST(CompilerInstance, MultipleInputsCleansFileIDs) { |
| 104 | + auto VFS = makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); |
| 105 | + VFS->addFile("a.cc", /*ModificationTime=*/{}, |
| 106 | + MemoryBuffer::getMemBuffer(R"cpp( |
| 107 | + #include "a.h" |
| 108 | + )cpp")); |
| 109 | + // Paddings of `void foo();` in the sources below are "important". We're |
| 110 | + // testing against source locations from previous compilations colliding. |
| 111 | + // Hence the `unused` variable in `b.h` needs to be within `#pragma clang |
| 112 | + // diagnostic` block from `a.h`. |
| 113 | + VFS->addFile("a.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp( |
| 114 | + #include "b.h" |
| 115 | + #pragma clang diagnostic push |
| 116 | + #pragma clang diagnostic warning "-Wunused" |
| 117 | + void foo(); |
| 118 | + #pragma clang diagnostic pop |
| 119 | + )cpp")); |
| 120 | + VFS->addFile("b.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp( |
| 121 | + void foo(); void foo(); void foo(); void foo(); |
| 122 | + inline void foo() { int unused = 2; } |
| 123 | + )cpp")); |
| 124 | + |
| 125 | + DiagnosticOptions DiagOpts; |
| 126 | + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = |
| 127 | + CompilerInstance::createDiagnostics(*VFS, DiagOpts); |
| 128 | + |
| 129 | + CreateInvocationOptions CIOpts; |
| 130 | + CIOpts.Diags = Diags; |
| 131 | + |
| 132 | + const char *Args[] = {"clang", "-xc++", "a.cc"}; |
| 133 | + std::shared_ptr<CompilerInvocation> CInvok = |
| 134 | + createInvocation(Args, std::move(CIOpts)); |
| 135 | + ASSERT_TRUE(CInvok) << "could not create compiler invocation"; |
| 136 | + |
| 137 | + CompilerInstance Instance(std::move(CInvok)); |
| 138 | + Instance.setDiagnostics(Diags.get()); |
| 139 | + Instance.createFileManager(VFS); |
| 140 | + |
| 141 | + // Run once for `a.cc` and then for `a.h`. This makes sure we get the same |
| 142 | + // file ID for `b.h` in the second run as `a.h` from first run. |
| 143 | + const auto &OrigInputKind = Instance.getFrontendOpts().Inputs[0].getKind(); |
| 144 | + Instance.getFrontendOpts().Inputs.emplace_back("a.h", OrigInputKind); |
| 145 | + |
| 146 | + SyntaxOnlyAction Act; |
| 147 | + EXPECT_TRUE(Instance.ExecuteAction(Act)) << "Failed to execute action"; |
| 148 | + EXPECT_FALSE(Diags->hasErrorOccurred()); |
| 149 | + EXPECT_EQ(Diags->getNumWarnings(), 0u); |
| 150 | +} |
100 | 151 | } // anonymous namespace
|
0 commit comments