diff options
author | Daniel Dunbar <daniel@zuster.org> | 2010-06-15 17:48:49 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2010-06-15 17:48:49 +0000 |
commit | 9b414d3e2d0cb84512b55a3275a98490b090162a (patch) | |
tree | a9e89bf09e843286a73c99a9e18520c48ad725b0 /lib/Rewrite/FixItRewriter.cpp | |
parent | c722ea4fbf886d6460b256b5e819a4ee751d5fff (diff) |
Break Frontend's dependency on Rewrite, Checker and CodeGen in shared library configuration
Currently, all AST consumers are located in the Frontend library,
meaning that in a shared library configuration, Frontend has a
dependency on Rewrite, Checker and CodeGen. This is suboptimal for
clients which only wish to make use of the frontend. CodeGen in
particular introduces a large number of unwanted dependencies.
This patch breaks the dependency by moving all AST consumers with
dependencies on Rewrite, Checker and/or CodeGen to their respective
libraries. The patch therefore introduces dependencies in the other
direction (i.e. from Rewrite, Checker and CodeGen to Frontend).
After applying this patch, Clang builds correctly using CMake and
shared libraries ("cmake -DBUILD_SHARED_LIBS=ON").
N.B. This patch includes file renames which are indicated in the
patch body.
Changes in this revision of the patch:
- Fixed some copy-paste mistakes in the header files
- Modified certain aspects of the coding to comply with the LLVM
Coding Standards
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106010 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Rewrite/FixItRewriter.cpp')
-rw-r--r-- | lib/Rewrite/FixItRewriter.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp new file mode 100644 index 0000000000..29ac7e380b --- /dev/null +++ b/lib/Rewrite/FixItRewriter.cpp @@ -0,0 +1,167 @@ +//===--- 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/Rewrite/FixItRewriter.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include <cstdio> + +using namespace clang; + +FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts, + FixItPathRewriter *PathRewriter) + : Diags(Diags), + Rewrite(SourceMgr, LangOpts), + PathRewriter(PathRewriter), + NumFailures(0) { + Client = Diags.getClient(); + Diags.setClient(this); +} + +FixItRewriter::~FixItRewriter() { + Diags.setClient(Client); +} + +bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) { + const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); + if (!RewriteBuf) return true; + RewriteBuf->write(OS); + OS.flush(); + return false; +} + +bool FixItRewriter::WriteFixedFiles() { + if (NumFailures > 0) { + Diag(FullSourceLoc(), diag::warn_fixit_no_changes); + return true; + } + + for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { + const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); + std::string Filename = Entry->getName(); + if (PathRewriter) + Filename = PathRewriter->RewriteFilename(Filename); + std::string Err; + llvm::raw_fd_ostream OS(Filename.c_str(), Err, + llvm::raw_fd_ostream::F_Binary); + if (!Err.empty()) { + Diags.Report(clang::diag::err_fe_unable_to_open_output) + << Filename << Err; + continue; + } + RewriteBuffer &RewriteBuf = I->second; + RewriteBuf.write(OS); + OS.flush(); + } + + return false; +} + +bool FixItRewriter::IncludeInDiagnosticCounts() const { + return Client ? Client->IncludeInDiagnosticCounts() : true; +} + +void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + Client->HandleDiagnostic(DiagLevel, Info); + + // Skip over any diagnostics that are ignored or notes. + if (DiagLevel <= Diagnostic::Note) + return; + + // Make sure that we can perform all of the modifications we + // in this diagnostic. + bool CanRewrite = Info.getNumFixItHints() > 0; + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); + Idx < Last; ++Idx) { + const FixItHint &Hint = Info.getFixItHint(Idx); + if (Hint.RemoveRange.isValid() && + Rewrite.getRangeSize(Hint.RemoveRange) == -1) { + CanRewrite = false; + break; + } + + if (Hint.InsertionLoc.isValid() && + !Rewrite.isRewritable(Hint.InsertionLoc)) { + CanRewrite = false; + break; + } + } + + if (!CanRewrite) { + if (Info.getNumFixItHints() > 0) + Diag(Info.getLocation(), diag::note_fixit_in_macro); + + // If this was an error, refuse to perform any rewriting. + if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) { + if (++NumFailures == 1) + Diag(Info.getLocation(), diag::note_fixit_unfixed_error); + } + return; + } + + bool Failed = false; + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); + Idx < Last; ++Idx) { + const FixItHint &Hint = Info.getFixItHint(Idx); + if (!Hint.RemoveRange.isValid()) { + // We're adding code. + if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert)) + Failed = true; + continue; + } + + if (Hint.CodeToInsert.empty()) { + // We're removing code. + if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(), + Rewrite.getRangeSize(Hint.RemoveRange))) + Failed = true; + continue; + } + + // We're replacing code. + if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(), + Rewrite.getRangeSize(Hint.RemoveRange), + Hint.CodeToInsert)) + Failed = true; + } + + if (Failed) { + ++NumFailures; + Diag(Info.getLocation(), diag::note_fixit_failed); + return; + } + + Diag(Info.getLocation(), diag::note_fixit_applied); +} + +/// \brief Emit a diagnostic via the adapted diagnostic client. +void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) { + // When producing this diagnostic, we temporarily bypass ourselves, + // clear out any current diagnostic, and let the downstream client + // format the diagnostic. + Diags.setClient(Client); + Diags.Clear(); + Diags.Report(Loc, DiagID); + Diags.setClient(this); +} + +FixItPathRewriter::~FixItPathRewriter() {} |