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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149027 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp
index 632c0de..5102966 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/FixItRewriter.cpp
@@ -31,14 +31,16 @@
: 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 @@
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 @@
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 @@
// 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 @@
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/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index f00e7fd..c1568cd 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/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 @@
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 @@
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
//===----------------------------------------------------------------------===//