clang  9.0.0
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"
12 #include "clang/Config/config.h"
16 #include "clang/Frontend/Utils.h"
17 #include "clang/Lex/Preprocessor.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 
33 using namespace clang;
34 
35 //===----------------------------------------------------------------------===//
36 // AST Consumer Actions
37 //===----------------------------------------------------------------------===//
38 
39 std::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 
50 std::unique_ptr<ASTConsumer>
52  return llvm::make_unique<ASTConsumer>();
53 }
54 
55 namespace {
56 class FixItRewriteInPlace : public FixItOptions {
57 public:
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 
65 class FixItActionSuffixInserter : public FixItOptions {
66  std::string NewSuffix;
67 
68 public:
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 Path.str();
80  }
81 };
82 
83 class FixItRewriteToTemp : public FixItOptions {
84 public:
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 Path.str();
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()));
106  return true;
107 }
108 
110  // Otherwise rewrite all files.
111  Rewriter->WriteFixedFiles();
112 }
113 
115 
116  std::vector<std::pair<std::string, std::string> > RewrittenFiles;
117  bool err = false;
118  {
119  const FrontendOptions &FEOpts = CI.getFrontendOpts();
120  std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
121  if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
122  std::unique_ptr<FixItOptions> FixItOpts;
123  if (FEOpts.FixToTemporaries)
124  FixItOpts.reset(new FixItRewriteToTemp());
125  else
126  FixItOpts.reset(new FixItRewriteInPlace());
127  FixItOpts->Silent = true;
128  FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
129  FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
131  CI.getLangOpts(), FixItOpts.get());
132  if (llvm::Error Err = FixAction->Execute()) {
133  // FIXME this drops the error on the floor.
134  consumeError(std::move(Err));
135  return false;
136  }
137 
138  err = Rewriter.WriteFixedFiles(&RewrittenFiles);
139 
140  FixAction->EndSourceFile();
141  CI.setSourceManager(nullptr);
142  CI.setFileManager(nullptr);
143  } else {
144  err = true;
145  }
146  }
147  if (err)
148  return false;
149  CI.getDiagnosticClient().clear();
150  CI.getDiagnostics().Reset();
151 
153  PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
154  RewrittenFiles.begin(), RewrittenFiles.end());
155  PPOpts.RemappedFilesKeepOriginalName = false;
156 
157  return true;
158 }
159 
160 #if CLANG_ENABLE_OBJC_REWRITER
161 
162 std::unique_ptr<ASTConsumer>
164  if (std::unique_ptr<raw_ostream> OS =
165  CI.createDefaultOutputFile(false, InFile, "cpp")) {
168  InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
169  CI.getDiagnosticOpts().NoRewriteMacros,
170  (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
171  return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
172  CI.getLangOpts(),
173  CI.getDiagnosticOpts().NoRewriteMacros);
174  }
175  return nullptr;
176 }
177 
178 #endif
179 
180 //===----------------------------------------------------------------------===//
181 // Preprocessor Actions
182 //===----------------------------------------------------------------------===//
183 
186  std::unique_ptr<raw_ostream> OS =
188  if (!OS) return;
189 
190  RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
191 }
192 
195  std::unique_ptr<raw_ostream> OS =
197  if (!OS) return;
198 
199  DoRewriteTest(CI.getPreprocessor(), OS.get());
200 }
201 
203  CompilerInstance &CI;
204  std::weak_ptr<raw_ostream> Out;
205 
207 
208 public:
209  RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
210  : CI(CI), Out(Out) {}
211 
212  void visitModuleFile(StringRef Filename,
213  serialization::ModuleKind Kind) override {
214  auto *File = CI.getFileManager().getFile(Filename);
215  assert(File && "missing file for loaded module?");
216 
217  // Only rewrite each module file once.
218  if (!Rewritten.insert(File).second)
219  return;
220 
222  CI.getModuleManager()->getModuleManager().lookup(File);
223  assert(File && "missing module file for loaded module?");
224 
225  // Not interested in PCH / preambles.
226  if (!MF->isModule())
227  return;
228 
229  auto OS = Out.lock();
230  assert(OS && "loaded module file after finishing rewrite action?");
231 
232  (*OS) << "#pragma clang module build ";
233  if (isValidIdentifier(MF->ModuleName))
234  (*OS) << MF->ModuleName;
235  else {
236  (*OS) << '"';
237  OS->write_escaped(MF->ModuleName);
238  (*OS) << '"';
239  }
240  (*OS) << '\n';
241 
242  // Rewrite the contents of the module in a separate compiler instance.
244  &CI.getModuleCache());
245  Instance.setInvocation(
246  std::make_shared<CompilerInvocation>(CI.getInvocation()));
247  Instance.createDiagnostics(
249  /*ShouldOwnClient=*/true);
250  Instance.getFrontendOpts().DisableFree = false;
251  Instance.getFrontendOpts().Inputs.clear();
252  Instance.getFrontendOpts().Inputs.emplace_back(
254  Instance.getFrontendOpts().ModuleFiles.clear();
255  Instance.getFrontendOpts().ModuleMapFiles.clear();
256  // Don't recursively rewrite imports. We handle them all at the top level.
257  Instance.getPreprocessorOutputOpts().RewriteImports = false;
258 
259  llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
260  RewriteIncludesAction Action;
261  Action.OutputStream = OS;
262  Instance.ExecuteAction(Action);
263  });
264 
265  (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
266  }
267 };
268 
270  if (!OutputStream) {
271  OutputStream =
273  if (!OutputStream)
274  return false;
275  }
276 
277  auto &OS = *OutputStream;
278 
279  // If we're preprocessing a module map, start by dumping the contents of the
280  // module itself before switching to the input buffer.
281  auto &Input = getCurrentInput();
282  if (Input.getKind().getFormat() == InputKind::ModuleMap) {
283  if (Input.isFile()) {
284  OS << "# 1 \"";
285  OS.write_escaped(Input.getFile());
286  OS << "\"\n";
287  }
288  getCurrentModule()->print(OS);
289  OS << "#pragma clang module contents\n";
290  }
291 
292  // If we're rewriting imports, set up a listener to track when we import
293  // module files.
295  CI.createModuleManager();
296  CI.getModuleManager()->addListener(
297  llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
298  }
299 
300  return true;
301 }
302 
305 
306  // If we're rewriting imports, emit the module build output first rather
307  // than switching back and forth (potentially in the middle of a line).
309  std::string Buffer;
310  llvm::raw_string_ostream OS(Buffer);
311 
314 
315  (*OutputStream) << OS.str();
316  } else {
317  RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
319  }
320 
321  OutputStream.reset();
322 }
LangOptions & getLangOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool RemappedFilesKeepOriginalName
True if the SourceManager should report the original file name for contents of files that were remapp...
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
std::string ModuleName
The name of the module.
Definition: Module.h:125
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
InMemoryModuleCache & getModuleCache() const
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void setSourceManager(SourceManager *Value)
setSourceManager - Replace the current source manager.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
std::string FixItSuffix
If given, the new suffix for fix-it rewritten files.
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 visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) override
This is called for each AST file loaded.
RewriteImportsListener(CompilerInstance &CI, std::shared_ptr< raw_ostream > Out)
std::unique_ptr< ASTConsumer > CreateModernObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning, bool LineInfo)
Module * getCurrentModule() const
CodeGenOptions & getCodeGenOpts()
CompilerInstance & getCompilerInstance() const
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
bool isNonFragile() const
Does this runtime follow the set of implied behaviors for a "non-fragile" ABI?
Definition: ObjCRuntime.h:81
FrontendOptions & getFrontendOpts()
StringRef getCurrentFileOrBufferName() const
PreprocessorOutputOptions & getPreprocessorOutputOpts()
std::unique_ptr< ASTConsumer > CreateObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning)
unsigned FixWhatYouCan
Apply fixes even if there are unfixable errors.
void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS)
RewriteMacrosInInput - Implement -rewrite-macros mode.
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:121
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
ModuleKind
Specifies the kind of module that has been loaded.
Definition: Module.h:42
StringRef Filename
Definition: Format.cpp:1711
IntrusiveRefCntPtr< ASTReader > getModuleManager() const
void print(raw_ostream &OS, unsigned Indent=0) const
Print the module map for this module to the given stream.
Definition: Module.cpp:419
Defines the clang::Preprocessor interface.
Information about a module that has been loaded by the ASTReader.
Definition: Module.h:107
clang::ObjCRuntime ObjCRuntime
Definition: LangOptions.h:207
unsigned FixOnlyWarnings
Apply fixes only for warnings.
void EndSourceFileAction() override
Callback at the end of processing a single input.
Kind
LLVM_READONLY bool isValidIdentifier(StringRef S, bool AllowDollar=false)
Return true if this is a valid ASCII identifier.
Definition: CharInfo.h:184
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
std::vector< FrontendInputFile > Inputs
The input files and their types.
bool isModule() const
Is this a module file for a module (rather than a PCH or similar).
Definition: Module.h:476
The kind of a file that we&#39;ve been handed as an input.
Diagnostic consumer that forwards diagnostics along to an existing, already-initialized diagnostic co...
Definition: Diagnostic.h:1563
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
unsigned RewriteImports
Include contents of transitively-imported modules.
unsigned FixToTemporaries
Apply fixes to temporary files.
void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
RewriteIncludesInInput - Implement -frewrite-includes mode.
Dataflow Directional Tag Classes.
FileManager & getFileManager() const
Return the current file manager to the caller.
const FrontendInputFile & getCurrentInput() const
SourceManager & getSourceManager() const
Return the current source manager.
FrontendOptions - Options for controlling the behavior of the frontend.
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:126
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS)
DoRewriteTest - A simple test for the TokenRewriter class.
Definition: RewriteTest.cpp:18
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="")
Create the default output file (from the invocation&#39;s options) and add it to the list of tracked outp...
void setInvocation(std::shared_ptr< CompilerInvocation > Value)
setInvocation - Replace the current invocation.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
DiagnosticConsumer & getDiagnosticClient() const
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...
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.