clang 23.0.0git
FrontendActions.cpp
Go to the documentation of this file.
1//===--- FrontendActions.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
13#include "clang/Config/config.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/Support/CrashRecoveryContext.h"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/raw_ostream.h"
30#include <memory>
31#include <utility>
32
33using namespace clang;
34
35//===----------------------------------------------------------------------===//
36// AST Consumer Actions
37//===----------------------------------------------------------------------===//
38
39std::unique_ptr<ASTConsumer>
41 if (std::unique_ptr<raw_ostream> OS =
42 CI.createDefaultOutputFile(false, InFile))
43 return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
44 return nullptr;
45}
46
49
50std::unique_ptr<ASTConsumer>
52 return std::make_unique<ASTConsumer>();
53}
54
55namespace {
56class FixItRewriteInPlace : public FixItOptions {
57public:
58 FixItRewriteInPlace() { InPlace = true; }
59
60 std::string RewriteFilename(const std::string &Filename, int &fd) override {
61 llvm_unreachable("don't call RewriteFilename for inplace rewrites");
62 }
63};
64
65class FixItActionSuffixInserter : public FixItOptions {
66 std::string NewSuffix;
67
68public:
69 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
70 : NewSuffix(std::move(NewSuffix)) {
71 this->FixWhatYouCan = FixWhatYouCan;
72 }
73
74 std::string RewriteFilename(const std::string &Filename, int &fd) override {
75 fd = -1;
76 SmallString<128> Path(Filename);
77 llvm::sys::path::replace_extension(Path,
78 NewSuffix + llvm::sys::path::extension(Path));
79 return std::string(Path);
80 }
81};
82
83class FixItRewriteToTemp : public FixItOptions {
84public:
85 std::string RewriteFilename(const std::string &Filename, int &fd) override {
86 SmallString<128> Path;
87 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
88 llvm::sys::path::extension(Filename).drop_front(), fd,
89 Path);
90 return std::string(Path);
91 }
92};
93} // end anonymous namespace
94
97 if (!FEOpts.FixItSuffix.empty()) {
98 FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
99 FEOpts.FixWhatYouCan));
100 } else {
101 FixItOpts.reset(new FixItRewriteInPlace);
102 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
103 }
105 CI.getLangOpts(), FixItOpts.get()));
107}
108
110 // Otherwise rewrite all files.
111 Rewriter->WriteFixedFiles();
113}
114
116
117 std::vector<std::pair<std::string, std::string> > RewrittenFiles;
118 bool err = false;
119 {
120 const FrontendOptions &FEOpts = CI.getFrontendOpts();
121 std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
122 if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
123 std::unique_ptr<FixItOptions> FixItOpts;
124 if (FEOpts.FixToTemporaries)
125 FixItOpts.reset(new FixItRewriteToTemp());
126 else
127 FixItOpts.reset(new FixItRewriteInPlace());
128 FixItOpts->Silent = true;
129 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
130 FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
132 CI.getLangOpts(), FixItOpts.get());
133 if (llvm::Error Err = FixAction->Execute()) {
134 // FIXME this drops the error on the floor.
135 consumeError(std::move(Err));
136 return false;
137 }
138
139 err = Rewriter.WriteFixedFiles(&RewrittenFiles);
140
141 FixAction->EndSourceFile();
142 CI.setSourceManager(nullptr);
143 CI.setFileManager(nullptr);
144 } else {
145 err = true;
146 }
147 }
148 if (err)
149 return false;
151 CI.getDiagnostics().Reset();
152
154 PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
155 RewrittenFiles.begin(), RewrittenFiles.end());
156 PPOpts.RemappedFilesKeepOriginalName = false;
157
158 return true;
159}
160
161#if CLANG_ENABLE_OBJC_REWRITER
162
163std::unique_ptr<ASTConsumer>
165 if (std::unique_ptr<raw_ostream> OS =
166 CI.createDefaultOutputFile(false, InFile, "cpp")) {
168 return CreateModernObjCRewriter(std::string(InFile), std::move(OS),
169 CI.getDiagnostics(), CI.getLangOpts(),
170 CI.getDiagnosticOpts().NoRewriteMacros,
171 (CI.getCodeGenOpts().getDebugInfo() !=
172 llvm::codegenoptions::NoDebugInfo));
173 return CreateObjCRewriter(std::string(InFile), std::move(OS),
174 CI.getDiagnostics(), CI.getLangOpts(),
175 CI.getDiagnosticOpts().NoRewriteMacros);
176 }
177 return nullptr;
178}
179
180#endif
181
182//===----------------------------------------------------------------------===//
183// Preprocessor Actions
184//===----------------------------------------------------------------------===//
185
188 std::unique_ptr<raw_ostream> OS =
190 if (!OS) return;
191
193}
194
197 std::unique_ptr<raw_ostream> OS =
199 if (!OS) return;
200
201 DoRewriteTest(CI.getPreprocessor(), OS.get());
202}
203
206 std::weak_ptr<raw_ostream> Out;
207
208 llvm::DenseSet<const serialization::ModuleFile *> Rewritten;
209
210public:
211 RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
212 : CI(CI), Out(Out) {}
213
215 bool DirectlyImported) override {
217 CI.getASTReader()->getModuleManager().lookupByFileName(Filename);
218 assert(MF && "missing module file for loaded module?");
219
220 // Only rewrite each module file once.
221 if (!Rewritten.insert(MF).second)
222 return;
223
224 // Not interested in PCH / preambles.
225 if (!MF->isModule())
226 return;
227
228 auto OS = Out.lock();
229 assert(OS && "loaded module file after finishing rewrite action?");
230
231 (*OS) << "#pragma clang module build ";
233 (*OS) << MF->ModuleName;
234 else {
235 (*OS) << '"';
236 OS->write_escaped(MF->ModuleName);
237 (*OS) << '"';
238 }
239 (*OS) << '\n';
240
241 // Rewrite the contents of the module in a separate compiler instance.
242 CompilerInstance Instance(
243 std::make_shared<CompilerInvocation>(CI.getInvocation()),
244 CI.getPCHContainerOperations(), CI.getModuleCachePtr());
245 Instance.setVirtualFileSystem(CI.getVirtualFileSystemPtr());
246 Instance.createDiagnostics(
247 new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
248 /*ShouldOwnClient=*/true);
249 Instance.getFrontendOpts().DisableFree = false;
250 Instance.getFrontendOpts().Inputs.clear();
251 Instance.getFrontendOpts().Inputs.emplace_back(
253 Instance.getFrontendOpts().ModuleFiles.clear();
254 Instance.getFrontendOpts().ModuleMapFiles.clear();
255 // Don't recursively rewrite imports. We handle them all at the top level.
256 Instance.getPreprocessorOutputOpts().RewriteImports = false;
257
258 llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
260 Action.OutputStream = OS;
261 Instance.ExecuteAction(Action);
262 });
263
264 (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
265 }
266};
267
269 if (!OutputStream) {
270 OutputStream =
272 if (!OutputStream)
273 return false;
274 }
275
276 auto &OS = *OutputStream;
277
278 // If we're preprocessing a module map, start by dumping the contents of the
279 // module itself before switching to the input buffer.
280 auto &Input = getCurrentInput();
281 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
282 if (Input.isFile()) {
283 OS << "# 1 \"";
284 OS.write_escaped(Input.getFile());
285 OS << "\"\n";
286 }
287 getCurrentModule()->print(OS);
288 OS << "#pragma clang module contents\n";
289 }
290
291 // If we're rewriting imports, set up a listener to track when we import
292 // module files.
294 CI.createASTReader();
295 CI.getASTReader()->addListener(
296 std::make_unique<RewriteImportsListener>(CI, OutputStream));
297 }
298
300}
301
304
305 // If we're rewriting imports, emit the module build output first rather
306 // than switching back and forth (potentially in the middle of a line).
308 std::string Buffer;
309 llvm::raw_string_ostream OS(Buffer);
310
313
314 (*OutputStream) << OS.str();
315 } else {
316 RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
318 }
319
320 OutputStream.reset();
321}
Defines the clang::Preprocessor interface.
RewriteImportsListener(CompilerInstance &CI, std::shared_ptr< raw_ostream > Out)
void visitModuleFile(ModuleFileName Filename, serialization::ModuleKind Kind, bool DirectlyImported) override
This is called for each AST file loaded.
Abstract interface for callback invocations by the ASTReader.
Definition ASTReader.h:117
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticConsumer & getDiagnosticClient() const
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="", bool RemoveFileOnSignal=true, bool CreateMissingDirectories=false, bool ForceUseTemporary=false)
Create the default output file (from the invocation's options) and add it to the list of tracked outp...
PreprocessorOutputOptions & getPreprocessorOutputOpts()
IntrusiveRefCntPtr< ASTReader > getASTReader() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
void setSourceManager(llvm::IntrusiveRefCntPtr< SourceManager > Value)
setSourceManager - Replace the current source manager.
PreprocessorOptions & getPreprocessorOpts()
void setFileManager(IntrusiveRefCntPtr< FileManager > Value)
Replace the current file manager.
DiagnosticOptions & getDiagnosticOpts()
CodeGenOptions & getCodeGenOpts()
SourceManager & getSourceManager() const
Return the current source manager.
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
std::unique_ptr< FixItRewriter > Rewriter
std::unique_ptr< FixItOptions > FixItOpts
void EndSourceFileAction() override
Callback at the end of processing a single input.
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Diagnostic consumer that forwards diagnostics along to an existing, already-initialized diagnostic co...
const FrontendInputFile & getCurrentInput() const
virtual void EndSourceFileAction()
Callback at the end of processing a single input.
CompilerInstance & getCompilerInstance() const
Module * getCurrentModule() const
virtual bool BeginSourceFileAction(CompilerInstance &CI)
Callback at the start of processing a single input.
StringRef getCurrentFileOrBufferName() const
FrontendOptions - Options for controlling the behavior of the frontend.
unsigned FixToTemporaries
Apply fixes to temporary files.
unsigned FixOnlyWarnings
Apply fixes only for warnings.
std::string FixItSuffix
If given, the new suffix for fix-it rewritten files.
unsigned FixWhatYouCan
Apply fixes even if there are unfixable errors.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
The kind of a file that we've been handed as an input.
clang::ObjCRuntime ObjCRuntime
Identifies a module file to be loaded.
Definition Module.h:102
void print(raw_ostream &OS, unsigned Indent=0, bool Dump=false) const
Print the module map for this module to the given stream.
Definition Module.cpp:482
bool isNonFragile() const
Does this runtime follow the set of implied behaviors for a "non-fragile" ABI?
Definition ObjCRuntime.h:82
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
std::vector< std::pair< std::string, std::string > > RemappedFiles
The set of file remappings, which take existing files on the system (the first part of each pair) and...
bool RemappedFilesKeepOriginalName
True if the SourceManager should report the original file name for contents of files that were remapp...
unsigned RewriteImports
Include contents of transitively-imported modules.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
Rewriter - This is the main interface to the rewrite buffers.
Definition Rewriter.h:32
Information about a module that has been loaded by the ASTReader.
Definition ModuleFile.h:158
bool isModule() const
Is this a module file for a module (rather than a PCH or similar).
Definition ModuleFile.h:554
std::string ModuleName
The name of the module.
Definition ModuleFile.h:183
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:44
The JSON file list parser is used to communicate input to InstallAPI.
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS)
DoRewriteTest - A simple test for the TokenRewriter class.
LLVM_READONLY bool isValidAsciiIdentifier(StringRef S, bool AllowDollar=false)
Return true if this is a valid ASCII identifier.
Definition CharInfo.h:244
std::unique_ptr< ASTConsumer > CreateObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning)
std::unique_ptr< ASTConsumer > CreateModernObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning, bool LineInfo)
std::unique_ptr< ASTConsumer > CreateHTMLPrinter(std::unique_ptr< raw_ostream > OS, Preprocessor &PP, bool SyntaxHighlight=true, bool HighlightMacros=true)
CreateHTMLPrinter - Create an AST consumer which rewrites source code to HTML with syntax highlightin...
Definition HTMLPrint.cpp:50
void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
RewriteIncludesInInput - Implement -frewrite-includes mode.
void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS)
RewriteMacrosInInput - Implement -rewrite-macros mode.