xref: /llvm-project/clang/lib/Basic/SourceMgrAdapter.cpp (revision f049395fc8d6d8bbbc711c7a2ce293210c580240)
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