//===--- FrontendActions.cpp ----------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/Rewrite/FrontendActions.h" #include "clang/AST/ASTConsumer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/Parser.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Rewrite/ASTConsumers.h" #include "clang/Rewrite/FixItRewriter.h" #include "clang/Rewrite/Rewriters.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" #include "llvm/Support/FileSystem.h" using namespace clang; //===----------------------------------------------------------------------===// // AST Consumer Actions //===----------------------------------------------------------------------===// ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) return CreateHTMLPrinter(OS, CI.getPreprocessor()); return 0; } FixItAction::FixItAction() {} FixItAction::~FixItAction() {} ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return new ASTConsumer(); } namespace { class FixItRewriteInPlace : public FixItOptions { public: std::string RewriteFilename(const std::string &Filename, int &fd) { fd = -1; return Filename; } }; class FixItActionSuffixInserter : public FixItOptions { std::string NewSuffix; public: FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) : NewSuffix(NewSuffix) { this->FixWhatYouCan = FixWhatYouCan; } std::string RewriteFilename(const std::string &Filename, int &fd) { fd = -1; SmallString<128> Path(Filename); llvm::sys::path::replace_extension(Path, NewSuffix + llvm::sys::path::extension(Path)); return Path.str(); } }; class FixItRewriteToTemp : public FixItOptions { public: std::string RewriteFilename(const std::string &Filename, int &fd) { SmallString<128> Path; Path = llvm::sys::path::filename(Filename); Path += "-%%%%%%%%"; Path += llvm::sys::path::extension(Filename); SmallString<128> NewPath; llvm::sys::fs::unique_file(Path.str(), fd, NewPath); return NewPath.str(); } }; } // end anonymous namespace bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) { const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); if (!FEOpts.FixItSuffix.empty()) { FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, FEOpts.FixWhatYouCan)); } else { FixItOpts.reset(new FixItRewriteInPlace); FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; } Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), CI.getLangOpts(), FixItOpts.get())); return true; } void FixItAction::EndSourceFileAction() { // Otherwise rewrite all files. Rewriter->WriteFixedFiles(); } bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { std::vector<std::pair<std::string, std::string> > RewrittenFiles; bool err = false; { const FrontendOptions &FEOpts = CI.getFrontendOpts(); OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction()); if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { OwningPtr<FixItOptions> FixItOpts; if (FEOpts.FixToTemporaries) FixItOpts.reset(new FixItRewriteToTemp()); else FixItOpts.reset(new FixItRewriteInPlace()); FixItOpts->Silent = true; FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings; FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(), CI.getLangOpts(), FixItOpts.get()); FixAction->Execute(); err = Rewriter.WriteFixedFiles(&RewrittenFiles); FixAction->EndSourceFile(); CI.setSourceManager(0); CI.setFileManager(0); } else { err = true; } } if (err) return false; CI.getDiagnosticClient().clear(); CI.getDiagnostics().Reset(); PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), RewrittenFiles.begin(), RewrittenFiles.end()); PPOpts.RemappedFilesKeepOriginalName = false; return true; } //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { if (CI.getLangOpts().ObjCNonFragileABI) return CreateModernObjCRewriter(InFile, OS, CI.getDiagnostics(), CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros); return CreateObjCRewriter(InFile, OS, CI.getDiagnostics(), CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros); } return 0; } void RewriteMacrosAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); if (!OS) return; RewriteMacrosInInput(CI.getPreprocessor(), OS); } void RewriteTestAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); if (!OS) return; DoRewriteTest(CI.getPreprocessor(), OS); }