1 //=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the adapter that maps diagnostics from llvm::SourceMgr
10 // to Clang's SourceManager.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Basic/SourceMgrAdapter.h"
15 #include "clang/Basic/Diagnostic.h"
17 using namespace clang
;
19 void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic
&Diag
,
21 static_cast<SourceMgrAdapter
*>(Context
)->handleDiag(Diag
);
24 SourceMgrAdapter::SourceMgrAdapter(SourceManager
&SM
,
25 DiagnosticsEngine
&Diagnostics
,
26 unsigned ErrorDiagID
, unsigned WarningDiagID
,
28 OptionalFileEntryRef DefaultFile
)
29 : SrcMgr(SM
), Diagnostics(Diagnostics
), ErrorDiagID(ErrorDiagID
),
30 WarningDiagID(WarningDiagID
), NoteDiagID(NoteDiagID
),
31 DefaultFile(DefaultFile
) {}
33 SourceMgrAdapter::~SourceMgrAdapter() {}
35 SourceLocation
SourceMgrAdapter::mapLocation(const llvm::SourceMgr
&LLVMSrcMgr
,
37 // Map invalid locations.
39 return SourceLocation();
41 // Find the buffer containing the location.
42 unsigned BufferID
= LLVMSrcMgr
.FindBufferContainingLoc(Loc
);
44 return SourceLocation();
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()) {
52 // Map to the default file.
53 FileID
= SrcMgr
.getOrCreateFileID(*DefaultFile
, SrcMgr::C_User
);
56 DefaultFile
= std::nullopt
;
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(),
64 // Add this memory buffer to the Clang source manager.
65 FileID
= SrcMgr
.createFileID(std::move(bufferCopy
));
69 KnownBuffer
= FileIDMapping
70 .insert(std::make_pair(
71 std::make_pair(&LLVMSrcMgr
, BufferID
), FileID
))
75 // Translate the offset into the file.
76 unsigned Offset
= Loc
.getPointer() - Buffer
->getBufferStart();
77 return SrcMgr
.getLocForStartOfFile(KnownBuffer
->second
)
78 .getLocWithOffset(Offset
);
81 SourceRange
SourceMgrAdapter::mapRange(const llvm::SourceMgr
&LLVMSrcMgr
,
82 llvm::SMRange Range
) {
86 SourceLocation Start
= mapLocation(LLVMSrcMgr
, Range
.Start
);
87 SourceLocation End
= mapLocation(LLVMSrcMgr
, Range
.End
);
88 return SourceRange(Start
, End
);
91 void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic
&Diag
) {
94 if (auto *LLVMSrcMgr
= Diag
.getSourceMgr())
95 Loc
= mapLocation(*LLVMSrcMgr
, Diag
.getLoc());
97 // Extract the message.
98 StringRef Message
= Diag
.getMessage();
100 // Map the diagnostic kind.
102 switch (Diag
.getKind()) {
103 case llvm::SourceMgr::DK_Error
:
104 DiagID
= ErrorDiagID
;
107 case llvm::SourceMgr::DK_Warning
:
108 DiagID
= WarningDiagID
;
111 case llvm::SourceMgr::DK_Remark
:
112 llvm_unreachable("remarks not implemented");
114 case llvm::SourceMgr::DK_Note
:
119 // Report the diagnostic.
120 DiagnosticBuilder Builder
= Diagnostics
.Report(Loc
, DiagID
) << Message
;
122 if (auto *LLVMSrcMgr
= Diag
.getSourceMgr()) {
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
));
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());