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