|  | //=== 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<SourceMgrAdapter *>(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>( | 
|  | 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()); | 
|  | } | 
|  | } | 
|  | } |