clang  20.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 
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/Basic/CharInfo.h"
13 #include "clang/Config/config.h"
17 #include "clang/Frontend/Utils.h"
18 #include "clang/Lex/Preprocessor.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 
34 using namespace clang;
35 
36 //===----------------------------------------------------------------------===//
37 // AST Consumer Actions
38 //===----------------------------------------------------------------------===//
39 
40 std::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 
51 std::unique_ptr<ASTConsumer>
53  return std::make_unique<ASTConsumer>();
54 }
55 
56 namespace {
57 class FixItRewriteInPlace : public FixItOptions {
58 public:
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 
66 class FixItActionSuffixInserter : public FixItOptions {
67  std::string NewSuffix;
68 
69 public:
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);
81  }
82 };
83 
84 class FixItRewriteToTemp : public FixItOptions {
85 public:
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);
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;
150  CI.getDiagnosticClient().clear();
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 
163 std::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 
192  RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
193 }
194 
197  std::unique_ptr<raw_ostream> OS =
198  CI.createDefaultOutputFile(/*Binary=*/false, getCurrentFileOrBufferName());
199  if (!OS) return;
200 
201  DoRewriteTest(CI.getPreprocessor(), OS.get());
202 }
203 
205  CompilerInstance &CI;
206  std::weak_ptr<raw_ostream> Out;
207 
208  llvm::DenseSet<const FileEntry*> Rewritten;
209 
210 public:
211  RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
212  : CI(CI), Out(Out) {}
213 
214  void visitModuleFile(StringRef Filename,
215  serialization::ModuleKind Kind) override {
216  auto File = CI.getFileManager().getFile(Filename);
217  assert(File && "missing file for loaded module?");
218 
219  // Only rewrite each module file once.
220  if (!Rewritten.insert(*File).second)
221  return;
222 
224  CI.getASTReader()->getModuleManager().lookup(*File);
225  assert(MF && "missing module file for loaded module?");
226 
227  // Not interested in PCH / preambles.
228  if (!MF->isModule())
229  return;
230 
231  auto OS = Out.lock();
232  assert(OS && "loaded module file after finishing rewrite action?");
233 
234  (*OS) << "#pragma clang module build ";
236  (*OS) << MF->ModuleName;
237  else {
238  (*OS) << '"';
239  OS->write_escaped(MF->ModuleName);
240  (*OS) << '"';
241  }
242  (*OS) << '\n';
243 
244  // Rewrite the contents of the module in a separate compiler instance.
246  &CI.getModuleCache());
247  Instance.setInvocation(
248  std::make_shared<CompilerInvocation>(CI.getInvocation()));
249  Instance.createDiagnostics(
251  /*ShouldOwnClient=*/true);
252  Instance.getFrontendOpts().DisableFree = false;
253  Instance.getFrontendOpts().Inputs.clear();
254  Instance.getFrontendOpts().Inputs.emplace_back(
256  Instance.getFrontendOpts().ModuleFiles.clear();
257  Instance.getFrontendOpts().ModuleMapFiles.clear();
258  // Don't recursively rewrite imports. We handle them all at the top level.
259  Instance.getPreprocessorOutputOpts().RewriteImports = false;
260 
261  llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
262  RewriteIncludesAction Action;
263  Action.OutputStream = OS;
264  Instance.ExecuteAction(Action);
265  });
266 
267  (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
268  }
269 };
270 
272  if (!OutputStream) {
273  OutputStream =
275  if (!OutputStream)
276  return false;
277  }
278 
279  auto &OS = *OutputStream;
280 
281  // If we're preprocessing a module map, start by dumping the contents of the
282  // module itself before switching to the input buffer.
283  auto &Input = getCurrentInput();
284  if (Input.getKind().getFormat() == InputKind::ModuleMap) {
285  if (Input.isFile()) {
286  OS << "# 1 \"";
287  OS.write_escaped(Input.getFile());
288  OS << "\"\n";
289  }
290  getCurrentModule()->print(OS);
291  OS << "#pragma clang module contents\n";
292  }
293 
294  // If we're rewriting imports, set up a listener to track when we import
295  // module files.
297  CI.createASTReader();
298  CI.getASTReader()->addListener(
299  std::make_unique<RewriteImportsListener>(CI, OutputStream));
300  }
301 
302  return true;
303 }
304 
307 
308  // If we're rewriting imports, emit the module build output first rather
309  // than switching back and forth (potentially in the middle of a line).
311  std::string Buffer;
312  llvm::raw_string_ostream OS(Buffer);
313 
316 
317  (*OutputStream) << OS.str();
318  } else {
319  RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
321  }
322 
323  OutputStream.reset();
324 }
IndirectLocalPath & Path
enum clang::sema::@1659::IndirectLocalPathEntry::EntryKind Kind
StringRef Filename
Definition: Format.cpp:3001
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:114
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.
CodeGenOptions & getCodeGenOpts()
void setSourceManager(SourceManager *Value)
setSourceManager - Replace the current source manager.
CompilerInvocation & getInvocation()
Preprocessor & getPreprocessor() const
Return the current preprocessor.
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...
FrontendOptions & getFrontendOpts()
PreprocessorOptions & getPreprocessorOpts()
InMemoryModuleCache & getModuleCache() const
IntrusiveRefCntPtr< ASTReader > getASTReader() const
SourceManager & getSourceManager() const
Return the current source manager.
FileManager & getFileManager() const
Return the current file manager to the caller.
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticConsumer & getDiagnosticClient() const
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
LangOptions & getLangOpts()
DiagnosticOptions & getDiagnosticOpts()
PreprocessorOutputOptions & getPreprocessorOutputOpts()
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:118
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:1818
const FrontendInputFile & getCurrentInput() const
Module * getCurrentModule() const
StringRef getCurrentFileOrBufferName() const
CompilerInstance & getCompilerInstance() 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:515
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:124
bool isModule() const
Is this a module file for a module (rather than a PCH or similar).
Definition: ModuleFile.h:509
std::string ModuleName
The name of the module.
Definition: ModuleFile.h:142
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:42
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.
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: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:51
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.