1*5f757f3fSDimitry Andric //=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // This file implements the adapter that maps diagnostics from llvm::SourceMgr 10*5f757f3fSDimitry Andric // to Clang's SourceManager. 11*5f757f3fSDimitry Andric // 12*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 13*5f757f3fSDimitry Andric 14*5f757f3fSDimitry Andric #include "clang/Basic/SourceMgrAdapter.h" 15*5f757f3fSDimitry Andric #include "clang/Basic/Diagnostic.h" 16*5f757f3fSDimitry Andric 17*5f757f3fSDimitry Andric using namespace clang; 18*5f757f3fSDimitry Andric 19*5f757f3fSDimitry Andric void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &Diag, 20*5f757f3fSDimitry Andric void *Context) { 21*5f757f3fSDimitry Andric static_cast<SourceMgrAdapter *>(Context)->handleDiag(Diag); 22*5f757f3fSDimitry Andric } 23*5f757f3fSDimitry Andric 24*5f757f3fSDimitry Andric SourceMgrAdapter::SourceMgrAdapter(SourceManager &SM, 25*5f757f3fSDimitry Andric DiagnosticsEngine &Diagnostics, 26*5f757f3fSDimitry Andric unsigned ErrorDiagID, unsigned WarningDiagID, 27*5f757f3fSDimitry Andric unsigned NoteDiagID, 28*5f757f3fSDimitry Andric OptionalFileEntryRef DefaultFile) 29*5f757f3fSDimitry Andric : SrcMgr(SM), Diagnostics(Diagnostics), ErrorDiagID(ErrorDiagID), 30*5f757f3fSDimitry Andric WarningDiagID(WarningDiagID), NoteDiagID(NoteDiagID), 31*5f757f3fSDimitry Andric DefaultFile(DefaultFile) {} 32*5f757f3fSDimitry Andric 33*5f757f3fSDimitry Andric SourceMgrAdapter::~SourceMgrAdapter() {} 34*5f757f3fSDimitry Andric 35*5f757f3fSDimitry Andric SourceLocation SourceMgrAdapter::mapLocation(const llvm::SourceMgr &LLVMSrcMgr, 36*5f757f3fSDimitry Andric llvm::SMLoc Loc) { 37*5f757f3fSDimitry Andric // Map invalid locations. 38*5f757f3fSDimitry Andric if (!Loc.isValid()) 39*5f757f3fSDimitry Andric return SourceLocation(); 40*5f757f3fSDimitry Andric 41*5f757f3fSDimitry Andric // Find the buffer containing the location. 42*5f757f3fSDimitry Andric unsigned BufferID = LLVMSrcMgr.FindBufferContainingLoc(Loc); 43*5f757f3fSDimitry Andric if (!BufferID) 44*5f757f3fSDimitry Andric return SourceLocation(); 45*5f757f3fSDimitry Andric 46*5f757f3fSDimitry Andric // If we haven't seen this buffer before, copy it over. 47*5f757f3fSDimitry Andric auto Buffer = LLVMSrcMgr.getMemoryBuffer(BufferID); 48*5f757f3fSDimitry Andric auto KnownBuffer = FileIDMapping.find(std::make_pair(&LLVMSrcMgr, BufferID)); 49*5f757f3fSDimitry Andric if (KnownBuffer == FileIDMapping.end()) { 50*5f757f3fSDimitry Andric FileID FileID; 51*5f757f3fSDimitry Andric if (DefaultFile) { 52*5f757f3fSDimitry Andric // Map to the default file. 53*5f757f3fSDimitry Andric FileID = SrcMgr.getOrCreateFileID(*DefaultFile, SrcMgr::C_User); 54*5f757f3fSDimitry Andric 55*5f757f3fSDimitry Andric // Only do this once. 56*5f757f3fSDimitry Andric DefaultFile = std::nullopt; 57*5f757f3fSDimitry Andric } else { 58*5f757f3fSDimitry Andric // Make a copy of the memory buffer. 59*5f757f3fSDimitry Andric StringRef bufferName = Buffer->getBufferIdentifier(); 60*5f757f3fSDimitry Andric auto bufferCopy = std::unique_ptr<llvm::MemoryBuffer>( 61*5f757f3fSDimitry Andric llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), 62*5f757f3fSDimitry Andric bufferName)); 63*5f757f3fSDimitry Andric 64*5f757f3fSDimitry Andric // Add this memory buffer to the Clang source manager. 65*5f757f3fSDimitry Andric FileID = SrcMgr.createFileID(std::move(bufferCopy)); 66*5f757f3fSDimitry Andric } 67*5f757f3fSDimitry Andric 68*5f757f3fSDimitry Andric // Save the mapping. 69*5f757f3fSDimitry Andric KnownBuffer = FileIDMapping 70*5f757f3fSDimitry Andric .insert(std::make_pair( 71*5f757f3fSDimitry Andric std::make_pair(&LLVMSrcMgr, BufferID), FileID)) 72*5f757f3fSDimitry Andric .first; 73*5f757f3fSDimitry Andric } 74*5f757f3fSDimitry Andric 75*5f757f3fSDimitry Andric // Translate the offset into the file. 76*5f757f3fSDimitry Andric unsigned Offset = Loc.getPointer() - Buffer->getBufferStart(); 77*5f757f3fSDimitry Andric return SrcMgr.getLocForStartOfFile(KnownBuffer->second) 78*5f757f3fSDimitry Andric .getLocWithOffset(Offset); 79*5f757f3fSDimitry Andric } 80*5f757f3fSDimitry Andric 81*5f757f3fSDimitry Andric SourceRange SourceMgrAdapter::mapRange(const llvm::SourceMgr &LLVMSrcMgr, 82*5f757f3fSDimitry Andric llvm::SMRange Range) { 83*5f757f3fSDimitry Andric if (!Range.isValid()) 84*5f757f3fSDimitry Andric return SourceRange(); 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric SourceLocation Start = mapLocation(LLVMSrcMgr, Range.Start); 87*5f757f3fSDimitry Andric SourceLocation End = mapLocation(LLVMSrcMgr, Range.End); 88*5f757f3fSDimitry Andric return SourceRange(Start, End); 89*5f757f3fSDimitry Andric } 90*5f757f3fSDimitry Andric 91*5f757f3fSDimitry Andric void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &Diag) { 92*5f757f3fSDimitry Andric // Map the location. 93*5f757f3fSDimitry Andric SourceLocation Loc; 94*5f757f3fSDimitry Andric if (auto *LLVMSrcMgr = Diag.getSourceMgr()) 95*5f757f3fSDimitry Andric Loc = mapLocation(*LLVMSrcMgr, Diag.getLoc()); 96*5f757f3fSDimitry Andric 97*5f757f3fSDimitry Andric // Extract the message. 98*5f757f3fSDimitry Andric StringRef Message = Diag.getMessage(); 99*5f757f3fSDimitry Andric 100*5f757f3fSDimitry Andric // Map the diagnostic kind. 101*5f757f3fSDimitry Andric unsigned DiagID; 102*5f757f3fSDimitry Andric switch (Diag.getKind()) { 103*5f757f3fSDimitry Andric case llvm::SourceMgr::DK_Error: 104*5f757f3fSDimitry Andric DiagID = ErrorDiagID; 105*5f757f3fSDimitry Andric break; 106*5f757f3fSDimitry Andric 107*5f757f3fSDimitry Andric case llvm::SourceMgr::DK_Warning: 108*5f757f3fSDimitry Andric DiagID = WarningDiagID; 109*5f757f3fSDimitry Andric break; 110*5f757f3fSDimitry Andric 111*5f757f3fSDimitry Andric case llvm::SourceMgr::DK_Remark: 112*5f757f3fSDimitry Andric llvm_unreachable("remarks not implemented"); 113*5f757f3fSDimitry Andric 114*5f757f3fSDimitry Andric case llvm::SourceMgr::DK_Note: 115*5f757f3fSDimitry Andric DiagID = NoteDiagID; 116*5f757f3fSDimitry Andric break; 117*5f757f3fSDimitry Andric } 118*5f757f3fSDimitry Andric 119*5f757f3fSDimitry Andric // Report the diagnostic. 120*5f757f3fSDimitry Andric DiagnosticBuilder Builder = Diagnostics.Report(Loc, DiagID) << Message; 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric if (auto *LLVMSrcMgr = Diag.getSourceMgr()) { 123*5f757f3fSDimitry Andric // Translate ranges. 124*5f757f3fSDimitry Andric SourceLocation StartOfLine = Loc.getLocWithOffset(-Diag.getColumnNo()); 125*5f757f3fSDimitry Andric for (auto Range : Diag.getRanges()) { 126*5f757f3fSDimitry Andric Builder << SourceRange(StartOfLine.getLocWithOffset(Range.first), 127*5f757f3fSDimitry Andric StartOfLine.getLocWithOffset(Range.second)); 128*5f757f3fSDimitry Andric } 129*5f757f3fSDimitry Andric 130*5f757f3fSDimitry Andric // Translate Fix-Its. 131*5f757f3fSDimitry Andric for (const llvm::SMFixIt &FixIt : Diag.getFixIts()) { 132*5f757f3fSDimitry Andric CharSourceRange Range(mapRange(*LLVMSrcMgr, FixIt.getRange()), false); 133*5f757f3fSDimitry Andric Builder << FixItHint::CreateReplacement(Range, FixIt.getText()); 134*5f757f3fSDimitry Andric } 135*5f757f3fSDimitry Andric } 136*5f757f3fSDimitry Andric } 137