[cfe-commits] r68342 - in /cfe/trunk: include/clang/Frontend/FixItRewriter.h lib/Frontend/FixItRewriter.cpp test/FixIt/fixit-at.c tools/clang-cc/clang-cc.cpp
Douglas Gregor
dgregor at apple.com
Thu Apr 2 12:05:20 PDT 2009
Author: dgregor
Date: Thu Apr 2 14:05:20 2009
New Revision: 68342
URL: http://llvm.org/viewvc/llvm-project?rev=68342&view=rev
Log:
Add a new command-line option "-fixit-at=file:line:column" that only
applies fix-its to error messages that occur at that specific location
in the program.
Added:
cfe/trunk/test/FixIt/fixit-at.c
Modified:
cfe/trunk/include/clang/Frontend/FixItRewriter.h
cfe/trunk/lib/Frontend/FixItRewriter.cpp
cfe/trunk/tools/clang-cc/clang-cc.cpp
Modified: cfe/trunk/include/clang/Frontend/FixItRewriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FixItRewriter.h?rev=68342&r1=68341&r2=68342&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FixItRewriter.h (original)
+++ cfe/trunk/include/clang/Frontend/FixItRewriter.h Thu Apr 2 14:05:20 2009
@@ -17,10 +17,23 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Rewrite/Rewriter.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
class SourceManager;
+class FileEntry;
+
+/// \brief Stores a source location in the form that it shows up on
+/// the Clang command line, e.g., file:line:column.
+///
+/// FIXME: Would prefer to use real SourceLocations, but I don't see a
+/// good way to resolve them during parsing.
+struct RequestedSourceLocation {
+ const FileEntry *File;
+ unsigned Line;
+ unsigned Column;
+};
class FixItRewriter : public DiagnosticClient {
/// \brief The diagnostics machinery.
@@ -37,6 +50,11 @@
/// \brief The number of rewriter failures.
unsigned NumFailures;
+ /// \brief Locations at which we should perform fix-its.
+ ///
+ /// When empty, perform fix-it modifications everywhere.
+ llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations;
+
public:
/// \brief Initialize a new fix-it rewriter.
FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr);
@@ -44,6 +62,12 @@
/// \brief Destroy the fix-it rewriter.
~FixItRewriter();
+ /// \brief Add a location where fix-it modifications should be
+ /// performed.
+ void addFixItLocation(RequestedSourceLocation Loc) {
+ FixItLocations.push_back(Loc);
+ }
+
/// \brief Write the modified source file.
///
/// \returns true if there was an error, false otherwise.
Modified: cfe/trunk/lib/Frontend/FixItRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FixItRewriter.cpp?rev=68342&r1=68341&r2=68342&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FixItRewriter.cpp (original)
+++ cfe/trunk/lib/Frontend/FixItRewriter.cpp Thu Apr 2 14:05:20 2009
@@ -81,8 +81,43 @@
void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
- if (Client)
- Client->HandleDiagnostic(DiagLevel, Info);
+ Client->HandleDiagnostic(DiagLevel, Info);
+
+ // Skip over any diagnostics that are ignored.
+ if (DiagLevel == Diagnostic::Ignored)
+ return;
+
+ if (!FixItLocations.empty()) {
+ // The user has specified the locations where we should perform
+ // the various fix-it modifications.
+
+ // If this diagnostic does not have any code modifications,
+ // completely ignore it, even if it's an error: fix-it locations
+ // are meant to perform specific fix-ups even in the presence of
+ // other errors.
+ if (Info.getNumCodeModificationHints() == 0)
+ return;
+
+ // See if the location of the error is one that matches what the
+ // user requested.
+ bool AcceptableLocation = false;
+ const FileEntry *File
+ = Rewrite.getSourceMgr().getFileEntryForID(
+ Info.getLocation().getFileID());
+ unsigned Line = Info.getLocation().getSpellingLineNumber();
+ unsigned Column = Info.getLocation().getSpellingColumnNumber();
+ for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
+ Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
+ Loc != LocEnd; ++Loc) {
+ if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
+ AcceptableLocation = true;
+ break;
+ }
+ }
+
+ if (!AcceptableLocation)
+ return;
+ }
// Make sure that we can perform all of the modifications we
// in this diagnostic.
Added: cfe/trunk/test/FixIt/fixit-at.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-at.c?rev=68342&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/fixit-at.c (added)
+++ cfe/trunk/test/FixIt/fixit-at.c Thu Apr 2 14:05:20 2009
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -fixit-at=fixit-at.c:3:1 %s -o - | clang-cc -verify -x c -
+
+_Complex cd;
+
+int i0 = { 17 }; // expected-warning{{braces}}
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=68342&r1=68341&r2=68342&view=diff
==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Thu Apr 2 14:05:20 2009
@@ -58,9 +58,94 @@
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Signals.h"
+#include <cstdlib>
+
using namespace clang;
//===----------------------------------------------------------------------===//
+// Source Location Parser
+//===----------------------------------------------------------------------===//
+
+/// \brief A source location that has been parsed on the command line.
+struct ParsedSourceLocation {
+ std::string FileName;
+ unsigned Line;
+ unsigned Column;
+
+ /// \brief Try to resolve the file name of a parsed source location.
+ ///
+ /// \returns true if there was an error, false otherwise.
+ bool ResolveLocation(FileManager &FileMgr, RequestedSourceLocation &Result);
+};
+
+bool
+ParsedSourceLocation::ResolveLocation(FileManager &FileMgr,
+ RequestedSourceLocation &Result) {
+ const FileEntry *File = FileMgr.getFile(FileName);
+ if (!File)
+ return true;
+
+ Result.File = File;
+ Result.Line = Line;
+ Result.Column = Column;
+ return false;
+}
+
+namespace llvm {
+ namespace cl {
+ /// \brief Command-line option parser that parses source locations.
+ ///
+ /// Source locations are of the form filename:line:column.
+ template<>
+ class parser<ParsedSourceLocation>
+ : public basic_parser<ParsedSourceLocation> {
+ public:
+ bool parse(Option &O, const char *ArgName,
+ const std::string &ArgValue,
+ ParsedSourceLocation &Val);
+ };
+
+ bool
+ parser<ParsedSourceLocation>::
+ parse(Option &O, const char *ArgName, const std::string &ArgValue,
+ ParsedSourceLocation &Val) {
+ using namespace clang;
+
+ const char *ExpectedFormat
+ = "source location must be of the form filename:line:column";
+ std::string::size_type SecondColon = ArgValue.rfind(':');
+ if (SecondColon == std::string::npos) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+ char *EndPtr;
+ long Column
+ = std::strtol(ArgValue.c_str() + SecondColon + 1, &EndPtr, 10);
+ if (EndPtr != ArgValue.c_str() + ArgValue.size()) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+
+ std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1);
+ if (SecondColon == std::string::npos) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+ long Line = std::strtol(ArgValue.c_str() + FirstColon + 1, &EndPtr, 10);
+ if (EndPtr != ArgValue.c_str() + SecondColon) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+
+ Val.FileName = ArgValue.substr(0, FirstColon);
+ Val.Line = Line;
+ Val.Column = Column;
+ return false;
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Global options.
//===----------------------------------------------------------------------===//
@@ -1262,6 +1347,13 @@
}
//===----------------------------------------------------------------------===//
+// Fix-It Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::list<ParsedSourceLocation>
+FixItAtLocations("fixit-at", llvm::cl::value_desc("source-location"),
+ llvm::cl::desc("Perform Fix-It modifications at the given source location"));
+
+//===----------------------------------------------------------------------===//
// Main driver
//===----------------------------------------------------------------------===//
@@ -1454,6 +1546,35 @@
if (Consumer) {
llvm::OwningPtr<ASTContext> ContextOwner;
+ if (FixItAtLocations.size() > 0) {
+ // Even without the "-fixit" flag, with may have some specific
+ // locations where the user has requested fixes. Process those
+ // locations now.
+ if (!FixItRewrite)
+ FixItRewrite = new FixItRewriter(PP.getDiagnostics(),
+ PP.getSourceManager());
+
+ bool AddedFixitLocation = false;
+ for (unsigned Idx = 0, Last = FixItAtLocations.size();
+ Idx != Last; ++Idx) {
+ RequestedSourceLocation Requested;
+ if (FixItAtLocations[Idx].ResolveLocation(PP.getFileManager(),
+ Requested)) {
+ fprintf(stderr, "FIX-IT could not find file \"%s\"\n",
+ FixItAtLocations[Idx].FileName.c_str());
+ } else {
+ FixItRewrite->addFixItLocation(Requested);
+ AddedFixitLocation = true;
+ }
+ }
+
+ if (!AddedFixitLocation) {
+ // All of the fix-it locations were bad. Don't fix anything.
+ delete FixItRewrite;
+ FixItRewrite = 0;
+ }
+ }
+
ContextOwner.reset(new ASTContext(PP.getLangOptions(),
PP.getSourceManager(),
PP.getTargetInfo(),
More information about the cfe-commits
mailing list