clang  14.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.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 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;
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  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 
191  RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
192 }
193 
196  std::unique_ptr<raw_ostream> OS =
197  CI.createDefaultOutputFile(/*Binary=*/false, getCurrentFileOrBufferName());
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.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([&]() {
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.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 }
clang::DiagnosticsEngine::Reset
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:133
clang::CompilerInstance::getPreprocessorOutputOpts
PreprocessorOutputOptions & getPreprocessorOutputOpts()
Definition: CompilerInstance.h:312
clang::DeclaratorContext::File
@ File
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::PreprocessorOptions
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
Definition: PreprocessorOptions.h:64
clang::ForwardingDiagnosticConsumer
Diagnostic consumer that forwards diagnostics along to an existing, already-initialized diagnostic co...
Definition: Diagnostic.h:1774
clang::RewriteTestAction::ExecuteAction
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
Definition: FrontendActions.cpp:194
clang::FixItAction::FixItAction
FixItAction()
Definition: FrontendActions.cpp:48
clang::CompilerInstance::getLangOpts
LangOptions & getLangOpts()
Definition: CompilerInstance.h:298
Filename
StringRef Filename
Definition: Format.cpp:2266
clang::FrontendAction::getCurrentModule
Module * getCurrentModule() const
Definition: FrontendAction.cpp:144
clang::RewriteIncludesAction
Definition: FrontendActions.h:75
clang::codegenoptions::NoDebugInfo
@ NoDebugInfo
Don't generate debug info.
Definition: DebugInfoOptions.h:22
clang::InputKind
The kind of a file that we've been handed as an input.
Definition: FrontendOptions.h:145
clang::CompilerInstance::getCodeGenOpts
CodeGenOptions & getCodeGenOpts()
Definition: CompilerInstance.h:253
clang::FrontendOptions::Inputs
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
Definition: FrontendOptions.h:386
Preprocessor.h
clang::CompilerInstance::getFileManager
FileManager & getFileManager() const
Return the current file manager to the caller.
Definition: CompilerInstance.h:401
clang::isValidAsciiIdentifier
LLVM_READONLY bool isValidAsciiIdentifier(StringRef S, bool AllowDollar=false)
Return true if this is a valid ASCII identifier.
Definition: CharInfo.h:189
Rewriters.h
clang::LangOptions::ObjCRuntime
clang::ObjCRuntime ObjCRuntime
Definition: LangOptions.h:323
clang::FrontendAction::getCurrentFileOrBufferName
StringRef getCurrentFileOrBufferName() const
Definition: FrontendAction.h:144
clang::CompilerInstance::createASTReader
void createASTReader()
Definition: CompilerInstance.cpp:1557
clang::SyntaxOnlyAction
Definition: FrontendActions.h:173
clang::RewriteIncludesAction::RewriteImportsListener::visitModuleFile
void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) override
This is called for each AST file loaded.
Definition: FrontendActions.cpp:213
clang::RewriteIncludesAction::RewriteImportsListener::RewriteImportsListener
RewriteImportsListener(CompilerInstance &CI, std::shared_ptr< raw_ostream > Out)
Definition: FrontendActions.cpp:210
clang::FrontendOptions
FrontendOptions - Options for controlling the behavior of the frontend.
Definition: FrontendOptions.h:228
Utils.h
clang::InputKind::Precompiled
@ Precompiled
Definition: FrontendOptions.h:156
clang::RewriteIncludesInInput
void RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
RewriteIncludesInInput - Implement -frewrite-includes mode.
Definition: InclusionRewriter.cpp:536
clang::PreprocessorOutputOptions::RewriteImports
unsigned RewriteImports
Include contents of transitively-imported modules.
Definition: PreprocessorOutputOptions.h:26
clang::FrontendAction::getCompilerInstance
CompilerInstance & getCompilerInstance() const
Definition: FrontendAction.h:119
llvm::SmallString< 128 >
clang::RewriteIncludesAction::BeginSourceFileAction
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
Definition: FrontendActions.cpp:270
clang::FrontendOptions::FixToTemporaries
unsigned FixToTemporaries
Apply fixes to temporary files.
Definition: FrontendOptions.h:262
FixItRewriter.h
llvm::DenseSet
Definition: Sema.h:78
clang::CompilerInstance::getPreprocessor
Preprocessor & getPreprocessor() const
Return the current preprocessor.
Definition: CompilerInstance.h:441
ASTConsumers.h
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:74
clang::FrontendOptions::FixOnlyWarnings
unsigned FixOnlyWarnings
Apply fixes only for warnings.
Definition: FrontendOptions.h:256
clang::CompilerInstance::getPreprocessorOpts
PreprocessorOptions & getPreprocessorOpts()
Definition: CompilerInstance.h:305
clang::CompilerInstance::getPCHContainerOperations
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
Definition: CompilerInstance.h:521
clang::serialization::ModuleFile::isModule
bool isModule() const
Is this a module file for a module (rather than a PCH or similar).
Definition: ModuleFile.h:501
clang::CompilerInstance::getModuleCache
InMemoryModuleCache & getModuleCache() const
Definition: CompilerInstance.h:816
clang::FrontendAction::getCurrentInput
const FrontendInputFile & getCurrentInput() const
Definition: FrontendAction.h:135
clang::InputKind::ModuleMap
@ ModuleMap
Definition: FrontendOptions.h:155
clang::RewriteIncludesAction::RewriteImportsListener
Definition: FrontendActions.cpp:203
CharInfo.h
clang::CompilerInstance::getDiagnosticClient
DiagnosticConsumer & getDiagnosticClient() const
Definition: CompilerInstance.h:341
clang::FixItAction::BeginSourceFileAction
bool BeginSourceFileAction(CompilerInstance &CI) override
Callback at the start of processing a single input.
Definition: FrontendActions.cpp:96
LangStandard.h
clang::RewriteMacrosInInput
void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS)
RewriteMacrosInInput - Implement -rewrite-macros mode.
Definition: RewriteMacros.cpp:89
clang::FrontendOptions::FixItSuffix
std::string FixItSuffix
If given, the new suffix for fix-it rewritten files.
Definition: FrontendOptions.h:396
clang::RewriteObjCAction::CreateASTConsumer
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: FrontendActions.cpp:164
clang::CompilerInstance::getInvocation
CompilerInvocation & getInvocation()
Definition: CompilerInstance.h:228
FrontendActions.h
clang::CreateObjCRewriter
std::unique_ptr< ASTConsumer > CreateObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning)
Definition: RewriteObjC.cpp:593
clang::HTMLPrintAction::CreateASTConsumer
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: FrontendActions.cpp:41
ASTConsumer.h
clang::FixItAction::~FixItAction
~FixItAction() override
Definition: FrontendActions.cpp:49
clang::CreateModernObjCRewriter
std::unique_ptr< ASTConsumer > CreateModernObjCRewriter(const std::string &InFile, std::unique_ptr< raw_ostream > OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning, bool LineInfo)
Definition: RewriteModernObjC.cpp:663
ModuleManager.h
clang::FixItAction::CreateASTConsumer
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: FrontendActions.cpp:52
clang::FixItAction::FixItOpts
std::unique_ptr< FixItOptions > FixItOpts
Definition: FrontendActions.h:32
clang::PreprocessorOptions::RemappedFiles
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...
Definition: PreprocessorOptions.h:157
clang::FixItRewriter
Definition: FixItRewriter.h:62
clang::serialization::ModuleFile::ModuleName
std::string ModuleName
The name of the module.
Definition: ModuleFile.h:128
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
std
Definition: Format.h:3832
ModuleFile.h
clang::RewriteIncludesAction::ExecuteAction
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
Definition: FrontendActions.cpp:304
clang::CompilerInstance::getDiagnosticOpts
DiagnosticOptions & getDiagnosticOpts()
Definition: CompilerInstance.h:267
clang
Definition: CalledOnceCheck.h:17
clang::CompilerInstance::createDefaultOutputFile
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...
Definition: CompilerInstance.cpp:746
FrontendDiagnostic.h
clang::Module::print
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:433
ASTReader.h
clang::ASTReaderListener
Abstract interface for callback invocations by the ASTReader.
Definition: ASTReader.h:114
clang::RewriteMacrosAction::ExecuteAction
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
Definition: FrontendActions.cpp:185
clang::DiagnosticConsumer::clear
virtual void clear()
Definition: Diagnostic.h:1718
clang::Rewriter
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
clang::FixItRecompile::BeginInvocation
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Definition: FrontendActions.cpp:115
clang::CompilerInstance::setFileManager
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
Definition: CompilerInstance.cpp:160
clang::FileManager::getFile
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
Definition: FileManager.cpp:196
CompilerInstance.h
clang::CompilerInstance::getFrontendOpts
FrontendOptions & getFrontendOpts()
Definition: CompilerInstance.h:281
clang::FixItAction::EndSourceFileAction
void EndSourceFileAction() override
Callback at the end of processing a single input.
Definition: FrontendActions.cpp:110
clang::FrontendOptions::FixWhatYouCan
unsigned FixWhatYouCan
Apply fixes even if there are unfixable errors.
Definition: FrontendOptions.h:253
clang::serialization::ModuleKind
ModuleKind
Specifies the kind of module that has been loaded.
Definition: ModuleFile.h:41
clang::Language::Unknown
@ Unknown
clang::CompilerInstance::getASTReader
IntrusiveRefCntPtr< ASTReader > getASTReader() const
Definition: CompilerInstance.cpp:198
clang::DoRewriteTest
void DoRewriteTest(Preprocessor &PP, raw_ostream *OS)
DoRewriteTest - A simple test for the TokenRewriter class.
Definition: RewriteTest.cpp:18
clang::ObjCRuntime::isNonFragile
bool isNonFragile() const
Does this runtime follow the set of implied behaviors for a "non-fragile" ABI?
Definition: ObjCRuntime.h:82
clang::CompilerInstance::getDiagnostics
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
Definition: CompilerInstance.h:333
clang::FixItOptions
Definition: FixItRewriter.h:33
clang::CompilerInstance::getSourceManager
SourceManager & getSourceManager() const
Return the current source manager.
Definition: CompilerInstance.h:421
FrontendActions.h
PreprocessorOptions.h
clang::CompilerInstance::setSourceManager
void setSourceManager(SourceManager *Value)
setSourceManager - Replace the current source manager.
Definition: CompilerInstance.cpp:164
clang::serialization::ModuleFile
Information about a module that has been loaded by the ASTReader.
Definition: ModuleFile.h:110
clang::CreateHTMLPrinter
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
clang::PreprocessorOptions::RemappedFilesKeepOriginalName
bool RemappedFilesKeepOriginalName
True if the SourceManager should report the original file name for contents of files that were remapp...
Definition: PreprocessorOptions.h:151