clang  10.0.0svn
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;
77  SmallString<128> Path(Filename);
78  llvm::sys::path::replace_extension(Path,
79  NewSuffix + llvm::sys::path::extension(Path));
80  return Path.str();
81  }
82 };
83 
84 class FixItRewriteToTemp : public FixItOptions {
85 public:
86  std::string RewriteFilename(const std::string &Filename, int &fd) override {
87  SmallString<128> Path;
88  llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
89  llvm::sys::path::extension(Filename).drop_front(), fd,
90  Path);
91  return 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;
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")) {
169  InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
170  CI.getDiagnosticOpts().NoRewriteMacros,
171  (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
172  return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
173  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 
191  RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
192 }
193 
196  std::unique_ptr<raw_ostream> OS =
198  if (!OS) return;
199 
200  DoRewriteTest(CI.getPreprocessor(), OS.get());
201 }
202 
204  CompilerInstance &CI;
205  std::weak_ptr<raw_ostream> Out;
206 
208 
209 public:
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.getModuleManager()->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 ";
234  if (isValidIdentifier(MF->ModuleName))
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([&]() {
261  RewriteIncludesAction Action;
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.createModuleManager();
297  CI.getModuleManager()->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 }
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
ModuleKind
Specifies the kind of module that has been loaded.
Definition: Module.h:42
StringRef Filename
Definition: Format.cpp:1807
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:223
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:1556
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.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
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.