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
handleDiag(const llvm::SMDiagnostic & Diag,void * Context)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
SourceMgrAdapter(SourceManager & SM,DiagnosticsEngine & Diagnostics,unsigned ErrorDiagID,unsigned WarningDiagID,unsigned NoteDiagID,OptionalFileEntryRef DefaultFile)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
~SourceMgrAdapter()33*5f757f3fSDimitry Andric SourceMgrAdapter::~SourceMgrAdapter() {}
34*5f757f3fSDimitry Andric
mapLocation(const llvm::SourceMgr & LLVMSrcMgr,llvm::SMLoc Loc)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
mapRange(const llvm::SourceMgr & LLVMSrcMgr,llvm::SMRange Range)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
handleDiag(const llvm::SMDiagnostic & Diag)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