clang 17.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"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/Support/CrashRecoveryContext.h"
28#include "llvm/Support/FileSystem.h"
29#include "llvm/Support/Path.h"
30#include "llvm/Support/raw_ostream.h"
31#include <memory>
32#include <utility>
33
34using namespace clang;
35
36//===----------------------------------------------------------------------===//
37// AST Consumer Actions
38//===----------------------------------------------------------------------===//
39
40std::unique_ptr<ASTConsumer>
42 if (std::unique_ptr<raw_ostream> OS =
43 CI.createDefaultOutputFile(false, InFile))
44 return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
45 return nullptr;
46}
47
50
51std::unique_ptr<ASTConsumer>
53 return std::make_unique<ASTConsumer>();
54}
55
56namespace {
57class FixItRewriteInPlace : public FixItOptions {
58public:
59 FixItRewriteInPlace() { InPlace = true; }
60
61 std::string RewriteFilename(const std::string &Filename, int &fd) override {
62 llvm_unreachable("don't call RewriteFilename for inplace rewrites");
63 }
64};
65
66class FixItActionSuffixInserter : public FixItOptions {
67 std::string NewSuffix;
68
69public:
70 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
71 : NewSuffix(std::move(NewSuffix)) {
72 this->FixWhatYouCan = FixWhatYouCan;
73 }
74
75 std::string RewriteFilename(const std::string &Filename, int &fd) override {
76 fd = -1;
78 llvm::sys::path::replace_extension(Path,
79 NewSuffix + llvm::sys::path::extension(Path));
80 return std::string(Path.str());
81 }
82};
83
84class FixItRewriteToTemp : public FixItOptions {
85public:
86 std::string RewriteFilename(const std::string &Filename, int &fd) override {
88 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
89 llvm::sys::path::extension(Filename).drop_front(), fd,
90 Path);
91 return std::string(Path.str());
92 }
93};
94} // end anonymous namespace
95
98 if (!FEOpts.FixItSuffix.empty()) {
99 FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
100 FEOpts.FixWhatYouCan));
101 } else {
102 FixItOpts.reset(new FixItRewriteInPlace);
103 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
104 }
106 CI.getLangOpts(), FixItOpts.get()));
107 return true;
108}
109
111 // Otherwise rewrite all files.
112 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")) {
169 std::string(InFile), std::move(OS), CI.getDiagnostics(),
170 CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros,
171 (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
172 return CreateObjCRewriter(std::string(InFile), std::move(OS),
173 CI.getDiagnostics(), CI.getLangOpts(),
174 CI.getDiagnosticOpts().NoRewriteMacros);
175 }
176 return nullptr;
177}
178
179#endif
180
181//===----------------------------------------------------------------------===//
182// Preprocessor Actions
183//===----------------------------------------------------------------------===//
184
187 std::unique_ptr<raw_ostream> OS =
189 if (!OS) return;
190
192}
193
196 std::unique_ptr<raw_ostream> OS =
198 if (!OS) return;
199
200 DoRewriteTest(CI.getPreprocessor(), OS.get());
201}
202
205 std::weak_ptr<raw_ostream> Out;
206
208
209public:
210 RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
211 : CI(CI), Out(Out) {}
212
213 void visitModuleFile(StringRef Filename,
214 serialization::ModuleKind Kind) override {
215 auto File = CI.getFileManager().getFile(Filename);
216 assert(File && "missing file for loaded module?");
217
218 // Only rewrite each module file once.
219 if (!Rewritten.insert(*File).second)
220 return;
221
223 CI.getASTReader()->getModuleManager().lookup(*File);
224 assert(MF && "missing module file for loaded module?");
225
226 // Not interested in PCH / preambles.
227 if (!MF->isModule())
228 return;
229
230 auto OS = Out.lock();
231 assert(OS && "loaded module file after finishing rewrite action?");
232
233 (*OS) << "#pragma clang module build ";
235 (*OS) << MF->ModuleName;
236 else {
237 (*OS) << '"';
238 OS->write_escaped(MF->ModuleName);
239 (*OS) << '"';
240 }
241 (*OS) << '\n';
242
243 // Rewrite the contents of the module in a separate compiler instance.
245 &CI.getModuleCache());
246 Instance.setInvocation(
247 std::make_shared<CompilerInvocation>(CI.getInvocation()));
248 Instance.createDiagnostics(
250 /*ShouldOwnClient=*/true);
251 Instance.getFrontendOpts().DisableFree = false;
252 Instance.getFrontendOpts().Inputs.clear();
253 Instance.getFrontendOpts().Inputs.emplace_back(
255 Instance.getFrontendOpts().ModuleFiles.clear();
256 Instance.getFrontendOpts().ModuleMapFiles.clear();
257 // Don't recursively rewrite imports. We handle them all at the top level.
258 Instance.getPreprocessorOutputOpts().RewriteImports = false;
259
260 llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
262 Action.OutputStream = OS;
263 Instance.ExecuteAction(Action);
264 });
265
266 (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
267 }
268};
269
271 if (!OutputStream) {
272 OutputStream =
274 if (!OutputStream)
275 return false;
276 }
277
278 auto &OS = *OutputStream;
279
280 // If we're preprocessing a module map, start by dumping the contents of the
281 // module itself before switching to the input buffer.
282 auto &Input = getCurrentInput();
283 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
284 if (Input.isFile()) {
285 OS << "# 1 \"";
286 OS.write_escaped(Input.getFile());
287 OS << "\"\n";
288 }
289 getCurrentModule()->print(OS);
290 OS << "#pragma clang module contents\n";
291 }
292
293 // If we're rewriting imports, set up a listener to track when we import
294 // module files.
296 CI.createASTReader();
297 CI.getASTReader()->addListener(
298 std::make_unique<RewriteImportsListener>(CI, OutputStream));
299 }
300
301 return true;
302}
303
306
307 // If we're rewriting imports, emit the module build output first rather
308 // than switching back and forth (potentially in the middle of a line).
310 std::string Buffer;
311 llvm::raw_string_ostream OS(Buffer);
312
315
316 (*OutputStream) << OS.str();
317 } else {
318 RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
320 }
321
322 OutputStream.reset();
323}
StringRef Filename
Definition: Format.cpp:2774
Defines the clang::Preprocessor interface.
RewriteImportsListener(CompilerInstance &CI, std::shared_ptr< raw_ostream > Out)
void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) override
This is called for each AST file loaded.
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:113
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
void setSourceManager(SourceManager *Value)
setSourceManager - Replace the current source manager.
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...
FileManager & getFileManager() const
Return the current file manager to the caller.
PreprocessorOutputOptions & getPreprocessorOutputOpts()
IntrusiveRefCntPtr< ASTReader > getASTReader() const
InMemoryModuleCache & getModuleCache() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
LangOptions & getLangOpts()
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.
Definition: Diagnostic.cpp:134
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
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...
Definition: Diagnostic.h:1807
const FrontendInputFile & getCurrentInput() const
CompilerInstance & getCompilerInstance() const
Module * getCurrentModule() const
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
Definition: LangOptions.h:417
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:454
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:122
bool isModule() const
Is this a module file for a module (rather than a PCH or similar).
Definition: ModuleFile.h:515
std::string ModuleName
The name of the module.
Definition: ModuleFile.h:140
@ NoDebugInfo
Don't generate debug info.
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:42
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS)
DoRewriteTest - A simple test for the TokenRewriter class.
Definition: RewriteTest.cpp:18
LLVM_READONLY bool isValidAsciiIdentifier(StringRef S, bool AllowDollar=false)
Return true if this is a valid ASCII identifier.
Definition: CharInfo.h:228
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:49
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.
Definition: Format.h:4657