xref: /freebsd/contrib/llvm-project/clang/lib/Basic/SourceMgrAdapter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
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 
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 
33*5f757f3fSDimitry Andric SourceMgrAdapter::~SourceMgrAdapter() {}
34*5f757f3fSDimitry Andric 
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 
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 
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