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