clang  6.0.0svn
FrontendActions.cpp
Go to the documentation of this file.
1 //===--- FrontendActions.cpp ----------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "clang/AST/ASTConsumer.h"
12 #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 llvm::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  FixAction->Execute();
134 
135  err = Rewriter.WriteFixedFiles(&RewrittenFiles);
136 
137  FixAction->EndSourceFile();
138  CI.setSourceManager(nullptr);
139  CI.setFileManager(nullptr);
140  } else {
141  err = true;
142  }
143  }
144  if (err)
145  return false;
146  CI.getDiagnosticClient().clear();
147  CI.getDiagnostics().Reset();
148 
150  PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
151  RewrittenFiles.begin(), RewrittenFiles.end());
152  PPOpts.RemappedFilesKeepOriginalName = false;
153 
154  return true;
155 }
156 
157 #if CLANG_ENABLE_OBJC_REWRITER
158 
159 std::unique_ptr<ASTConsumer>
161  if (std::unique_ptr<raw_ostream> OS =
162  CI.createDefaultOutputFile(false, InFile, "cpp")) {
165  InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
166  CI.getDiagnosticOpts().NoRewriteMacros,
167  (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
168  return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
169  CI.getLangOpts(),
170  CI.getDiagnosticOpts().NoRewriteMacros);
171  }
172  return nullptr;
173 }
174 
175 #endif
176 
177 //===----------------------------------------------------------------------===//
178 // Preprocessor Actions
179 //===----------------------------------------------------------------------===//
180 
183  std::unique_ptr<raw_ostream> OS =
185  if (!OS) return;
186 
187  RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
188 }
189 
192  std::unique_ptr<raw_ostream> OS =
194  if (!OS) return;
195 
196  DoRewriteTest(CI.getPreprocessor(), OS.get());
197 }
198 
200  CompilerInstance &CI;
201  std::weak_ptr<raw_ostream> Out;
202 
204 
205 public:
206  RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
207  : CI(CI), Out(Out) {}
208 
209  void visitModuleFile(StringRef Filename,
210  serialization::ModuleKind Kind) override {
211  auto *File = CI.getFileManager().getFile(Filename);
212  assert(File && "missing file for loaded module?");
213 
214  // Only rewrite each module file once.
215  if (!Rewritten.insert(File).second)
216  return;
217 
219  CI.getModuleManager()->getModuleManager().lookup(File);
220  assert(File && "missing module file for loaded module?");
221 
222  // Not interested in PCH / preambles.
223  if (!MF->isModule())
224  return;
225 
226  auto OS = Out.lock();
227  assert(OS && "loaded module file after finishing rewrite action?");
228 
229  (*OS) << "#pragma clang module build ";
230  if (isValidIdentifier(MF->ModuleName))
231  (*OS) << MF->ModuleName;
232  else {
233  (*OS) << '"';
234  OS->write_escaped(MF->ModuleName);
235  (*OS) << '"';
236  }
237  (*OS) << '\n';
238 
239  // Rewrite the contents of the module in a separate compiler instance.
241  &CI.getPreprocessor().getPCMCache());
242  Instance.setInvocation(
243  std::make_shared<CompilerInvocation>(CI.getInvocation()));
244  Instance.createDiagnostics(
246  /*ShouldOwnClient=*/true);
247  Instance.getFrontendOpts().DisableFree = false;
248  Instance.getFrontendOpts().Inputs.clear();
249  Instance.getFrontendOpts().Inputs.emplace_back(
251  Instance.getFrontendOpts().ModuleFiles.clear();
252  Instance.getFrontendOpts().ModuleMapFiles.clear();
253  // Don't recursively rewrite imports. We handle them all at the top level.
254  Instance.getPreprocessorOutputOpts().RewriteImports = false;
255 
256  llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
257  RewriteIncludesAction Action;
258  Action.OutputStream = OS;
259  Instance.ExecuteAction(Action);
260  });
261 
262  (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
263  }
264 };
265 
267  if (!OutputStream) {
268  OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
269  if (!OutputStream)
270  return false;
271  }
272 
273  auto &OS = *OutputStream;
274 
275  // If we're preprocessing a module map, start by dumping the contents of the
276  // module itself before switching to the input buffer.
277  auto &Input = getCurrentInput();
278  if (Input.getKind().getFormat() == InputKind::ModuleMap) {
279  if (Input.isFile()) {
280  OS << "# 1 \"";
281  OS.write_escaped(Input.getFile());
282  OS << "\"\n";
283  }
284  getCurrentModule()->print(OS);
285  OS << "#pragma clang module contents\n";
286  }
287 
288  // If we're rewriting imports, set up a listener to track when we import
289  // module files.
291  CI.createModuleManager();
292  CI.getModuleManager()->addListener(
293  llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
294  }
295 
296  return true;
297 }
298 
301 
302  // If we're rewriting imports, emit the module build output first rather
303  // than switching back and forth (potentially in the middle of a line).
305  std::string Buffer;
306  llvm::raw_string_ostream OS(Buffer);
307 
310 
311  (*OutputStream) << OS.str();
312  } else {
313  RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
315  }
316 
317  OutputStream.reset();
318 }
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...
MemoryBufferCache & getPCMCache() const
Definition: Preprocessor.h:816
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
std::string ModuleName
The name of the module.
Definition: Module.h:118
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.
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:50
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:80
FrontendOptions & getFrontendOpts()
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:113
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:47
StringRef Filename
Definition: Format.cpp:1345
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:360
Defines the clang::Preprocessor interface.
Information about a module that has been loaded by the ASTReader.
Definition: Module.h:100
LLVM_READONLY bool isValidIdentifier(StringRef S)
Return true if this is a valid ASCII identifier.
Definition: CharInfo.h:185
clang::ObjCRuntime ObjCRuntime
Definition: LangOptions.h:117
unsigned FixOnlyWarnings
Apply fixes only for warnings.
void EndSourceFileAction() override
Callback at the end of processing a single input.
Kind
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:458
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:1465
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:129
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS)
DoRewriteTest - A simple test for the TokenRewriter class.
Definition: RewriteTest.cpp:19
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:31
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.
const StringRef getCurrentFile() const