//=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // 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(Context)->handleDiag(Diag); } SourceMgrAdapter::SourceMgrAdapter(SourceManager &SM, DiagnosticsEngine &Diagnostics, unsigned ErrorDiagID, unsigned WarningDiagID, unsigned NoteDiagID, OptionalFileEntryRef DefaultFile) : SrcMgr(SM), Diagnostics(Diagnostics), 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.getOrCreateFileID(*DefaultFile, SrcMgr::C_User); // Only do this once. DefaultFile = std::nullopt; } else { // Make a copy of the memory buffer. StringRef bufferName = Buffer->getBufferIdentifier(); auto bufferCopy = std::unique_ptr( 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_Remark: llvm_unreachable("remarks not implemented"); case llvm::SourceMgr::DK_Note: DiagID = NoteDiagID; break; } // Report the diagnostic. DiagnosticBuilder Builder = Diagnostics.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()); } } }