11 #include "../lsp-server-support/CompilationDatabase.h" 12 #include "../lsp-server-support/Logging.h" 13 #include "../lsp-server-support/Protocol.h" 14 #include "../lsp-server-support/SourceMgrUtils.h" 16 #include "llvm/ADT/IntervalMap.h" 17 #include "llvm/ADT/PointerUnion.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "llvm/ADT/StringSet.h" 20 #include "llvm/ADT/TypeSwitch.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/TableGen/Parser.h" 24 #include "llvm/TableGen/Record.h" 32 int bufferId = mgr.FindBufferContainingLoc(loc);
33 if (bufferId == 0 || bufferId == static_cast<int>(mgr.getMainFileID()))
36 mgr.getBufferInfo(bufferId).Buffer->getBufferIdentifier());
56 static Optional<lsp::Diagnostic>
59 auto *sourceMgr =
const_cast<llvm::SourceMgr *
>(diag.getSourceMgr());
60 if (!sourceMgr || !diag.getLoc().isValid())
64 lspDiag.
source =
"tablegen";
76 switch (diag.getKind()) {
77 case llvm::SourceMgr::DK_Warning:
80 case llvm::SourceMgr::DK_Error:
83 case llvm::SourceMgr::DK_Note:
87 case llvm::SourceMgr::DK_Remark:
91 lspDiag.
message = diag.getMessage().str();
104 struct TableGenIndexSymbol {
105 TableGenIndexSymbol(
const llvm::Record *record)
106 : definition(record),
108 TableGenIndexSymbol(
const llvm::RecordVal *
value)
125 class TableGenIndex {
127 TableGenIndex() : intervalMap(allocator) {}
130 void initialize(
const llvm::RecordKeeper &records);
135 const TableGenIndexSymbol *lookup(SMLoc loc,
136 SMRange *overlappedRange =
nullptr)
const;
141 using MapT = llvm::IntervalMap<
142 const char *,
const TableGenIndexSymbol *,
143 llvm::IntervalMapImpl::NodeSizer<
const char *,
144 const TableGenIndexSymbol *>::LeafSize,
145 llvm::IntervalMapHalfOpenInfo<const char *>>;
148 MapT::Allocator allocator;
159 void TableGenIndex::initialize(
const llvm::RecordKeeper &records) {
160 auto getOrInsertDef = [&](
const auto *def) -> TableGenIndexSymbol * {
161 auto it = defToSymbol.try_emplace(def,
nullptr);
163 it.first->second = std::make_unique<TableGenIndexSymbol>(def);
164 return &*it.first->second;
166 auto insertRef = [&](TableGenIndexSymbol *sym, SMRange refLoc,
167 bool isDef =
false) {
168 const char *startLoc = refLoc.Start.getPointer();
169 const char *endLoc = refLoc.End.getPointer();
173 if (startLoc == endLoc) {
175 startLoc = refLoc.Start.getPointer();
176 endLoc = refLoc.End.getPointer();
180 if (startLoc == endLoc)
188 if (!intervalMap.overlaps(startLoc, endLoc))
189 intervalMap.insert(startLoc, endLoc, sym);
192 sym->references.push_back(refLoc);
195 llvm::make_pointee_range(llvm::make_second_range(records.getClasses()));
197 llvm::make_pointee_range(llvm::make_second_range(records.getDefs()));
198 for (
const llvm::Record &def : llvm::concat<llvm::Record>(classes, defs)) {
199 auto *sym = getOrInsertDef(&def);
200 insertRef(sym, sym->defLoc,
true);
203 for (SMLoc loc : def.getLoc().drop_front())
207 for (
auto &it : def.getSuperClasses())
208 insertRef(getOrInsertDef(it.first),
212 for (
const llvm::RecordVal &
value : def.getValues()) {
213 auto *sym = getOrInsertDef(&
value);
214 insertRef(sym, sym->defLoc,
true);
219 const TableGenIndexSymbol *
220 TableGenIndex::lookup(SMLoc loc, SMRange *overlappedRange)
const {
221 auto it = intervalMap.find(loc.getPointer());
222 if (!it.valid() || loc.getPointer() < it.start())
225 if (overlappedRange) {
226 *overlappedRange = SMRange(SMLoc::getFromPointer(it.start()),
227 SMLoc::getFromPointer(it.stop()));
238 class TableGenTextFile {
242 const std::vector<std::string> &extraIncludeDirs,
243 std::vector<lsp::Diagnostic> &diagnostics);
246 int64_t getVersion()
const {
return version; }
252 std::vector<lsp::Diagnostic> &diagnostics);
259 std::vector<lsp::Location> &locations);
261 std::vector<lsp::Location> &references);
268 std::vector<lsp::DocumentLink> &links);
280 std::vector<lsp::Diagnostic> &diagnostics);
283 std::string contents;
289 std::vector<std::string> includeDirs;
292 llvm::SourceMgr sourceMgr;
295 std::unique_ptr<llvm::RecordKeeper> recordKeeper;
305 TableGenTextFile::TableGenTextFile(
307 const std::vector<std::string> &extraIncludeDirs,
308 std::vector<lsp::Diagnostic> &diagnostics)
309 : contents(fileContents.str()), version(version) {
312 llvm::sys::path::remove_filename(uriDirectory);
313 includeDirs.push_back(uriDirectory.str().str());
314 includeDirs.insert(includeDirs.end(), extraIncludeDirs.begin(),
315 extraIncludeDirs.end());
318 initialize(uri, version, diagnostics);
322 TableGenTextFile::update(
const lsp::URIForFile &uri, int64_t newVersion,
324 std::vector<lsp::Diagnostic> &diagnostics) {
331 initialize(uri, newVersion, diagnostics);
337 std::vector<lsp::Diagnostic> &diagnostics) {
338 version = newVersion;
339 sourceMgr = llvm::SourceMgr();
340 recordKeeper = std::make_unique<llvm::RecordKeeper>();
343 auto memBuffer = llvm::MemoryBuffer::getMemBuffer(contents, uri.
file());
348 sourceMgr.setIncludeDirs(includeDirs);
349 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
353 struct DiagHandlerContext {
354 std::vector<lsp::Diagnostic> &diagnostics;
356 } handlerContext{diagnostics, uri};
359 sourceMgr.setDiagHandler(
360 [](
const llvm::SMDiagnostic &
diag,
void *rawHandlerContext) {
361 auto *ctx =
reinterpret_cast<DiagHandlerContext *
>(rawHandlerContext);
363 ctx->diagnostics.push_back(*lspDiag);
366 bool failedToParse = llvm::TableGenParseFile(sourceMgr, *recordKeeper);
374 index.initialize(*recordKeeper);
383 std::vector<lsp::Location> &locations) {
385 const TableGenIndexSymbol *symbol = index.lookup(posLoc);
392 void TableGenTextFile::findReferencesOf(
394 std::vector<lsp::Location> &references) {
396 const TableGenIndexSymbol *symbol = index.lookup(posLoc);
401 for (SMRange refLoc : symbol->references)
410 std::vector<lsp::DocumentLink> &links) {
412 links.emplace_back(include.range, include.uri);
424 if (include.range.contains(hoverPos))
425 return include.buildHover();
435 : options(options), compilationDatabase(options.compilationDatabases) {}
445 llvm::StringMap<std::unique_ptr<TableGenTextFile>>
files;
453 :
impl(std::make_unique<
Impl>(options)) {}
458 std::vector<Diagnostic> &diagnostics) {
460 std::vector<std::string> additionalIncludeDirs =
impl->options.extraDirs;
461 const auto &fileInfo =
impl->compilationDatabase.getFileInfo(uri.
file());
462 llvm::append_range(additionalIncludeDirs, fileInfo.includeDirs);
464 impl->files[uri.
file()] = std::make_unique<TableGenTextFile>(
465 uri, contents, version, additionalIncludeDirs, diagnostics);
470 int64_t version, std::vector<Diagnostic> &diagnostics) {
472 auto it =
impl->files.find(uri.
file());
473 if (it ==
impl->files.end())
478 if (
failed(it->second->update(uri, version, changes, diagnostics)))
479 impl->files.erase(it);
483 auto it =
impl->files.find(uri.
file());
484 if (it ==
impl->files.end())
487 int64_t version = it->second->getVersion();
488 impl->files.erase(it);
494 std::vector<Location> &locations) {
495 auto fileIt =
impl->files.find(uri.
file());
496 if (fileIt !=
impl->files.end())
497 fileIt->second->getLocationsOf(uri, defPos, locations);
502 std::vector<Location> &references) {
503 auto fileIt =
impl->files.find(uri.
file());
504 if (fileIt !=
impl->files.end())
505 fileIt->second->findReferencesOf(uri, pos, references);
509 const URIForFile &uri, std::vector<DocumentLink> &documentLinks) {
510 auto fileIt =
impl->files.find(uri.
file());
511 if (fileIt !=
impl->files.end())
512 return fileIt->second->getDocumentLinks(uri, documentLinks);
517 auto fileIt =
impl->files.find(uri.
file());
518 if (fileIt !=
impl->files.end())
519 return fileIt->second->findHover(uri, hoverPos);
StringRef file() const
Returns the absolute path to the file.
Include the generated interface declarations.
Impl(const Options &options)
Documents should not be synced at all.
static std::string diag(llvm::Value &v)
lsp::CompilationDatabase compilationDatabase
The compilation database containing additional information for files passed to the server...
static void error(const char *fmt, Ts &&...vals)
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
DiagnosticSeverity severity
The diagnostic's severity.
Optional< std::string > category
The diagnostic's category.
URI in "file" scheme for a file.
static constexpr const bool value
static Optional< lsp::Diagnostic > getLspDiagnoticFromDiag(const llvm::SMDiagnostic &diag, const lsp::URIForFile &uri)
Convert the given TableGen diagnostic to the LSP form.
void updateDocument(const URIForFile &uri, ArrayRef< TextDocumentContentChangeEvent > changes, int64_t version, std::vector< Diagnostic > &diagnostics)
Update the document, with the provided version, at the given URI.
This class represents a single include within a root file.
This class contains a collection of compilation information for files provided to the language server...
LogicalResult applyTo(std::string &contents) const
Try to apply this change to the given contents string.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
std::string source
A human-readable string describing the source of this diagnostic, e.g.
void findReferencesOf(const URIForFile &uri, const Position &pos, std::vector< Location > &references)
Find all references of the object pointed at by the given position.
This class represents an efficient way to signal success or failure.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
void getDocumentLinks(const URIForFile &uri, std::vector< DocumentLink > &documentLinks)
Return the document links referenced by the given file.
const Options & options
TableGen LSP options.
Optional< int64_t > removeDocument(const URIForFile &uri)
Remove the document with the given uri.
TableGenServer(const Options &options)
SMRange convertTokenLocToRange(SMLoc loc)
Returns the range of a lexical token given a SMLoc corresponding to the start of an token location...
llvm::StringMap< std::unique_ptr< TableGenTextFile > > files
The files held by the server, mapped by their URI file name.
std::string message
The diagnostic's message.
static llvm::ManagedStatic< PassManagerOptions > options
URIForFile uri
The text document's URI.
void gatherIncludeFiles(llvm::SourceMgr &sourceMgr, SmallVectorImpl< SourceMgrInclude > &includes)
Given a source manager, gather all of the processed include files.
Range range
The source range where the message applies.
void addDocument(const URIForFile &uri, StringRef contents, int64_t version, std::vector< Diagnostic > &diagnostics)
Add the document, with the provided version, at the given URI.
StringRef toString(IteratorType t)
static lsp::URIForFile getURIFromLoc(const llvm::SourceMgr &mgr, SMLoc loc, const lsp::URIForFile &mainFileURI)
Returns a language server uri for the given source location.
static llvm::Expected< URIForFile > fromFile(StringRef absoluteFilepath)
Try to build a URIForFile from the given absolute file path.
Optional< Hover > findHover(const URIForFile &uri, const Position &hoverPos)
Find a hover description for the given hover position, or None if one couldn't be found...
SMLoc getAsSMLoc(llvm::SourceMgr &mgr) const
Convert this position into a source location in the main file of the given source manager...
void getLocationsOf(const URIForFile &uri, const Position &defPos, std::vector< Location > &locations)
Return the locations of the object pointed at by the given position.
static lsp::Location getLocationFromLoc(llvm::SourceMgr &mgr, SMRange loc, const lsp::URIForFile &uri)
Returns a language server location from the given source range.