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
17using namespace clang;
18
19void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &Diag,
20 void *Context) {
21 static_cast<SourceMgrAdapter *>(Context)->handleDiag(Diag);
22}
23
24SourceMgrAdapter::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
33SourceMgrAdapter::~SourceMgrAdapter() {}
34
35SourceLocation 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
81SourceRange 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
91void 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