diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Frontend/FixItRewriter.cpp | 140 | ||||
-rw-r--r-- | clang/lib/Parse/ParseInit.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 2 |
3 files changed, 142 insertions, 2 deletions
diff --git a/clang/lib/Frontend/FixItRewriter.cpp b/clang/lib/Frontend/FixItRewriter.cpp new file mode 100644 index 00000000000..a53d1e56d14 --- /dev/null +++ b/clang/lib/Frontend/FixItRewriter.cpp @@ -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; +} diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 7837a0c7fd5..052586f5ca3 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -218,7 +218,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { (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()); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c2928dc6ccf..feb127bcf46 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1309,7 +1309,7 @@ bool Sema::CheckConstructor(CXXConstructorDecl *Constructor) { 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; } } |