137 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the adapter that maps diagnostics from llvm::SourceMgr10// to Clang's SourceManager.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Basic/SourceMgrAdapter.h"15#include "clang/Basic/Diagnostic.h"16 17using namespace clang;18 19void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &Diag,20 void *Context) {21 static_cast<SourceMgrAdapter *>(Context)->handleDiag(Diag);22}23 24SourceMgrAdapter::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 33SourceMgrAdapter::~SourceMgrAdapter() {}34 35SourceLocation 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 = FileIDMapping70 .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 81SourceRange 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 91void 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