24#include <clang/Basic/SourceLocation.h>
25#include <clang/Basic/SourceManager.h>
26#include <clang/Lex/Lexer.h>
27#include <llvm/ADT/DenseMap.h>
42using LocCache = llvm::DenseMap<uintptr_t, CachedLoc>;
43using FileEntryCache = llvm::DenseMap<const clang::FileEntry *, FileID>;
44using EndTokenCache = llvm::DenseMap<uintptr_t, clang::SourceLocation>;
47thread_local LocCache locCache;
48thread_local FileEntryCache fileEntryCache;
49thread_local EndTokenCache endTokenCache;
51uintptr_t toKey(
const clang::SourceLocation &loc) {
52 return static_cast<uintptr_t
>(loc.getRawEncoding());
55clang::SourceLocation resolveFileLoc(
const clang::SourceLocation &loc,
56 const clang::SourceManager &sm) {
57 return loc.isInvalid() ? loc : sm.getFileLoc(loc);
61SourceLocation::SourceLocation(
FileID fileId,
unsigned line,
unsigned column)
62 : fileId_(fileId), line_(line), column_(column) {}
65 const clang::SourceManager &sm,
67 if (loc.isInvalid()) {
72 clang::SourceLocation fileLoc = resolveFileLoc(loc, sm);
73 if (fileLoc.isInvalid()) {
77 const uintptr_t key = toKey(fileLoc);
78 if (
auto it = locCache.find(key); it != locCache.end()) {
79 return SourceLocation(it->second.fileId, it->second.line, it->second.column);
83 auto decomposed = sm.getDecomposedSpellingLoc(fileLoc);
84 clang::FileID fid = decomposed.first;
85 unsigned offset = decomposed.second;
91 auto fileEntry = sm.getFileEntryRefForID(fid);
97 const clang::FileEntry *fe = &fileEntry->getFileEntry();
98 auto feIt = fileEntryCache.find(fe);
100 if (feIt != fileEntryCache.end()) {
101 fileId = feIt->second;
104 const char *filename = fileEntry->getName().data();
110 fileEntryCache.try_emplace(fe, fileId);
114 unsigned line = sm.getLineNumber(fid, offset);
115 unsigned column = sm.getColumnNumber(fid, offset);
117 locCache.try_emplace(key, CachedLoc{fileId, offset, line, column});
119 return SourceLocation(fileId, line, column);
123 : begin_(begin), end_(end) {}
126 const clang::SourceManager &sm,
128 if (range.isInvalid()) {
130 return SourceRange(invalid, invalid);
134 clang::SourceLocation startLoc = resolveFileLoc(range.getBegin(), sm);
135 clang::SourceLocation lastTokenLoc = resolveFileLoc(range.getEnd(), sm);
138 clang::SourceLocation endLoc;
142 bool canUseGetLocForEndOfToken =
false;
143 if (lastTokenLoc.isValid() && lastTokenLoc.isFileID()) {
144 clang::FileID fid = sm.getFileID(lastTokenLoc);
146 auto buffer = sm.getBufferOrNone(fid);
148 unsigned offset = sm.getFileOffset(lastTokenLoc);
151 if (offset < buffer->getBufferSize()) {
152 canUseGetLocForEndOfToken =
true;
158 if (canUseGetLocForEndOfToken) {
159 if (
auto it = endTokenCache.find(toKey(lastTokenLoc));
160 it != endTokenCache.end()) {
163 clang::LangOptions langOpts;
164 endLoc = clang::Lexer::getLocForEndOfToken(lastTokenLoc, 0, sm, langOpts);
165 endTokenCache.try_emplace(toKey(lastTokenLoc), endLoc);
170 if (endLoc.isInvalid()) {
171 endLoc = lastTokenLoc;
177 return SourceRange(begin, end);
180static void resetAllCaches() {
182 fileEntryCache.clear();
183 endTokenCache.clear();
std::size_t FileID
Type-safe identifier for registered files. 0 is reserved for invalid.
Source code location representation.
Centralized file registry providing path-to-FileID mapping.
static constexpr FileID InvalidFileID
Reserved invalid FileID.
FileID registerFile(std::string_view filePath)
Register a file and return its FileID.
std::optional< FileID > tryGetFileId(std::string_view filePath) const
Look up FileID for a path without registering.
Represents a specific position in source code.
static void resetCache()
Reset internal caches (per extraction run).
static SourceLocation fromClang(const clang::SourceLocation &loc, const clang::SourceManager &sm, FileManager &fileMgr)
Create SourceLocation from Clang's SourceLocation.
static SourceRange fromClang(const clang::SourceRange &range, const clang::SourceManager &sm, FileManager &fileMgr)
Create SourceRange from Clang's SourceRange.