//===--- PrintingDiagnosticConsumer.cpp - Print Text Diagnostics ----------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the PrintingDiagnosticConsumer class. // //===----------------------------------------------------------------------===// #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" using namespace swift; namespace { class ColoredStream : public raw_ostream { raw_ostream &Underlying; public: explicit ColoredStream(raw_ostream &underlying) : Underlying(underlying) {} ~ColoredStream() { flush(); } raw_ostream &changeColor(Colors color, bool bold = false, bool bg = false) override { Underlying.changeColor(color, bold, bg); return *this; } raw_ostream &resetColor() override { Underlying.resetColor(); return *this; } raw_ostream &reverseColor() override { Underlying.reverseColor(); return *this; } bool has_colors() const override { return true; } void write_impl(const char *ptr, size_t size) override { Underlying.write(ptr, size); } uint64_t current_pos() const override { return Underlying.tell() - GetNumBytesInBuffer(); } size_t preferred_buffer_size() const override { return 0; } }; } // end anonymous namespace llvm::SMLoc DiagnosticConsumer::getRawLoc(SourceLoc loc) { return loc.Value; } void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind, StringRef Text, const DiagnosticInfo &Info) { // Determine what kind of diagnostic we're emitting. llvm::SourceMgr::DiagKind SMKind; switch (Kind) { case DiagnosticKind::Error: SMKind = llvm::SourceMgr::DK_Error; break; case DiagnosticKind::Warning: SMKind = llvm::SourceMgr::DK_Warning; break; case DiagnosticKind::Note: SMKind = llvm::SourceMgr::DK_Note; break; } if (Kind == DiagnosticKind::Error) { DidErrorOccur = true; } // Translate ranges. SmallVector Ranges; for (auto R : Info.Ranges) Ranges.push_back(getRawRange(SM, R)); // Translate fix-its. SmallVector FixIts; for (DiagnosticInfo::FixIt F : Info.FixIts) FixIts.push_back(getRawFixIt(SM, F)); // Display the diagnostic. ColoredStream coloredErrs{Stream}; raw_ostream &out = ForceColors ? coloredErrs : Stream; const llvm::SourceMgr &rawSM = SM.getLLVMSourceMgr(); auto Msg = SM.GetMessage(Loc, SMKind, Text, Ranges, FixIts); rawSM.PrintMessage(out, Msg); } llvm::SMDiagnostic SourceManager::GetMessage(SourceLoc Loc, llvm::SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef Ranges, ArrayRef FixIts) const { // First thing to do: find the current buffer containing the specified // location to pull out the source line. SmallVector, 4> ColRanges; std::pair LineAndCol; const char *BufferID = ""; std::string LineStr; if (Loc.isValid()) { BufferID = getBufferIdentifierForLoc(Loc); auto CurMB = LLVMSourceMgr.getMemoryBuffer(findBufferContainingLoc(Loc)); // Scan backward to find the start of the line. const char *LineStart = Loc.Value.getPointer(); const char *BufStart = CurMB->getBufferStart(); while (LineStart != BufStart && LineStart[-1] != '\n' && LineStart[-1] != '\r') --LineStart; // Get the end of the line. const char *LineEnd = Loc.Value.getPointer(); const char *BufEnd = CurMB->getBufferEnd(); while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r') ++LineEnd; LineStr = std::string(LineStart, LineEnd); // Convert any ranges to column ranges that only intersect the line of the // location. for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { llvm::SMRange R = Ranges[i]; if (!R.isValid()) continue; // If the line doesn't contain any part of the range, then ignore it. if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) continue; // Ignore pieces of the range that go onto other lines. if (R.Start.getPointer() < LineStart) R.Start = llvm::SMLoc::getFromPointer(LineStart); if (R.End.getPointer() > LineEnd) R.End = llvm::SMLoc::getFromPointer(LineEnd); // Translate from SMLoc ranges to column ranges. // FIXME: Handle multibyte characters. ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, R.End.getPointer()-LineStart)); } LineAndCol = getLineAndColumn(Loc); } return llvm::SMDiagnostic(LLVMSourceMgr, Loc.Value, BufferID, LineAndCol.first, LineAndCol.second-1, Kind, Msg.str(), LineStr, ColRanges, FixIts); }