Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 61d679a

Browse files
committed
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
1 parent 7a776be commit 61d679a

File tree

10 files changed

+139
-7
lines changed

10 files changed

+139
-7
lines changed

include/clang/Basic/Diagnostic.h

+1
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,7 @@ class DiagnosticConsumer {
10701070

10711071
unsigned getNumErrors() const { return NumErrors; }
10721072
unsigned getNumWarnings() const { return NumWarnings; }
1073+
virtual void clear() { NumWarnings = NumErrors = 0; }
10731074

10741075
virtual ~DiagnosticConsumer();
10751076

include/clang/Driver/CC1Options.td

+6
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,12 @@ def fdump_record_layouts : Flag<"-fdump-record-layouts">,
453453
HelpText<"Dump record layout information">;
454454
def fix_what_you_can : Flag<"-fix-what-you-can">,
455455
HelpText<"Apply fix-it advice even in the presence of unfixable errors">;
456+
def fix_only_warnings : Flag<"-fix-only-warnings">,
457+
HelpText<"Apply fix-it advice only for warnings, not errors">;
458+
def fixit_recompile : Flag<"-fixit-recompile">,
459+
HelpText<"Apply fix-it changes and recompile">;
460+
def fixit_to_temp : Flag<"-fixit-to-temporary">,
461+
HelpText<"Apply fix-it changes to temporary files">;
456462

457463
// Generic forwarding to LLVM options. This should only be used for debugging
458464
// and experimental features.

include/clang/Frontend/FrontendOptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class FrontendOptions {
102102
unsigned ShowVersion : 1; ///< Show the -version text.
103103
unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are
104104
/// unfixable errors.
105+
unsigned FixOnlyWarnings : 1; ///< Apply fixes only for warnings.
106+
unsigned FixAndRecompile : 1; ///< Apply fixes and recompile.
107+
unsigned FixToTemporaries : 1; ///< Apply fixes to temporary files.
105108
unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the
106109
/// migrator can fix them
107110

include/clang/Rewrite/FixItRewriter.h

+17-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class FileEntry;
2626

2727
class FixItOptions {
2828
public:
29+
FixItOptions() : FixWhatYouCan(false),
30+
FixOnlyWarnings(false), Silent(false) { }
31+
2932
virtual ~FixItOptions();
3033

3134
/// \brief This file is about to be rewritten. Return the name of the file
@@ -34,6 +37,14 @@ class FixItOptions {
3437

3538
/// \brief Whether to abort fixing a file when not all errors could be fixed.
3639
bool FixWhatYouCan;
40+
41+
/// \brief Whether to only fix warnings and not errors.
42+
bool FixOnlyWarnings;
43+
44+
/// \brief If true, only pass the diagnostic to the actual diagnostic consumer
45+
/// if it is an error or a fixit was applied as part of the diagnostic.
46+
/// It basically silences warnings without accompanying fixits.
47+
bool Silent;
3748
};
3849

3950
class FixItRewriter : public DiagnosticConsumer {
@@ -47,6 +58,7 @@ class FixItRewriter : public DiagnosticConsumer {
4758
/// \brief The diagnostic client that performs the actual formatting
4859
/// of error messages.
4960
DiagnosticConsumer *Client;
61+
bool OwnsClient;
5062

5163
/// \brief Turn an input path into an output path. NULL implies overwriting
5264
/// the original.
@@ -55,6 +67,9 @@ class FixItRewriter : public DiagnosticConsumer {
5567
/// \brief The number of rewriter failures.
5668
unsigned NumFailures;
5769

70+
/// \brief Whether the previous diagnostic was not passed to the consumer.
71+
bool PrevDiagSilenced;
72+
5873
public:
5974
typedef Rewriter::buffer_iterator iterator;
6075

@@ -82,7 +97,8 @@ class FixItRewriter : public DiagnosticConsumer {
8297
/// \brief Write the modified source files.
8398
///
8499
/// \returns true if there was an error, false otherwise.
85-
bool WriteFixedFiles();
100+
bool WriteFixedFiles(
101+
std::vector<std::pair<std::string, std::string> > *RewrittenFiles = 0);
86102

87103
/// IncludeInDiagnosticCounts - This method (whose default implementation
88104
/// returns true) indicates whether the diagnostics handled by this

include/clang/Rewrite/FrontendActions.h

+12
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ class FixItAction : public ASTFrontendAction {
4646
~FixItAction();
4747
};
4848

49+
/// \brief Emits changes to temporary files and uses them for the original
50+
/// frontend action.
51+
class FixItRecompile : public WrapperFrontendAction {
52+
FrontendAction *WrappedAction;
53+
public:
54+
FixItRecompile(FrontendAction *WrappedAction)
55+
: WrapperFrontendAction(WrappedAction), WrappedAction(WrappedAction) {}
56+
57+
protected:
58+
virtual bool BeginInvocation(CompilerInstance &CI);
59+
};
60+
4961
class RewriteObjCAction : public ASTFrontendAction {
5062
protected:
5163
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,

lib/Frontend/CompilerInvocation.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
466466
Res.push_back("-version");
467467
if (Opts.FixWhatYouCan)
468468
Res.push_back("-fix-what-you-can");
469+
if (Opts.FixOnlyWarnings)
470+
Res.push_back("-fix-only-warnings");
471+
if (Opts.FixAndRecompile)
472+
Res.push_back("-fixit-recompile");
473+
if (Opts.FixToTemporaries)
474+
Res.push_back("-fixit-to-temporary");
469475
switch (Opts.ARCMTAction) {
470476
case FrontendOptions::ARCMT_None:
471477
break;
@@ -1401,6 +1407,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
14011407
Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
14021408
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
14031409
Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
1410+
Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings);
1411+
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
1412+
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
14041413

14051414
Opts.ARCMTAction = FrontendOptions::ARCMT_None;
14061415
if (const Arg *A = Args.getLastArg(OPT_arcmt_check,

lib/FrontendTool/ExecuteCompilerInvocation.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
8787
if (!Act)
8888
return 0;
8989

90+
if (CI.getFrontendOpts().FixAndRecompile) {
91+
Act = new FixItRecompile(Act);
92+
}
93+
9094
// Potentially wrap the base FE action in an ARC Migrate Tool action.
9195
switch (CI.getFrontendOpts().ARCMTAction) {
9296
case FrontendOptions::ARCMT_None:

lib/Rewrite/FixItRewriter.cpp

+24-6
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
3131
: Diags(Diags),
3232
Rewrite(SourceMgr, LangOpts),
3333
FixItOpts(FixItOpts),
34-
NumFailures(0) {
34+
NumFailures(0),
35+
PrevDiagSilenced(false) {
36+
OwnsClient = Diags.ownsClient();
3537
Client = Diags.takeClient();
3638
Diags.setClient(this);
3739
}
3840

3941
FixItRewriter::~FixItRewriter() {
4042
Diags.takeClient();
41-
Diags.setClient(Client);
43+
Diags.setClient(Client, OwnsClient);
4244
}
4345

4446
bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
@@ -49,7 +51,8 @@ bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
4951
return false;
5052
}
5153

52-
bool FixItRewriter::WriteFixedFiles() {
54+
bool FixItRewriter::WriteFixedFiles(
55+
std::vector<std::pair<std::string, std::string> > *RewrittenFiles) {
5356
if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) {
5457
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
5558
return true;
@@ -69,6 +72,9 @@ bool FixItRewriter::WriteFixedFiles() {
6972
RewriteBuffer &RewriteBuf = I->second;
7073
RewriteBuf.write(OS);
7174
OS.flush();
75+
76+
if (RewrittenFiles)
77+
RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename));
7278
}
7379

7480
return false;
@@ -83,11 +89,24 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
8389
// Default implementation (Warnings/errors count).
8490
DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
8591

86-
Client->HandleDiagnostic(DiagLevel, Info);
92+
if (!FixItOpts->Silent ||
93+
DiagLevel >= DiagnosticsEngine::Error ||
94+
(DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) ||
95+
(DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) {
96+
Client->HandleDiagnostic(DiagLevel, Info);
97+
PrevDiagSilenced = false;
98+
} else {
99+
PrevDiagSilenced = true;
100+
}
87101

88102
// Skip over any diagnostics that are ignored or notes.
89103
if (DiagLevel <= DiagnosticsEngine::Note)
90104
return;
105+
// Skip over errors if we are only fixing warnings.
106+
if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) {
107+
++NumFailures;
108+
return;
109+
}
91110

92111
// Make sure that we can perform all of the modifications we
93112
// in this diagnostic.
@@ -107,8 +126,7 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
107126
Diag(Info.getLocation(), diag::note_fixit_in_macro);
108127

109128
// If this was an error, refuse to perform any rewriting.
110-
if (DiagLevel == DiagnosticsEngine::Error ||
111-
DiagLevel == DiagnosticsEngine::Fatal) {
129+
if (DiagLevel >= DiagnosticsEngine::Error) {
112130
if (++NumFailures == 1)
113131
Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
114132
}

lib/Rewrite/FrontendActions.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "clang/Lex/Preprocessor.h"
1313
#include "clang/Parse/Parser.h"
1414
#include "clang/Basic/FileManager.h"
15+
#include "clang/Frontend/FrontendActions.h"
1516
#include "clang/Frontend/CompilerInstance.h"
1617
#include "clang/Frontend/FrontendDiagnostic.h"
1718
#include "clang/Frontend/Utils.h"
@@ -21,6 +22,7 @@
2122
#include "llvm/ADT/OwningPtr.h"
2223
#include "llvm/Support/raw_ostream.h"
2324
#include "llvm/Support/Path.h"
25+
#include "llvm/Support/FileSystem.h"
2426
using namespace clang;
2527

2628
//===----------------------------------------------------------------------===//
@@ -64,6 +66,22 @@ class FixItActionSuffixInserter : public FixItOptions {
6466
return Path.str();
6567
}
6668
};
69+
70+
class FixItRewriteToTemp : public FixItOptions {
71+
public:
72+
std::string RewriteFilename(const std::string &Filename) {
73+
llvm::SmallString<128> Path;
74+
Path = llvm::sys::path::filename(Filename);
75+
Path += "-%%%%%%%%";
76+
Path += llvm::sys::path::extension(Filename);
77+
int fd;
78+
llvm::SmallString<128> NewPath;
79+
if (llvm::sys::fs::unique_file(Path.str(), fd, NewPath)
80+
== llvm::errc::success)
81+
::close(fd);
82+
return NewPath.str();
83+
}
84+
};
6785
} // end anonymous namespace
6886

6987
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
@@ -86,6 +104,45 @@ void FixItAction::EndSourceFileAction() {
86104
Rewriter->WriteFixedFiles();
87105
}
88106

107+
bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
108+
109+
std::vector<std::pair<std::string, std::string> > RewrittenFiles;
110+
bool err = false;
111+
{
112+
const FrontendOptions &FEOpts = CI.getFrontendOpts();
113+
llvm::OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction());
114+
FixAction->BeginSourceFile(CI, FEOpts.Inputs[0]);
115+
116+
llvm::OwningPtr<FixItOptions> FixItOpts;
117+
if (FEOpts.FixToTemporaries)
118+
FixItOpts.reset(new FixItRewriteToTemp());
119+
else
120+
FixItOpts.reset(new FixItRewriteInPlace());
121+
FixItOpts->Silent = true;
122+
FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
123+
FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
124+
FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
125+
CI.getLangOpts(), FixItOpts.get());
126+
FixAction->Execute();
127+
128+
err = Rewriter.WriteFixedFiles(&RewrittenFiles);
129+
130+
FixAction->EndSourceFile();
131+
CI.setSourceManager(0);
132+
CI.setFileManager(0);
133+
}
134+
if (err)
135+
return false;
136+
CI.getDiagnosticClient().clear();
137+
138+
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
139+
PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
140+
RewrittenFiles.begin(), RewrittenFiles.end());
141+
PPOpts.RemappedFilesKeepOriginalName = false;
142+
143+
return true;
144+
}
145+
89146
//===----------------------------------------------------------------------===//
90147
// Preprocessor Actions
91148
//===----------------------------------------------------------------------===//

test/FixIt/fixit-recompile.c

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -E -o - | FileCheck %s
2+
// RUN: not %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -fix-only-warnings
3+
4+
_Complex cd;
5+
6+
// CHECK: _Complex double cd;

0 commit comments

Comments
 (0)