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