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