diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-01-26 02:40:48 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-01-26 02:40:48 +0000 |
commit | 24e9afff4345b331c8eab721741c3d6cf6600bbf (patch) | |
tree | 448a5967ebb13639c601d69768120328419d6702 /clang | |
parent | 7b878febf1bb8bec97f0ed55d5c09298b329ad12 (diff) | |
download | bcm5719-llvm-24e9afff4345b331c8eab721741c3d6cf6600bbf.tar.gz bcm5719-llvm-24e9afff4345b331c8eab721741c3d6cf6600bbf.zip |
Introduce 3 new fixit options:
-fixit-recompile
applies fixits and recompiles the result
-fixit-to-temporary
applies fixits to temporary files
-fix-only-warnings">,
applies fixits for warnings only, not errors
Combining "-fixit-recompile -fixit-to-temporary" allows testing the result of fixits
without touching the original sources.
llvm-svn: 149027
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/Diagnostic.h | 1 | ||||
-rw-r--r-- | clang/include/clang/Driver/CC1Options.td | 6 | ||||
-rw-r--r-- | clang/include/clang/Frontend/FrontendOptions.h | 3 | ||||
-rw-r--r-- | clang/include/clang/Rewrite/FixItRewriter.h | 18 | ||||
-rw-r--r-- | clang/include/clang/Rewrite/FrontendActions.h | 12 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 9 | ||||
-rw-r--r-- | clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Rewrite/FixItRewriter.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Rewrite/FrontendActions.cpp | 57 | ||||
-rw-r--r-- | clang/test/FixIt/fixit-recompile.c | 6 |
10 files changed, 139 insertions, 7 deletions
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 0a785fd0a71..4f5fe6501ef 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -1070,6 +1070,7 @@ public: unsigned getNumErrors() const { return NumErrors; } unsigned getNumWarnings() const { return NumWarnings; } + virtual void clear() { NumWarnings = NumErrors = 0; } virtual ~DiagnosticConsumer(); diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 1125ddd6033..bf7b915e3d9 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -453,6 +453,12 @@ def fdump_record_layouts : Flag<"-fdump-record-layouts">, HelpText<"Dump record layout information">; def fix_what_you_can : Flag<"-fix-what-you-can">, HelpText<"Apply fix-it advice even in the presence of unfixable errors">; +def fix_only_warnings : Flag<"-fix-only-warnings">, + HelpText<"Apply fix-it advice only for warnings, not errors">; +def fixit_recompile : Flag<"-fixit-recompile">, + HelpText<"Apply fix-it changes and recompile">; +def fixit_to_temp : Flag<"-fixit-to-temporary">, + HelpText<"Apply fix-it changes to temporary files">; // Generic forwarding to LLVM options. This should only be used for debugging // and experimental features. diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 637ceff5783..080e1435033 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -102,6 +102,9 @@ public: unsigned ShowVersion : 1; ///< Show the -version text. unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are /// unfixable errors. + unsigned FixOnlyWarnings : 1; ///< Apply fixes only for warnings. + unsigned FixAndRecompile : 1; ///< Apply fixes and recompile. + unsigned FixToTemporaries : 1; ///< Apply fixes to temporary files. unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the /// migrator can fix them diff --git a/clang/include/clang/Rewrite/FixItRewriter.h b/clang/include/clang/Rewrite/FixItRewriter.h index bf7e7911c97..aeda25b24e2 100644 --- a/clang/include/clang/Rewrite/FixItRewriter.h +++ b/clang/include/clang/Rewrite/FixItRewriter.h @@ -26,6 +26,9 @@ class FileEntry; class FixItOptions { public: + FixItOptions() : FixWhatYouCan(false), + FixOnlyWarnings(false), Silent(false) { } + virtual ~FixItOptions(); /// \brief This file is about to be rewritten. Return the name of the file @@ -34,6 +37,14 @@ public: /// \brief Whether to abort fixing a file when not all errors could be fixed. bool FixWhatYouCan; + + /// \brief Whether to only fix warnings and not errors. + bool FixOnlyWarnings; + + /// \brief If true, only pass the diagnostic to the actual diagnostic consumer + /// if it is an error or a fixit was applied as part of the diagnostic. + /// It basically silences warnings without accompanying fixits. + bool Silent; }; class FixItRewriter : public DiagnosticConsumer { @@ -47,6 +58,7 @@ class FixItRewriter : public DiagnosticConsumer { /// \brief The diagnostic client that performs the actual formatting /// of error messages. DiagnosticConsumer *Client; + bool OwnsClient; /// \brief Turn an input path into an output path. NULL implies overwriting /// the original. @@ -55,6 +67,9 @@ class FixItRewriter : public DiagnosticConsumer { /// \brief The number of rewriter failures. unsigned NumFailures; + /// \brief Whether the previous diagnostic was not passed to the consumer. + bool PrevDiagSilenced; + public: typedef Rewriter::buffer_iterator iterator; @@ -82,7 +97,8 @@ public: /// \brief Write the modified source files. /// /// \returns true if there was an error, false otherwise. - bool WriteFixedFiles(); + bool WriteFixedFiles( + std::vector<std::pair<std::string, std::string> > *RewrittenFiles = 0); /// IncludeInDiagnosticCounts - This method (whose default implementation /// returns true) indicates whether the diagnostics handled by this diff --git a/clang/include/clang/Rewrite/FrontendActions.h b/clang/include/clang/Rewrite/FrontendActions.h index f7aeefae7e5..35a37ee6509 100644 --- a/clang/include/clang/Rewrite/FrontendActions.h +++ b/clang/include/clang/Rewrite/FrontendActions.h @@ -46,6 +46,18 @@ public: ~FixItAction(); }; +/// \brief Emits changes to temporary files and uses them for the original +/// frontend action. +class FixItRecompile : public WrapperFrontendAction { + FrontendAction *WrappedAction; +public: + FixItRecompile(FrontendAction *WrappedAction) + : WrapperFrontendAction(WrappedAction), WrappedAction(WrappedAction) {} + +protected: + virtual bool BeginInvocation(CompilerInstance &CI); +}; + class RewriteObjCAction : public ASTFrontendAction { protected: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index aa367b0a74a..7e5af12d517 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -466,6 +466,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-version"); if (Opts.FixWhatYouCan) Res.push_back("-fix-what-you-can"); + if (Opts.FixOnlyWarnings) + Res.push_back("-fix-only-warnings"); + if (Opts.FixAndRecompile) + Res.push_back("-fixit-recompile"); + if (Opts.FixToTemporaries) + Res.push_back("-fixit-to-temporary"); switch (Opts.ARCMTAction) { case FrontendOptions::ARCMT_None: break; @@ -1401,6 +1407,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); + Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings); + Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile); + Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); Opts.ARCMTAction = FrontendOptions::ARCMT_None; if (const Arg *A = Args.getLastArg(OPT_arcmt_check, diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 2782a85beb6..9f2bdf25be5 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -87,6 +87,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { if (!Act) return 0; + if (CI.getFrontendOpts().FixAndRecompile) { + Act = new FixItRecompile(Act); + } + // Potentially wrap the base FE action in an ARC Migrate Tool action. switch (CI.getFrontendOpts().ARCMTAction) { case FrontendOptions::ARCMT_None: diff --git a/clang/lib/Rewrite/FixItRewriter.cpp b/clang/lib/Rewrite/FixItRewriter.cpp index 632c0de0742..51029665e47 100644 --- a/clang/lib/Rewrite/FixItRewriter.cpp +++ b/clang/lib/Rewrite/FixItRewriter.cpp @@ -31,14 +31,16 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, : Diags(Diags), Rewrite(SourceMgr, LangOpts), FixItOpts(FixItOpts), - NumFailures(0) { + NumFailures(0), + PrevDiagSilenced(false) { + OwnsClient = Diags.ownsClient(); Client = Diags.takeClient(); Diags.setClient(this); } FixItRewriter::~FixItRewriter() { Diags.takeClient(); - Diags.setClient(Client); + Diags.setClient(Client, OwnsClient); } bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { @@ -49,7 +51,8 @@ bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) { return false; } -bool FixItRewriter::WriteFixedFiles() { +bool FixItRewriter::WriteFixedFiles( + std::vector<std::pair<std::string, std::string> > *RewrittenFiles) { if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) { Diag(FullSourceLoc(), diag::warn_fixit_no_changes); return true; @@ -69,6 +72,9 @@ bool FixItRewriter::WriteFixedFiles() { RewriteBuffer &RewriteBuf = I->second; RewriteBuf.write(OS); OS.flush(); + + if (RewrittenFiles) + RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename)); } return false; @@ -83,11 +89,24 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); - Client->HandleDiagnostic(DiagLevel, Info); + if (!FixItOpts->Silent || + DiagLevel >= DiagnosticsEngine::Error || + (DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) || + (DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) { + Client->HandleDiagnostic(DiagLevel, Info); + PrevDiagSilenced = false; + } else { + PrevDiagSilenced = true; + } // Skip over any diagnostics that are ignored or notes. if (DiagLevel <= DiagnosticsEngine::Note) return; + // Skip over errors if we are only fixing warnings. + if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) { + ++NumFailures; + return; + } // Make sure that we can perform all of the modifications we // in this diagnostic. @@ -107,8 +126,7 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, Diag(Info.getLocation(), diag::note_fixit_in_macro); // If this was an error, refuse to perform any rewriting. - if (DiagLevel == DiagnosticsEngine::Error || - DiagLevel == DiagnosticsEngine::Fatal) { + if (DiagLevel >= DiagnosticsEngine::Error) { if (++NumFailures == 1) Diag(Info.getLocation(), diag::note_fixit_unfixed_error); } diff --git a/clang/lib/Rewrite/FrontendActions.cpp b/clang/lib/Rewrite/FrontendActions.cpp index f00e7fd9c91..c1568cd5223 100644 --- a/clang/lib/Rewrite/FrontendActions.cpp +++ b/clang/lib/Rewrite/FrontendActions.cpp @@ -12,6 +12,7 @@ #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" @@ -21,6 +22,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -64,6 +66,22 @@ public: return Path.str(); } }; + +class FixItRewriteToTemp : public FixItOptions { +public: + std::string RewriteFilename(const std::string &Filename) { + llvm::SmallString<128> Path; + Path = llvm::sys::path::filename(Filename); + Path += "-%%%%%%%%"; + Path += llvm::sys::path::extension(Filename); + int fd; + llvm::SmallString<128> NewPath; + if (llvm::sys::fs::unique_file(Path.str(), fd, NewPath) + == llvm::errc::success) + ::close(fd); + return NewPath.str(); + } +}; } // end anonymous namespace bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, @@ -86,6 +104,45 @@ void FixItAction::EndSourceFileAction() { Rewriter->WriteFixedFiles(); } +bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { + + std::vector<std::pair<std::string, std::string> > RewrittenFiles; + bool err = false; + { + const FrontendOptions &FEOpts = CI.getFrontendOpts(); + llvm::OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction()); + FixAction->BeginSourceFile(CI, FEOpts.Inputs[0]); + + llvm::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); + } + if (err) + return false; + CI.getDiagnosticClient().clear(); + + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), + RewrittenFiles.begin(), RewrittenFiles.end()); + PPOpts.RemappedFilesKeepOriginalName = false; + + return true; +} + //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/clang/test/FixIt/fixit-recompile.c b/clang/test/FixIt/fixit-recompile.c new file mode 100644 index 00000000000..a2e62fbddcd --- /dev/null +++ b/clang/test/FixIt/fixit-recompile.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -E -o - | FileCheck %s +// RUN: not %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -fix-only-warnings + +_Complex cd; + +// CHECK: _Complex double cd; |