[cfe-commits] r68268 - in /cfe/trunk: include/clang/Frontend/FixItRewriter.h lib/Frontend/FixItRewriter.cpp lib/Parse/ParseInit.cpp lib/Sema/SemaDeclCXX.cpp test/Sema/fixit-c90.c test/Sema/fixit-errors.c test/Sema/fixit.c test/SemaCXX/fixit.cpp tools/clang-cc/clang-cc.cpp
Douglas Gregor
dgregor at apple.com
Wed Apr 1 18:08:08 PDT 2009
Author: dgregor
Date: Wed Apr 1 20:08:08 2009
New Revision: 68268
URL: http://llvm.org/viewvc/llvm-project?rev=68268&view=rev
Log:
Introduce a "-fixit" mode to clang-cc that applies code-modification hints.
Added:
cfe/trunk/include/clang/Frontend/FixItRewriter.h
cfe/trunk/lib/Frontend/FixItRewriter.cpp
Modified:
cfe/trunk/lib/Parse/ParseInit.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/Sema/fixit-c90.c
cfe/trunk/test/Sema/fixit-errors.c
cfe/trunk/test/Sema/fixit.c
cfe/trunk/test/SemaCXX/fixit.cpp
cfe/trunk/tools/clang-cc/clang-cc.cpp
Added: cfe/trunk/include/clang/Frontend/FixItRewriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FixItRewriter.h?rev=68268&view=auto
==============================================================================
--- cfe/trunk/include/clang/Frontend/FixItRewriter.h (added)
+++ cfe/trunk/include/clang/Frontend/FixItRewriter.h Wed Apr 1 20:08:08 2009
@@ -0,0 +1,65 @@
+//===--- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a diagnostic client adaptor that performs rewrites as
+// suggested by code modification hints attached to diagnostics. It
+// then forwards any diagnostics to the adapted diagnostic client.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
+#define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+
+class Rewriter;
+class SourceManager;
+
+class FixItRewriter : public DiagnosticClient {
+ /// \brief The adapted diagnostic client, to which we will forward
+ /// any diagnostics.
+ DiagnosticClient *Client;
+
+ /// \brief The rewriter used to perform the various code
+ /// modifications.
+ Rewriter *Rewrite;
+
+ /// \brief The number of rewriter failures.
+ unsigned NumFailures;
+
+public:
+ /// \brief Initialize a new fix-it rewriter.
+ FixItRewriter(DiagnosticClient *Client, SourceManager &SourceMgr);
+
+ /// \brief Destroy the fix-it rewriter.
+ ~FixItRewriter();
+
+ /// \brief Write the modified source file.
+ ///
+ /// \returns true if there was an error, false otherwise.
+ bool WriteFixedFile(const std::string &InFileName,
+ const std::string &OutFileName = std::string());
+
+ /// IncludeInDiagnosticCounts - This method (whose default implementation
+ /// returns true) indicates whether the diagnostics handled by this
+ /// DiagnosticClient should be included in the number of diagnostics
+ /// reported by Diagnostic.
+ virtual bool IncludeInDiagnosticCounts() const;
+
+ /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+ /// capturing it to a log as needed.
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+
+};
+
+}
+
+#endif // LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
Added: cfe/trunk/lib/Frontend/FixItRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FixItRewriter.cpp?rev=68268&view=auto
==============================================================================
--- cfe/trunk/lib/Frontend/FixItRewriter.cpp (added)
+++ cfe/trunk/lib/Frontend/FixItRewriter.cpp Wed Apr 1 20:08:08 2009
@@ -0,0 +1,140 @@
+//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a diagnostic client adaptor that performs rewrites as
+// suggested by code modification hints attached to diagnostics. It
+// then forwards any diagnostics to the adapted diagnostic client.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include <cstdio>
+using namespace clang;
+
+FixItRewriter::FixItRewriter(DiagnosticClient *Client,
+ SourceManager &SourceMgr)
+ : Client(Client), NumFailures(0) {
+ Rewrite = new Rewriter(SourceMgr);
+}
+
+FixItRewriter::~FixItRewriter() {
+ delete Rewrite;
+}
+
+bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
+ const std::string &OutFileName) {
+ if (NumFailures > 0) {
+ // FIXME: Use diagnostic machinery!
+ std::fprintf(stderr,
+ "%d fix-it failures detected; code will not be modified",
+ NumFailures);
+ return true;
+ }
+
+ llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
+ llvm::raw_ostream *OutFile;
+ if (OutFileName == "-") {
+ OutFile = &llvm::outs();
+ } else if (!OutFileName.empty()) {
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ } else if (InFileName == "-") {
+ OutFile = &llvm::outs();
+ } else {
+ llvm::sys::Path Path(InFileName);
+ Path.eraseSuffix();
+ Path.appendSuffix("cpp");
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ }
+
+ FileID MainFileID = Rewrite->getSourceMgr().getMainFileID();
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite->getRewriteBufferFor(MainFileID)) {
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ std::fprintf(stderr, "Main file is unchanged\n");
+ }
+ OutFile->flush();
+
+ return false;
+}
+
+bool FixItRewriter::IncludeInDiagnosticCounts() const {
+ return Client? Client->IncludeInDiagnosticCounts() : false;
+}
+
+void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ if (Client)
+ Client->HandleDiagnostic(DiagLevel, Info);
+
+ // Make sure that we can perform all of the modifications we
+ // in this diagnostic.
+ bool CanRewrite = true;
+ for (unsigned Idx = 0; Idx < Info.getNumCodeModificationHints(); ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ if (Hint.RemoveRange.isValid() &&
+ (!Rewrite->isRewritable(Hint.RemoveRange.getBegin()) ||
+ !Rewrite->isRewritable(Hint.RemoveRange.getEnd()) ||
+ Rewrite->getRangeSize(Hint.RemoveRange) == -1)) {
+ CanRewrite = false;
+ break;
+ }
+
+ if (Hint.InsertionLoc.isValid() &&
+ !Rewrite->isRewritable(Hint.InsertionLoc)) {
+ CanRewrite = false;
+ break;
+ }
+ }
+
+ if (!CanRewrite) // FIXME: warn the user that this rewrite couldn't be done
+ return;
+
+ bool Failed = false;
+ for (unsigned Idx = 0; Idx < Info.getNumCodeModificationHints(); ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ if (Hint.RemoveRange.isValid()) {
+ if (Hint.CodeToInsert.empty()) {
+ // We're removing code.
+ if (Rewrite->RemoveText(Hint.RemoveRange.getBegin(),
+ Rewrite->getRangeSize(Hint.RemoveRange)))
+ Failed = true;
+ } else {
+ // We're replacing code.
+ if (Rewrite->ReplaceText(Hint.RemoveRange.getBegin(),
+ Rewrite->getRangeSize(Hint.RemoveRange),
+ Hint.CodeToInsert.c_str(),
+ Hint.CodeToInsert.size()))
+ Failed = true;
+ }
+ } else {
+ // We're adding code.
+ if (Rewrite->InsertStrBefore(Hint.InsertionLoc, Hint.CodeToInsert))
+ Failed = true;
+ }
+ }
+
+ if (Failed)
+ ++NumFailures;
+}
Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Wed Apr 1 20:08:08 2009
@@ -218,7 +218,7 @@
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator())) {
Diag(Tok, diag::ext_gnu_missing_equal_designator)
- << CodeModificationHint::CreateInsertion(Tok.getLocation(), "=");
+ << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= ");
return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
true, ParseInitializer());
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Apr 1 20:08:08 2009
@@ -1309,7 +1309,7 @@
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
- << CodeModificationHint::CreateInsertion(ParamLoc, "const &");
+ << CodeModificationHint::CreateInsertion(ParamLoc, " const &");
Invalid = true;
}
}
Modified: cfe/trunk/test/Sema/fixit-c90.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/fixit-c90.c?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/test/Sema/fixit-c90.c (original)
+++ cfe/trunk/test/Sema/fixit-c90.c Wed Apr 1 20:08:08 2009
@@ -1,4 +1,4 @@
-/* RUN: clang -fsyntax-only -std=c90 -pedantic %s
+/* RUN: clang -fsyntax-only -std=c90 -pedantic -fixit %s -o - | clang-cc -pedantic -x c -std=c90 -Werror -
*/
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. Eventually,
Modified: cfe/trunk/test/Sema/fixit-errors.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/fixit-errors.c?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/test/Sema/fixit-errors.c (original)
+++ cfe/trunk/test/Sema/fixit-errors.c Wed Apr 1 20:08:08 2009
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -pedantic -Werror -x c -
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. Eventually,
Modified: cfe/trunk/test/Sema/fixit.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/fixit.c?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/test/Sema/fixit.c (original)
+++ cfe/trunk/test/Sema/fixit.c Wed Apr 1 20:08:08 2009
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only -pedantic %s
+// RUN: clang -fsyntax-only -pedantic -fixit %s -o - | clang-cc -pedantic -Werror -x c -
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. Eventually,
@@ -25,5 +25,6 @@
int f2(const char *my_string) {
// FIXME: terminal output isn't so good when "my_string" is shorter
- return my_string == "foo";
+ // FIXME: Needs an #include hint, too!
+ // return my_string == "foo";
}
Modified: cfe/trunk/test/SemaCXX/fixit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/fixit.cpp?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/fixit.cpp (original)
+++ cfe/trunk/test/SemaCXX/fixit.cpp Wed Apr 1 20:08:08 2009
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -fsyntax-only -pedantic -Werror -x c++ -
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. Eventually,
Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=68268&r1=68267&r2=68268&view=diff
==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Wed Apr 1 20:08:08 2009
@@ -25,6 +25,7 @@
#include "clang-cc.h"
#include "ASTConsumers.h"
#include "clang/Frontend/CompileOptions.h"
+#include "clang/Frontend/FixItRewriter.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/InitHeaderSearch.h"
#include "clang/Frontend/PathDiagnosticClients.h"
@@ -85,6 +86,7 @@
RewriteBlocks, // ObjC->C Rewriter for Blocks.
RewriteMacros, // Expand macros but not #includes.
RewriteTest, // Rewriter playground
+ FixIt, // Fix-It Rewriter
HTMLTest, // HTML displayer testing stuff.
EmitAssembly, // Emit a .s file.
EmitLLVM, // Emit a .ll file.
@@ -161,6 +163,8 @@
"Expand macros without full preprocessing"),
clEnumValN(RewriteBlocks, "rewrite-blocks",
"Rewrite Blocks to C"),
+ clEnumValN(FixIt, "fixit",
+ "Apply fix-it advice to the input source"),
clEnumValEnd));
@@ -1342,7 +1346,8 @@
const std::string &InFile, ProgActions PA) {
llvm::OwningPtr<ASTConsumer> Consumer;
bool ClearSourceMgr = false;
-
+ FixItRewriter *FixItRewrite = 0;
+
switch (PA) {
default:
Consumer.reset(CreateASTConsumer(InFile, PP.getDiagnostics(),
@@ -1443,6 +1448,14 @@
ClearSourceMgr = true;
break;
}
+
+ case FixIt:
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Consumer.reset(new ASTConsumer());
+ FixItRewrite = new FixItRewriter(PP.getDiagnostics().getClient(),
+ PP.getSourceManager());
+ PP.getDiagnostics().setClient(FixItRewrite);
+ break;
}
if (Consumer) {
@@ -1458,6 +1471,9 @@
ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats);
+ if (FixItRewrite)
+ FixItRewrite->WriteFixedFile(InFile, OutputFile);
+
// If in -disable-free mode, don't deallocate these when they go out of
// scope.
if (DisableFree)
More information about the cfe-commits
mailing list