| //=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the adapter that maps diagnostics from llvm::SourceMgr |
| // to Clang's SourceManager. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Basic/SourceMgrAdapter.h" |
| #include "clang/Basic/Diagnostic.h" |
| |
| using namespace clang; |
| |
| void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag, |
| void *context) { |
| static_cast<SourceMgrAdapter *>(context)->handleDiag(diag); |
| } |
| |
| SourceMgrAdapter::SourceMgrAdapter(SourceManager &srcMgr, |
| DiagnosticsEngine &diag, |
| unsigned errorDiagID, |
| unsigned warningDiagID, |
| unsigned noteDiagID, |
| const FileEntry *defaultFile) |
| : SrcMgr(srcMgr), Diag(diag), ErrorDiagID(errorDiagID), |
| WarningDiagID(warningDiagID), NoteDiagID(noteDiagID), |
| DefaultFile(defaultFile) { } |
| |
| SourceMgrAdapter::~SourceMgrAdapter() { } |
| |
| SourceLocation SourceMgrAdapter::mapLocation(const llvm::SourceMgr &llvmSrcMgr, |
| llvm::SMLoc loc) { |
| // Map invalid locations. |
| if (!loc.isValid()) |
| return SourceLocation(); |
| |
| // Find the buffer containing the location. |
| unsigned bufferID = llvmSrcMgr.FindBufferContainingLoc(loc); |
| if (!bufferID) |
| return SourceLocation(); |
| |
| |
| // If we haven't seen this buffer before, copy it over. |
| auto buffer = llvmSrcMgr.getMemoryBuffer(bufferID); |
| auto knownBuffer = FileIDMapping.find(std::make_pair(&llvmSrcMgr, bufferID)); |
| if (knownBuffer == FileIDMapping.end()) { |
| FileID fileID; |
| if (DefaultFile) { |
| // Map to the default file. |
| fileID = SrcMgr.createFileID(DefaultFile, SourceLocation(), |
| SrcMgr::C_User); |
| |
| // Only do this once. |
| DefaultFile = nullptr; |
| } else { |
| // Make a copy of the memory buffer. |
| StringRef bufferName = buffer->getBufferIdentifier(); |
| auto bufferCopy |
| = std::unique_ptr<llvm::MemoryBuffer>( |
| llvm::MemoryBuffer::getMemBufferCopy(buffer->getBuffer(), |
| bufferName)); |
| |
| // Add this memory buffer to the Clang source manager. |
| fileID = SrcMgr.createFileID(std::move(bufferCopy)); |
| } |
| |
| // Save the mapping. |
| knownBuffer = FileIDMapping.insert( |
| std::make_pair(std::make_pair(&llvmSrcMgr, bufferID), |
| fileID)).first; |
| } |
| |
| // Translate the offset into the file. |
| unsigned offset = loc.getPointer() - buffer->getBufferStart(); |
| return SrcMgr.getLocForStartOfFile(knownBuffer->second) |
| .getLocWithOffset(offset); |
| } |
| |
| SourceRange SourceMgrAdapter::mapRange(const llvm::SourceMgr &llvmSrcMgr, |
| llvm::SMRange range) { |
| if (!range.isValid()) |
| return SourceRange(); |
| |
| SourceLocation start = mapLocation(llvmSrcMgr, range.Start); |
| SourceLocation end = mapLocation(llvmSrcMgr, range.End); |
| return SourceRange(start, end); |
| } |
| |
| void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag) { |
| // Map the location. |
| SourceLocation loc; |
| if (auto *llvmSrcMgr = diag.getSourceMgr()) |
| loc = mapLocation(*llvmSrcMgr, diag.getLoc()); |
| |
| // Extract the message. |
| StringRef message = diag.getMessage(); |
| |
| // Map the diagnostic kind. |
| unsigned diagID; |
| switch (diag.getKind()) { |
| case llvm::SourceMgr::DK_Error: |
| diagID = ErrorDiagID; |
| break; |
| |
| case llvm::SourceMgr::DK_Warning: |
| diagID = WarningDiagID; |
| break; |
| |
| case llvm::SourceMgr::DK_Note: |
| diagID = NoteDiagID; |
| break; |
| } |
| |
| // Report the diagnostic. |
| DiagnosticBuilder builder = Diag.Report(loc, diagID) << message; |
| |
| if (auto *llvmSrcMgr = diag.getSourceMgr()) { |
| // Translate ranges. |
| SourceLocation startOfLine = loc.getLocWithOffset(-diag.getColumnNo()); |
| for (auto range : diag.getRanges()) { |
| builder << SourceRange(startOfLine.getLocWithOffset(range.first), |
| startOfLine.getLocWithOffset(range.second)); |
| } |
| |
| // Translate Fix-Its. |
| for (const llvm::SMFixIt &fixIt : diag.getFixIts()) { |
| CharSourceRange range(mapRange(*llvmSrcMgr, fixIt.getRange()), false); |
| builder << FixItHint::CreateReplacement(range, fixIt.getText()); |
| } |
| } |
| } |