clang: lib/Testing/TestAST.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
15#include "llvm/ADT/ScopeExit.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/VirtualFileSystem.h"
18
19#include "gtest/gtest.h"
20#include
21
23namespace {
24
25
26class StoreDiagnostics : public DiagnosticConsumer {
27 std::vector &Out;
28 bool ReportErrors;
29 LangOptions LangOpts;
30
31public:
32 StoreDiagnostics(std::vector &Out, bool ReportErrors)
33 : Out(Out), ReportErrors(ReportErrors) {}
34
35 void BeginSourceFile(const LangOptions &LangOpts,
36 const Preprocessor *) override {
37 this->LangOpts = LangOpts;
38 }
39
41 const Diagnostic &Info) override {
42 Out.emplace_back(DiagLevel, Info);
44 std::string Text;
45 llvm::raw_string_ostream OS(Text);
46 TextDiagnostic Renderer(OS, LangOpts,
47 &Info.getDiags()->getDiagnosticOptions());
48 Renderer.emitStoredDiagnostic(Out.back());
49 ADD_FAILURE() << Text;
50 }
51 }
52};
53
54
55
56void createMissingComponents(CompilerInstance &Clang) {
57 if (!Clang.hasDiagnostics())
58 Clang.createDiagnostics(*llvm::vfs::getRealFileSystem());
59 if (!Clang.hasFileManager())
60 Clang.createFileManager();
61 if (!Clang.hasSourceManager())
62 Clang.createSourceManager(Clang.getFileManager());
63 if (!Clang.hasTarget())
64 Clang.createTarget();
65 if (!Clang.hasPreprocessor())
67 if (!Clang.hasASTConsumer())
68 Clang.setASTConsumer(std::make_unique());
69 if (!Clang.hasASTContext())
70 Clang.createASTContext();
71 if (!Clang.hasSema())
72 Clang.createSema(TU_Complete, nullptr);
73}
74
75}
76
78 Clang = std::make_unique(
79 std::make_shared());
80
81
82 auto RecoverFromEarlyExit =
83 llvm::make_scope_exit([&] { createMissingComponents(*Clang); });
84
85 std::string Filename = In.FileName;
88
89
90 auto VFS = llvm::makeIntrusiveRefCntllvm::vfs::InMemoryFileSystem();
91 if (auto Err = VFS->setCurrentWorkingDirectory(In.WorkingDir))
92 ADD_FAILURE() << "Failed to setWD: " << Err.message();
93 VFS->addFile(Filename, 0,
94 llvm::MemoryBuffer::getMemBufferCopy(In.Code, Filename));
95 for (const auto &Extra : In.ExtraFiles)
96 VFS->addFile(
97 Extra.getKey(), 0,
98 llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(), Extra.getKey()));
99
100
101 bool ErrorOK = In.ErrorOK || llvm::StringRef(In.Code).contains("error-ok");
102 Clang->createDiagnostics(*VFS, new StoreDiagnostics(Diagnostics, !ErrorOK));
103
104
105 std::vector<const char *> Argv;
107 for (const auto &S : LangArgs)
108 Argv.push_back(S.c_str());
109 for (const auto &S : In.ExtraArgs)
110 Argv.push_back(S.c_str());
111 Argv.push_back(Filename.c_str());
112 Clang->setInvocation(std::make_unique());
114 Clang->getDiagnostics(), "clang")) {
115 ADD_FAILURE() << "Failed to create invocation";
116 return;
117 }
118 assert(!Clang->getInvocation().getFrontendOpts().DisableFree);
119
120 Clang->createFileManager(VFS);
121
122
123
124 EXPECT_TRUE(Clang->createTarget());
125 Action =
126 In.MakeAction ? In.MakeAction() : std::make_unique();
127 const FrontendInputFile &Main = Clang->getFrontendOpts().Inputs.front();
128 if (!Action->BeginSourceFile(*Clang, Main)) {
129 ADD_FAILURE() << "Failed to BeginSourceFile()";
130 Action.reset();
131 return;
132 }
133 if (auto Err = Action->Execute())
134 ADD_FAILURE() << "Failed to Execute(): " << llvm::toString(std::move(Err));
135
136
137
138 Clang->getPreprocessor().EndSourceFile();
139
140 Clang->getDiagnosticClient().EndSourceFile();
142 true);
143}
144
145void TestAST::clear() {
146 if (Action) {
147
148
149 auto PP = Clang->getPreprocessorPtr();
150 Clang->setPreprocessor(nullptr);
151 Action->EndSourceFile();
152
153 }
154 Action.reset();
155 Clang.reset();
156 Diagnostics.clear();
157}
158
160 clear();
161 Action = std::move(M.Action);
162 Clang = std::move(M.Clang);
163 Diagnostics = std::move(M.Diagnostics);
164 return *this;
165}
166
168
170
171}
Defines the Diagnostic-related interfaces.
Defines the clang::LangOptions interface.
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Level
The level of the diagnostic, after it has been through mapping.
An input file for the front end.
The result of parsing a file specified by TestInputs.
TestAST(const TestInputs &)
Constructing a TestAST parses the virtual file.
TestAST & operator=(TestAST &&)
The JSON file list parser is used to communicate input to InstallAPI.
std::vector< std::string > getCC1ArgsForTesting(TestLanguage Lang)
StringRef getFilenameForTesting(TestLanguage Lang)
@ TU_Complete
The translation unit is a complete translation unit.
Specifies a virtual source file to be parsed as part of a test.