blob: 1d52a2438594b7c822c01796682d3a7efb6289e1 [file] [log] [blame]
//=== SourceMgrAdapter.cpp - SourceMgr to SourceManager Adapter -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the adapter that maps diagnostics from llvm::SourceMgr
// to Clang's SourceManager.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/SourceMgrAdapter.h"
#include "clang/Basic/Diagnostic.h"
using namespace clang;
void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag,
void *context) {
static_cast<SourceMgrAdapter *>(context)->handleDiag(diag);
}
SourceMgrAdapter::SourceMgrAdapter(SourceManager &srcMgr,
DiagnosticsEngine &diag,
unsigned errorDiagID,
unsigned warningDiagID,
unsigned noteDiagID,
const FileEntry *defaultFile)
: SrcMgr(srcMgr), Diag(diag), ErrorDiagID(errorDiagID),
WarningDiagID(warningDiagID), NoteDiagID(noteDiagID),
DefaultFile(defaultFile) { }
SourceMgrAdapter::~SourceMgrAdapter() { }
SourceLocation SourceMgrAdapter::mapLocation(const llvm::SourceMgr &llvmSrcMgr,
llvm::SMLoc loc) {
// Map invalid locations.
if (!loc.isValid())
return SourceLocation();
// Find the buffer containing the location.
unsigned bufferID = llvmSrcMgr.FindBufferContainingLoc(loc);
if (!bufferID)
return SourceLocation();
// If we haven't seen this buffer before, copy it over.
auto buffer = llvmSrcMgr.getMemoryBuffer(bufferID);
auto knownBuffer = FileIDMapping.find(std::make_pair(&llvmSrcMgr, bufferID));
if (knownBuffer == FileIDMapping.end()) {
FileID fileID;
if (DefaultFile) {
// Map to the default file.
fileID = SrcMgr.createFileID(DefaultFile, SourceLocation(),
SrcMgr::C_User);
// Only do this once.
DefaultFile = nullptr;
} else {
// Make a copy of the memory buffer.
StringRef bufferName = buffer->getBufferIdentifier();
auto bufferCopy
= std::unique_ptr<llvm::MemoryBuffer>(
llvm::MemoryBuffer::getMemBufferCopy(buffer->getBuffer(),
bufferName));
// Add this memory buffer to the Clang source manager.
fileID = SrcMgr.createFileID(std::move(bufferCopy));
}
// Save the mapping.
knownBuffer = FileIDMapping.insert(
std::make_pair(std::make_pair(&llvmSrcMgr, bufferID),
fileID)).first;
}
// Translate the offset into the file.
unsigned offset = loc.getPointer() - buffer->getBufferStart();
return SrcMgr.getLocForStartOfFile(knownBuffer->second)
.getLocWithOffset(offset);
}
SourceRange SourceMgrAdapter::mapRange(const llvm::SourceMgr &llvmSrcMgr,
llvm::SMRange range) {
if (!range.isValid())
return SourceRange();
SourceLocation start = mapLocation(llvmSrcMgr, range.Start);
SourceLocation end = mapLocation(llvmSrcMgr, range.End);
return SourceRange(start, end);
}
void SourceMgrAdapter::handleDiag(const llvm::SMDiagnostic &diag) {
// Map the location.
SourceLocation loc;
if (auto *llvmSrcMgr = diag.getSourceMgr())
loc = mapLocation(*llvmSrcMgr, diag.getLoc());
// Extract the message.
StringRef message = diag.getMessage();
// Map the diagnostic kind.
unsigned diagID;
switch (diag.getKind()) {
case llvm::SourceMgr::DK_Error:
diagID = ErrorDiagID;
break;
case llvm::SourceMgr::DK_Warning:
diagID = WarningDiagID;
break;
case llvm::SourceMgr::DK_Note:
diagID = NoteDiagID;
break;
}
// Report the diagnostic.
DiagnosticBuilder builder = Diag.Report(loc, diagID) << message;
if (auto *llvmSrcMgr = diag.getSourceMgr()) {
// Translate ranges.
SourceLocation startOfLine = loc.getLocWithOffset(-diag.getColumnNo());
for (auto range : diag.getRanges()) {
builder << SourceRange(startOfLine.getLocWithOffset(range.first),
startOfLine.getLocWithOffset(range.second));
}
// Translate Fix-Its.
for (const llvm::SMFixIt &fixIt : diag.getFixIts()) {
CharSourceRange range(mapRange(*llvmSrcMgr, fixIt.getRange()), false);
builder << FixItHint::CreateReplacement(range, fixIt.getText());
}
}
}