15de12bb7SRiver Riddle //===- TableGenServer.cpp - TableGen Language Server ----------------------===// 25de12bb7SRiver Riddle // 35de12bb7SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45de12bb7SRiver Riddle // See https://llvm.org/LICENSE.txt for license information. 55de12bb7SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65de12bb7SRiver Riddle // 75de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 85de12bb7SRiver Riddle 95de12bb7SRiver Riddle #include "TableGenServer.h" 105de12bb7SRiver Riddle 113e2ad376SRiver Riddle #include "mlir/Support/IndentedOstream.h" 12305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/CompilationDatabase.h" 13305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/Logging.h" 14305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/Protocol.h" 15305d7185SRiver Riddle #include "mlir/Tools/lsp-server-support/SourceMgrUtils.h" 165de12bb7SRiver Riddle #include "llvm/ADT/IntervalMap.h" 178d021670SRiver Riddle #include "llvm/ADT/PointerUnion.h" 185de12bb7SRiver Riddle #include "llvm/ADT/StringMap.h" 195de12bb7SRiver Riddle #include "llvm/Support/Path.h" 205de12bb7SRiver Riddle #include "llvm/TableGen/Parser.h" 215de12bb7SRiver Riddle #include "llvm/TableGen/Record.h" 22a1fe1f5fSKazu Hirata #include <optional> 235de12bb7SRiver Riddle 245de12bb7SRiver Riddle using namespace mlir; 25429819f2SRahul Joshi using llvm::Record; 26429819f2SRahul Joshi using llvm::RecordKeeper; 27429819f2SRahul Joshi using llvm::RecordVal; 28429819f2SRahul Joshi using llvm::SourceMgr; 295de12bb7SRiver Riddle 30305d7185SRiver Riddle /// Returns the range of a lexical token given a SMLoc corresponding to the 31305d7185SRiver Riddle /// start of an token location. The range is computed heuristically, and 32305d7185SRiver Riddle /// supports identifier-like tokens, strings, etc. 33305d7185SRiver Riddle static SMRange convertTokenLocToRange(SMLoc loc) { 34305d7185SRiver Riddle return lsp::convertTokenLocToRange(loc, "$"); 35305d7185SRiver Riddle } 36305d7185SRiver Riddle 375de12bb7SRiver Riddle /// Returns a language server uri for the given source location. `mainFileURI` 385de12bb7SRiver Riddle /// corresponds to the uri for the main file of the source manager. 39429819f2SRahul Joshi static lsp::URIForFile getURIFromLoc(const SourceMgr &mgr, SMLoc loc, 405de12bb7SRiver Riddle const lsp::URIForFile &mainFileURI) { 415de12bb7SRiver Riddle int bufferId = mgr.FindBufferContainingLoc(loc); 425de12bb7SRiver Riddle if (bufferId == 0 || bufferId == static_cast<int>(mgr.getMainFileID())) 435de12bb7SRiver Riddle return mainFileURI; 445de12bb7SRiver Riddle llvm::Expected<lsp::URIForFile> fileForLoc = lsp::URIForFile::fromFile( 455de12bb7SRiver Riddle mgr.getBufferInfo(bufferId).Buffer->getBufferIdentifier()); 465de12bb7SRiver Riddle if (fileForLoc) 475de12bb7SRiver Riddle return *fileForLoc; 485de12bb7SRiver Riddle lsp::Logger::error("Failed to create URI for include file: {0}", 495de12bb7SRiver Riddle llvm::toString(fileForLoc.takeError())); 505de12bb7SRiver Riddle return mainFileURI; 515de12bb7SRiver Riddle } 525de12bb7SRiver Riddle 535de12bb7SRiver Riddle /// Returns a language server location from the given source range. 54429819f2SRahul Joshi static lsp::Location getLocationFromLoc(SourceMgr &mgr, SMRange loc, 558d021670SRiver Riddle const lsp::URIForFile &uri) { 568d021670SRiver Riddle return lsp::Location(getURIFromLoc(mgr, loc.Start, uri), 578d021670SRiver Riddle lsp::Range(mgr, loc)); 588d021670SRiver Riddle } 59429819f2SRahul Joshi static lsp::Location getLocationFromLoc(SourceMgr &mgr, SMLoc loc, 605de12bb7SRiver Riddle const lsp::URIForFile &uri) { 61305d7185SRiver Riddle return getLocationFromLoc(mgr, convertTokenLocToRange(loc), uri); 625de12bb7SRiver Riddle } 635de12bb7SRiver Riddle 645de12bb7SRiver Riddle /// Convert the given TableGen diagnostic to the LSP form. 650a81ace0SKazu Hirata static std::optional<lsp::Diagnostic> 665de12bb7SRiver Riddle getLspDiagnoticFromDiag(const llvm::SMDiagnostic &diag, 675de12bb7SRiver Riddle const lsp::URIForFile &uri) { 68429819f2SRahul Joshi auto *sourceMgr = const_cast<SourceMgr *>(diag.getSourceMgr()); 695de12bb7SRiver Riddle if (!sourceMgr || !diag.getLoc().isValid()) 701a36588eSKazu Hirata return std::nullopt; 715de12bb7SRiver Riddle 725de12bb7SRiver Riddle lsp::Diagnostic lspDiag; 735de12bb7SRiver Riddle lspDiag.source = "tablegen"; 745de12bb7SRiver Riddle lspDiag.category = "Parse Error"; 755de12bb7SRiver Riddle 765de12bb7SRiver Riddle // Try to grab a file location for this diagnostic. 775de12bb7SRiver Riddle lsp::Location loc = getLocationFromLoc(*sourceMgr, diag.getLoc(), uri); 785de12bb7SRiver Riddle lspDiag.range = loc.range; 795de12bb7SRiver Riddle 805de12bb7SRiver Riddle // Skip diagnostics that weren't emitted within the main file. 815de12bb7SRiver Riddle if (loc.uri != uri) 821a36588eSKazu Hirata return std::nullopt; 835de12bb7SRiver Riddle 845de12bb7SRiver Riddle // Convert the severity for the diagnostic. 855de12bb7SRiver Riddle switch (diag.getKind()) { 86429819f2SRahul Joshi case SourceMgr::DK_Warning: 875de12bb7SRiver Riddle lspDiag.severity = lsp::DiagnosticSeverity::Warning; 885de12bb7SRiver Riddle break; 89429819f2SRahul Joshi case SourceMgr::DK_Error: 905de12bb7SRiver Riddle lspDiag.severity = lsp::DiagnosticSeverity::Error; 915de12bb7SRiver Riddle break; 92429819f2SRahul Joshi case SourceMgr::DK_Note: 935de12bb7SRiver Riddle // Notes are emitted separately from the main diagnostic, so we just treat 945de12bb7SRiver Riddle // them as remarks given that we can't determine the diagnostic to relate 955de12bb7SRiver Riddle // them to. 96429819f2SRahul Joshi case SourceMgr::DK_Remark: 975de12bb7SRiver Riddle lspDiag.severity = lsp::DiagnosticSeverity::Information; 985de12bb7SRiver Riddle break; 995de12bb7SRiver Riddle } 1005de12bb7SRiver Riddle lspDiag.message = diag.getMessage().str(); 1015de12bb7SRiver Riddle 1025de12bb7SRiver Riddle return lspDiag; 1035de12bb7SRiver Riddle } 1045de12bb7SRiver Riddle 1053e2ad376SRiver Riddle /// Get the base definition of the given record value, or nullptr if one 1063e2ad376SRiver Riddle /// couldn't be found. 107429819f2SRahul Joshi static std::pair<const Record *, const RecordVal *> 108429819f2SRahul Joshi getBaseValue(const Record *record, const RecordVal *value) { 1093e2ad376SRiver Riddle if (value->isTemplateArg()) 1103e2ad376SRiver Riddle return {nullptr, nullptr}; 1113e2ad376SRiver Riddle 1123e2ad376SRiver Riddle // Find a base value for the field in the super classes of the given record. 1133e2ad376SRiver Riddle // On success, `record` is updated to the new parent record. 1143e2ad376SRiver Riddle StringRef valueName = value->getName(); 11565e69f74SRahul Joshi auto findValueInSupers = [&](const Record *&record) -> const RecordVal * { 1163e2ad376SRiver Riddle for (auto [parentRecord, loc] : record->getSuperClasses()) { 1173e2ad376SRiver Riddle if (auto *newBase = parentRecord->getValue(valueName)) { 1183e2ad376SRiver Riddle record = parentRecord; 1193e2ad376SRiver Riddle return newBase; 1203e2ad376SRiver Riddle } 1213e2ad376SRiver Riddle } 1223e2ad376SRiver Riddle return nullptr; 1233e2ad376SRiver Riddle }; 1243e2ad376SRiver Riddle 1253e2ad376SRiver Riddle // Try to find the lowest definition of the record value. 126429819f2SRahul Joshi std::pair<const Record *, const RecordVal *> baseValue = {}; 127429819f2SRahul Joshi while (const RecordVal *newBase = findValueInSupers(record)) 1283e2ad376SRiver Riddle baseValue = {record, newBase}; 1293e2ad376SRiver Riddle 1303e2ad376SRiver Riddle // Check that the base isn't the same as the current value (e.g. if the value 1313e2ad376SRiver Riddle // wasn't overridden). 1323e2ad376SRiver Riddle if (!baseValue.second || baseValue.second->getLoc() == value->getLoc()) 1333e2ad376SRiver Riddle return {nullptr, nullptr}; 1343e2ad376SRiver Riddle return baseValue; 1353e2ad376SRiver Riddle } 1363e2ad376SRiver Riddle 1375de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 1388d021670SRiver Riddle // TableGenIndex 1398d021670SRiver Riddle //===----------------------------------------------------------------------===// 1408d021670SRiver Riddle 1418d021670SRiver Riddle namespace { 1428d021670SRiver Riddle /// This class represents a single symbol definition within a TableGen index. It 1438d021670SRiver Riddle /// contains the definition of the symbol, the location of the symbol, and any 1448d021670SRiver Riddle /// recorded references. 1458d021670SRiver Riddle struct TableGenIndexSymbol { 146429819f2SRahul Joshi TableGenIndexSymbol(const Record *record) 1478d021670SRiver Riddle : definition(record), 148305d7185SRiver Riddle defLoc(convertTokenLocToRange(record->getLoc().front())) {} 149429819f2SRahul Joshi TableGenIndexSymbol(const RecordVal *value) 150305d7185SRiver Riddle : definition(value), defLoc(convertTokenLocToRange(value->getLoc())) {} 151e00dc16dSRiver Riddle virtual ~TableGenIndexSymbol() = default; 1528d021670SRiver Riddle 1533e2ad376SRiver Riddle // The main definition of the symbol. 154429819f2SRahul Joshi PointerUnion<const Record *, const RecordVal *> definition; 1558d021670SRiver Riddle 1568d021670SRiver Riddle /// The source location of the definition. 1578d021670SRiver Riddle SMRange defLoc; 1588d021670SRiver Riddle 1598d021670SRiver Riddle /// The source location of the references of the definition. 1608d021670SRiver Riddle SmallVector<SMRange> references; 1618d021670SRiver Riddle }; 1623e2ad376SRiver Riddle /// This class represents a single record symbol. 1633e2ad376SRiver Riddle struct TableGenRecordSymbol : public TableGenIndexSymbol { 164429819f2SRahul Joshi TableGenRecordSymbol(const Record *record) : TableGenIndexSymbol(record) {} 165e00dc16dSRiver Riddle ~TableGenRecordSymbol() override = default; 1663e2ad376SRiver Riddle 1673e2ad376SRiver Riddle static bool classof(const TableGenIndexSymbol *symbol) { 168*4f4e2abbSKazu Hirata return isa<const Record *>(symbol->definition); 1693e2ad376SRiver Riddle } 1703e2ad376SRiver Riddle 1713e2ad376SRiver Riddle /// Return the value of this symbol. 172*4f4e2abbSKazu Hirata const Record *getValue() const { return cast<const Record *>(definition); } 1733e2ad376SRiver Riddle }; 1743e2ad376SRiver Riddle /// This class represents a single record value symbol. 1753e2ad376SRiver Riddle struct TableGenRecordValSymbol : public TableGenIndexSymbol { 176429819f2SRahul Joshi TableGenRecordValSymbol(const Record *record, const RecordVal *value) 1773e2ad376SRiver Riddle : TableGenIndexSymbol(value), record(record) {} 178e00dc16dSRiver Riddle ~TableGenRecordValSymbol() override = default; 1793e2ad376SRiver Riddle 1803e2ad376SRiver Riddle static bool classof(const TableGenIndexSymbol *symbol) { 181*4f4e2abbSKazu Hirata return isa<const RecordVal *>(symbol->definition); 1823e2ad376SRiver Riddle } 1833e2ad376SRiver Riddle 1843e2ad376SRiver Riddle /// Return the value of this symbol. 185429819f2SRahul Joshi const RecordVal *getValue() const { 186*4f4e2abbSKazu Hirata return cast<const RecordVal *>(definition); 1873e2ad376SRiver Riddle } 1883e2ad376SRiver Riddle 1893e2ad376SRiver Riddle /// The parent record of this symbol. 190429819f2SRahul Joshi const Record *record; 1913e2ad376SRiver Riddle }; 1928d021670SRiver Riddle 1938d021670SRiver Riddle /// This class provides an index for definitions/uses within a TableGen 1948d021670SRiver Riddle /// document. It provides efficient lookup of a definition given an input source 1958d021670SRiver Riddle /// range. 1968d021670SRiver Riddle class TableGenIndex { 1978d021670SRiver Riddle public: 1988d021670SRiver Riddle TableGenIndex() : intervalMap(allocator) {} 1998d021670SRiver Riddle 2008d021670SRiver Riddle /// Initialize the index with the given RecordKeeper. 201429819f2SRahul Joshi void initialize(const RecordKeeper &records); 2028d021670SRiver Riddle 2038d021670SRiver Riddle /// Lookup a symbol for the given location. Returns nullptr if no symbol could 2048d021670SRiver Riddle /// be found. If provided, `overlappedRange` is set to the range that the 2058d021670SRiver Riddle /// provided `loc` overlapped with. 2068d021670SRiver Riddle const TableGenIndexSymbol *lookup(SMLoc loc, 2078d021670SRiver Riddle SMRange *overlappedRange = nullptr) const; 2088d021670SRiver Riddle 2098d021670SRiver Riddle private: 2108d021670SRiver Riddle /// The type of interval map used to store source references. SMRange is 2118d021670SRiver Riddle /// half-open, so we also need to use a half-open interval map. 2128d021670SRiver Riddle using MapT = llvm::IntervalMap< 2138d021670SRiver Riddle const char *, const TableGenIndexSymbol *, 2148d021670SRiver Riddle llvm::IntervalMapImpl::NodeSizer<const char *, 2158d021670SRiver Riddle const TableGenIndexSymbol *>::LeafSize, 2168d021670SRiver Riddle llvm::IntervalMapHalfOpenInfo<const char *>>; 2178d021670SRiver Riddle 2183e2ad376SRiver Riddle /// Get or insert a symbol for the given record. 219429819f2SRahul Joshi TableGenIndexSymbol *getOrInsertDef(const Record *record) { 2203e2ad376SRiver Riddle auto it = defToSymbol.try_emplace(record, nullptr); 2213e2ad376SRiver Riddle if (it.second) 2223e2ad376SRiver Riddle it.first->second = std::make_unique<TableGenRecordSymbol>(record); 2233e2ad376SRiver Riddle return &*it.first->second; 2243e2ad376SRiver Riddle } 2253e2ad376SRiver Riddle /// Get or insert a symbol for the given record value. 226429819f2SRahul Joshi TableGenIndexSymbol *getOrInsertDef(const Record *record, 227429819f2SRahul Joshi const RecordVal *value) { 2283e2ad376SRiver Riddle auto it = defToSymbol.try_emplace(value, nullptr); 2293e2ad376SRiver Riddle if (it.second) { 2303e2ad376SRiver Riddle it.first->second = 2313e2ad376SRiver Riddle std::make_unique<TableGenRecordValSymbol>(record, value); 2323e2ad376SRiver Riddle } 2333e2ad376SRiver Riddle return &*it.first->second; 2343e2ad376SRiver Riddle } 2353e2ad376SRiver Riddle 2368d021670SRiver Riddle /// An allocator for the interval map. 2378d021670SRiver Riddle MapT::Allocator allocator; 2388d021670SRiver Riddle 2398d021670SRiver Riddle /// An interval map containing a corresponding definition mapped to a source 2408d021670SRiver Riddle /// interval. 2418d021670SRiver Riddle MapT intervalMap; 2428d021670SRiver Riddle 2438d021670SRiver Riddle /// A mapping between definitions and their corresponding symbol. 2448d021670SRiver Riddle DenseMap<const void *, std::unique_ptr<TableGenIndexSymbol>> defToSymbol; 2458d021670SRiver Riddle }; 2468d021670SRiver Riddle } // namespace 2478d021670SRiver Riddle 248429819f2SRahul Joshi void TableGenIndex::initialize(const RecordKeeper &records) { 249e00dc16dSRiver Riddle intervalMap.clear(); 250e00dc16dSRiver Riddle defToSymbol.clear(); 251e00dc16dSRiver Riddle 2528d021670SRiver Riddle auto insertRef = [&](TableGenIndexSymbol *sym, SMRange refLoc, 2538d021670SRiver Riddle bool isDef = false) { 2548d021670SRiver Riddle const char *startLoc = refLoc.Start.getPointer(); 2558d021670SRiver Riddle const char *endLoc = refLoc.End.getPointer(); 2568d021670SRiver Riddle 2578d021670SRiver Riddle // If the location we got was empty, try to lex a token from the start 2588d021670SRiver Riddle // location. 2598d021670SRiver Riddle if (startLoc == endLoc) { 260305d7185SRiver Riddle refLoc = convertTokenLocToRange(SMLoc::getFromPointer(startLoc)); 2618d021670SRiver Riddle startLoc = refLoc.Start.getPointer(); 2628d021670SRiver Riddle endLoc = refLoc.End.getPointer(); 2638d021670SRiver Riddle 2648d021670SRiver Riddle // If the location is still empty, bail on trying to use this reference 2658d021670SRiver Riddle // location. 2668d021670SRiver Riddle if (startLoc == endLoc) 2678d021670SRiver Riddle return; 2688d021670SRiver Riddle } 2698d021670SRiver Riddle 2708d021670SRiver Riddle // Check to see if a symbol is already attached to this location. 2718d021670SRiver Riddle // IntervalMap doesn't allow overlapping inserts, and we don't really 2728d021670SRiver Riddle // want multiple symbols attached to a source location anyways. This 2738d021670SRiver Riddle // shouldn't really happen in practice, but we should handle it gracefully. 2748d021670SRiver Riddle if (!intervalMap.overlaps(startLoc, endLoc)) 2758d021670SRiver Riddle intervalMap.insert(startLoc, endLoc, sym); 2768d021670SRiver Riddle 2778d021670SRiver Riddle if (!isDef) 2788d021670SRiver Riddle sym->references.push_back(refLoc); 2798d021670SRiver Riddle }; 2808d021670SRiver Riddle auto classes = 2818d021670SRiver Riddle llvm::make_pointee_range(llvm::make_second_range(records.getClasses())); 2828d021670SRiver Riddle auto defs = 2838d021670SRiver Riddle llvm::make_pointee_range(llvm::make_second_range(records.getDefs())); 284429819f2SRahul Joshi for (const Record &def : llvm::concat<Record>(classes, defs)) { 2858d021670SRiver Riddle auto *sym = getOrInsertDef(&def); 2868d021670SRiver Riddle insertRef(sym, sym->defLoc, /*isDef=*/true); 2878d021670SRiver Riddle 2888d021670SRiver Riddle // Add references to the definition. 2898d021670SRiver Riddle for (SMLoc loc : def.getLoc().drop_front()) 290305d7185SRiver Riddle insertRef(sym, convertTokenLocToRange(loc)); 29150d96f59SRiver Riddle for (SMRange loc : def.getReferenceLocs()) 29250d96f59SRiver Riddle insertRef(sym, loc); 2938d021670SRiver Riddle 2948d021670SRiver Riddle // Add definitions for any values. 295429819f2SRahul Joshi for (const RecordVal &value : def.getValues()) { 2963e2ad376SRiver Riddle auto *sym = getOrInsertDef(&def, &value); 2978d021670SRiver Riddle insertRef(sym, sym->defLoc, /*isDef=*/true); 29850d96f59SRiver Riddle for (SMRange refLoc : value.getReferenceLocs()) 29950d96f59SRiver Riddle insertRef(sym, refLoc); 3008d021670SRiver Riddle } 3018d021670SRiver Riddle } 3028d021670SRiver Riddle } 3038d021670SRiver Riddle 3048d021670SRiver Riddle const TableGenIndexSymbol * 3058d021670SRiver Riddle TableGenIndex::lookup(SMLoc loc, SMRange *overlappedRange) const { 3068d021670SRiver Riddle auto it = intervalMap.find(loc.getPointer()); 3078d021670SRiver Riddle if (!it.valid() || loc.getPointer() < it.start()) 3088d021670SRiver Riddle return nullptr; 3098d021670SRiver Riddle 3108d021670SRiver Riddle if (overlappedRange) { 3118d021670SRiver Riddle *overlappedRange = SMRange(SMLoc::getFromPointer(it.start()), 3128d021670SRiver Riddle SMLoc::getFromPointer(it.stop())); 3138d021670SRiver Riddle } 3148d021670SRiver Riddle return it.value(); 3158d021670SRiver Riddle } 3168d021670SRiver Riddle 3178d021670SRiver Riddle //===----------------------------------------------------------------------===// 3185de12bb7SRiver Riddle // TableGenTextFile 3195de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 3205de12bb7SRiver Riddle 3215de12bb7SRiver Riddle namespace { 3225de12bb7SRiver Riddle /// This class represents a text file containing one or more TableGen documents. 3235de12bb7SRiver Riddle class TableGenTextFile { 3245de12bb7SRiver Riddle public: 3255de12bb7SRiver Riddle TableGenTextFile(const lsp::URIForFile &uri, StringRef fileContents, 326dc9fb65cSRiver Riddle int64_t version, 327dc9fb65cSRiver Riddle const std::vector<std::string> &extraIncludeDirs, 328dc9fb65cSRiver Riddle std::vector<lsp::Diagnostic> &diagnostics); 3295de12bb7SRiver Riddle 3305de12bb7SRiver Riddle /// Return the current version of this text file. 3315de12bb7SRiver Riddle int64_t getVersion() const { return version; } 3325de12bb7SRiver Riddle 3336187178eSRiver Riddle /// Update the file to the new version using the provided set of content 3346187178eSRiver Riddle /// changes. Returns failure if the update was unsuccessful. 3356187178eSRiver Riddle LogicalResult update(const lsp::URIForFile &uri, int64_t newVersion, 3366187178eSRiver Riddle ArrayRef<lsp::TextDocumentContentChangeEvent> changes, 3376187178eSRiver Riddle std::vector<lsp::Diagnostic> &diagnostics); 3386187178eSRiver Riddle 339682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 3408d021670SRiver Riddle // Definitions and References 3418d021670SRiver Riddle //===--------------------------------------------------------------------===// 3428d021670SRiver Riddle 3438d021670SRiver Riddle void getLocationsOf(const lsp::URIForFile &uri, const lsp::Position &defPos, 3448d021670SRiver Riddle std::vector<lsp::Location> &locations); 3458d021670SRiver Riddle void findReferencesOf(const lsp::URIForFile &uri, const lsp::Position &pos, 3468d021670SRiver Riddle std::vector<lsp::Location> &references); 3478d021670SRiver Riddle 3488d021670SRiver Riddle //===--------------------------------------------------------------------===// 349682ca00eSRiver Riddle // Document Links 350682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 351682ca00eSRiver Riddle 352682ca00eSRiver Riddle void getDocumentLinks(const lsp::URIForFile &uri, 353682ca00eSRiver Riddle std::vector<lsp::DocumentLink> &links); 354682ca00eSRiver Riddle 355682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 356682ca00eSRiver Riddle // Hover 357682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 358682ca00eSRiver Riddle 3591da3a795SFangrui Song std::optional<lsp::Hover> findHover(const lsp::URIForFile &uri, 360682ca00eSRiver Riddle const lsp::Position &hoverPos); 361429819f2SRahul Joshi lsp::Hover buildHoverForRecord(const Record *record, 3623e2ad376SRiver Riddle const SMRange &hoverRange); 363429819f2SRahul Joshi lsp::Hover buildHoverForTemplateArg(const Record *record, 364429819f2SRahul Joshi const RecordVal *value, 3653e2ad376SRiver Riddle const SMRange &hoverRange); 366429819f2SRahul Joshi lsp::Hover buildHoverForField(const Record *record, const RecordVal *value, 3673e2ad376SRiver Riddle const SMRange &hoverRange); 368682ca00eSRiver Riddle 3695de12bb7SRiver Riddle private: 3706187178eSRiver Riddle /// Initialize the text file from the given file contents. 3716187178eSRiver Riddle void initialize(const lsp::URIForFile &uri, int64_t newVersion, 3726187178eSRiver Riddle std::vector<lsp::Diagnostic> &diagnostics); 3736187178eSRiver Riddle 3745de12bb7SRiver Riddle /// The full string contents of the file. 3755de12bb7SRiver Riddle std::string contents; 3765de12bb7SRiver Riddle 3775de12bb7SRiver Riddle /// The version of this file. 3785de12bb7SRiver Riddle int64_t version; 3795de12bb7SRiver Riddle 3805de12bb7SRiver Riddle /// The include directories for this file. 3815de12bb7SRiver Riddle std::vector<std::string> includeDirs; 3825de12bb7SRiver Riddle 3835de12bb7SRiver Riddle /// The source manager containing the contents of the input file. 384429819f2SRahul Joshi SourceMgr sourceMgr; 3855de12bb7SRiver Riddle 3865de12bb7SRiver Riddle /// The record keeper containing the parsed tablegen constructs. 387429819f2SRahul Joshi std::unique_ptr<RecordKeeper> recordKeeper; 388682ca00eSRiver Riddle 3898d021670SRiver Riddle /// The index of the parsed file. 3908d021670SRiver Riddle TableGenIndex index; 3918d021670SRiver Riddle 392682ca00eSRiver Riddle /// The set of includes of the parsed file. 393682ca00eSRiver Riddle SmallVector<lsp::SourceMgrInclude> parsedIncludes; 3945de12bb7SRiver Riddle }; 3955de12bb7SRiver Riddle } // namespace 3965de12bb7SRiver Riddle 397dc9fb65cSRiver Riddle TableGenTextFile::TableGenTextFile( 398dc9fb65cSRiver Riddle const lsp::URIForFile &uri, StringRef fileContents, int64_t version, 399dc9fb65cSRiver Riddle const std::vector<std::string> &extraIncludeDirs, 4005de12bb7SRiver Riddle std::vector<lsp::Diagnostic> &diagnostics) 4015de12bb7SRiver Riddle : contents(fileContents.str()), version(version) { 4025de12bb7SRiver Riddle // Build the set of include directories for this file. 4035de12bb7SRiver Riddle llvm::SmallString<32> uriDirectory(uri.file()); 4045de12bb7SRiver Riddle llvm::sys::path::remove_filename(uriDirectory); 4055de12bb7SRiver Riddle includeDirs.push_back(uriDirectory.str().str()); 406dc9fb65cSRiver Riddle includeDirs.insert(includeDirs.end(), extraIncludeDirs.begin(), 407dc9fb65cSRiver Riddle extraIncludeDirs.end()); 4085de12bb7SRiver Riddle 4096187178eSRiver Riddle // Initialize the file. 4106187178eSRiver Riddle initialize(uri, version, diagnostics); 4116187178eSRiver Riddle } 4126187178eSRiver Riddle 4136187178eSRiver Riddle LogicalResult 4146187178eSRiver Riddle TableGenTextFile::update(const lsp::URIForFile &uri, int64_t newVersion, 4156187178eSRiver Riddle ArrayRef<lsp::TextDocumentContentChangeEvent> changes, 4166187178eSRiver Riddle std::vector<lsp::Diagnostic> &diagnostics) { 4176187178eSRiver Riddle if (failed(lsp::TextDocumentContentChangeEvent::applyTo(changes, contents))) { 4186187178eSRiver Riddle lsp::Logger::error("Failed to update contents of {0}", uri.file()); 4196187178eSRiver Riddle return failure(); 4206187178eSRiver Riddle } 4216187178eSRiver Riddle 4226187178eSRiver Riddle // If the file contents were properly changed, reinitialize the text file. 4236187178eSRiver Riddle initialize(uri, newVersion, diagnostics); 4246187178eSRiver Riddle return success(); 4256187178eSRiver Riddle } 4266187178eSRiver Riddle 4276187178eSRiver Riddle void TableGenTextFile::initialize(const lsp::URIForFile &uri, 4286187178eSRiver Riddle int64_t newVersion, 4296187178eSRiver Riddle std::vector<lsp::Diagnostic> &diagnostics) { 4306187178eSRiver Riddle version = newVersion; 431429819f2SRahul Joshi sourceMgr = SourceMgr(); 432429819f2SRahul Joshi recordKeeper = std::make_unique<RecordKeeper>(); 4336187178eSRiver Riddle 4346187178eSRiver Riddle // Build a buffer for this file. 4356187178eSRiver Riddle auto memBuffer = llvm::MemoryBuffer::getMemBuffer(contents, uri.file()); 4366187178eSRiver Riddle if (!memBuffer) { 4376187178eSRiver Riddle lsp::Logger::error("Failed to create memory buffer for file", uri.file()); 4386187178eSRiver Riddle return; 4396187178eSRiver Riddle } 4405de12bb7SRiver Riddle sourceMgr.setIncludeDirs(includeDirs); 4415de12bb7SRiver Riddle sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc()); 4425de12bb7SRiver Riddle 443429819f2SRahul Joshi // This class provides a context argument for the SourceMgr diagnostic 4445de12bb7SRiver Riddle // handler. 4455de12bb7SRiver Riddle struct DiagHandlerContext { 4465de12bb7SRiver Riddle std::vector<lsp::Diagnostic> &diagnostics; 4475de12bb7SRiver Riddle const lsp::URIForFile &uri; 4485de12bb7SRiver Riddle } handlerContext{diagnostics, uri}; 4495de12bb7SRiver Riddle 4505de12bb7SRiver Riddle // Set the diagnostic handler for the tablegen source manager. 4515de12bb7SRiver Riddle sourceMgr.setDiagHandler( 4525de12bb7SRiver Riddle [](const llvm::SMDiagnostic &diag, void *rawHandlerContext) { 4535de12bb7SRiver Riddle auto *ctx = reinterpret_cast<DiagHandlerContext *>(rawHandlerContext); 4545de12bb7SRiver Riddle if (auto lspDiag = getLspDiagnoticFromDiag(diag, ctx->uri)) 4555de12bb7SRiver Riddle ctx->diagnostics.push_back(*lspDiag); 4565de12bb7SRiver Riddle }, 4575de12bb7SRiver Riddle &handlerContext); 4586187178eSRiver Riddle bool failedToParse = llvm::TableGenParseFile(sourceMgr, *recordKeeper); 459682ca00eSRiver Riddle 460682ca00eSRiver Riddle // Process all of the include files. 461682ca00eSRiver Riddle lsp::gatherIncludeFiles(sourceMgr, parsedIncludes); 462682ca00eSRiver Riddle if (failedToParse) 4635de12bb7SRiver Riddle return; 4648d021670SRiver Riddle 4658d021670SRiver Riddle // If we successfully parsed the file, we can now build the index. 4666187178eSRiver Riddle index.initialize(*recordKeeper); 4678d021670SRiver Riddle } 4688d021670SRiver Riddle 4698d021670SRiver Riddle //===----------------------------------------------------------------------===// 4708d021670SRiver Riddle // TableGenTextFile: Definitions and References 4718d021670SRiver Riddle //===----------------------------------------------------------------------===// 4728d021670SRiver Riddle 4738d021670SRiver Riddle void TableGenTextFile::getLocationsOf(const lsp::URIForFile &uri, 4748d021670SRiver Riddle const lsp::Position &defPos, 4758d021670SRiver Riddle std::vector<lsp::Location> &locations) { 4768d021670SRiver Riddle SMLoc posLoc = defPos.getAsSMLoc(sourceMgr); 4778d021670SRiver Riddle const TableGenIndexSymbol *symbol = index.lookup(posLoc); 4788d021670SRiver Riddle if (!symbol) 4798d021670SRiver Riddle return; 4808d021670SRiver Riddle 48199e24123SRiver Riddle // If this symbol is a record value and the def position is already the def of 48299e24123SRiver Riddle // the symbol, check to see if the value has a base definition. This allows 48399e24123SRiver Riddle // for a "go-to-def" on a "let" to resolve the definition in the base class. 48499e24123SRiver Riddle auto *valSym = dyn_cast<TableGenRecordValSymbol>(symbol); 48599e24123SRiver Riddle if (valSym && lsp::contains(valSym->defLoc, posLoc)) { 48699e24123SRiver Riddle if (auto *val = getBaseValue(valSym->record, valSym->getValue()).second) { 48799e24123SRiver Riddle locations.push_back(getLocationFromLoc(sourceMgr, val->getLoc(), uri)); 48899e24123SRiver Riddle return; 48999e24123SRiver Riddle } 49099e24123SRiver Riddle } 49199e24123SRiver Riddle 4928d021670SRiver Riddle locations.push_back(getLocationFromLoc(sourceMgr, symbol->defLoc, uri)); 4938d021670SRiver Riddle } 4948d021670SRiver Riddle 4958d021670SRiver Riddle void TableGenTextFile::findReferencesOf( 4968d021670SRiver Riddle const lsp::URIForFile &uri, const lsp::Position &pos, 4978d021670SRiver Riddle std::vector<lsp::Location> &references) { 4988d021670SRiver Riddle SMLoc posLoc = pos.getAsSMLoc(sourceMgr); 4998d021670SRiver Riddle const TableGenIndexSymbol *symbol = index.lookup(posLoc); 5008d021670SRiver Riddle if (!symbol) 5018d021670SRiver Riddle return; 5028d021670SRiver Riddle 5038d021670SRiver Riddle references.push_back(getLocationFromLoc(sourceMgr, symbol->defLoc, uri)); 5048d021670SRiver Riddle for (SMRange refLoc : symbol->references) 5058d021670SRiver Riddle references.push_back(getLocationFromLoc(sourceMgr, refLoc, uri)); 5065de12bb7SRiver Riddle } 5075de12bb7SRiver Riddle 508682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 509682ca00eSRiver Riddle // TableGenTextFile: Document Links 510682ca00eSRiver Riddle //===--------------------------------------------------------------------===// 511682ca00eSRiver Riddle 512682ca00eSRiver Riddle void TableGenTextFile::getDocumentLinks(const lsp::URIForFile &uri, 513682ca00eSRiver Riddle std::vector<lsp::DocumentLink> &links) { 514682ca00eSRiver Riddle for (const lsp::SourceMgrInclude &include : parsedIncludes) 515682ca00eSRiver Riddle links.emplace_back(include.range, include.uri); 516682ca00eSRiver Riddle } 517682ca00eSRiver Riddle 518682ca00eSRiver Riddle //===----------------------------------------------------------------------===// 519682ca00eSRiver Riddle // TableGenTextFile: Hover 520682ca00eSRiver Riddle //===----------------------------------------------------------------------===// 521682ca00eSRiver Riddle 5221da3a795SFangrui Song std::optional<lsp::Hover> 523682ca00eSRiver Riddle TableGenTextFile::findHover(const lsp::URIForFile &uri, 524682ca00eSRiver Riddle const lsp::Position &hoverPos) { 525682ca00eSRiver Riddle // Check for a reference to an include. 526682ca00eSRiver Riddle for (const lsp::SourceMgrInclude &include : parsedIncludes) 527682ca00eSRiver Riddle if (include.range.contains(hoverPos)) 528682ca00eSRiver Riddle return include.buildHover(); 5293e2ad376SRiver Riddle 5303e2ad376SRiver Riddle // Find the symbol at the given location. 5313e2ad376SRiver Riddle SMRange hoverRange; 5323e2ad376SRiver Riddle SMLoc posLoc = hoverPos.getAsSMLoc(sourceMgr); 5333e2ad376SRiver Riddle const TableGenIndexSymbol *symbol = index.lookup(posLoc, &hoverRange); 5343e2ad376SRiver Riddle if (!symbol) 5351a36588eSKazu Hirata return std::nullopt; 5363e2ad376SRiver Riddle 5373e2ad376SRiver Riddle // Build hover for a Record. 5383e2ad376SRiver Riddle if (auto *record = dyn_cast<TableGenRecordSymbol>(symbol)) 5393e2ad376SRiver Riddle return buildHoverForRecord(record->getValue(), hoverRange); 5403e2ad376SRiver Riddle 5413e2ad376SRiver Riddle // Build hover for a RecordVal, which is either a template argument or a 5423e2ad376SRiver Riddle // field. 5433e2ad376SRiver Riddle auto *recordVal = cast<TableGenRecordValSymbol>(symbol); 544429819f2SRahul Joshi const RecordVal *value = recordVal->getValue(); 5453e2ad376SRiver Riddle if (value->isTemplateArg()) 5463e2ad376SRiver Riddle return buildHoverForTemplateArg(recordVal->record, value, hoverRange); 5473e2ad376SRiver Riddle return buildHoverForField(recordVal->record, value, hoverRange); 5483e2ad376SRiver Riddle } 5493e2ad376SRiver Riddle 550429819f2SRahul Joshi lsp::Hover TableGenTextFile::buildHoverForRecord(const Record *record, 5513e2ad376SRiver Riddle const SMRange &hoverRange) { 5523e2ad376SRiver Riddle lsp::Hover hover(lsp::Range(sourceMgr, hoverRange)); 5533e2ad376SRiver Riddle { 5543e2ad376SRiver Riddle llvm::raw_string_ostream hoverOS(hover.contents.value); 5553e2ad376SRiver Riddle 5563e2ad376SRiver Riddle // Format the type of record this is. 5573e2ad376SRiver Riddle if (record->isClass()) { 5583e2ad376SRiver Riddle hoverOS << "**class** `" << record->getName() << "`"; 5593e2ad376SRiver Riddle } else if (record->isAnonymous()) { 5603e2ad376SRiver Riddle hoverOS << "**anonymous class**"; 5613e2ad376SRiver Riddle } else { 5623e2ad376SRiver Riddle hoverOS << "**def** `" << record->getName() << "`"; 5633e2ad376SRiver Riddle } 5643e2ad376SRiver Riddle hoverOS << "\n***\n"; 5653e2ad376SRiver Riddle 5663e2ad376SRiver Riddle // Check if this record has summary/description fields. These are often used 5673e2ad376SRiver Riddle // to hold documentation for the record. 5683e2ad376SRiver Riddle auto printAndFormatField = [&](StringRef fieldName) { 5693e2ad376SRiver Riddle // Check that the record actually has the given field, and that it's a 5703e2ad376SRiver Riddle // string. 571429819f2SRahul Joshi const RecordVal *value = record->getValue(fieldName); 5723e2ad376SRiver Riddle if (!value || !value->getValue()) 5733e2ad376SRiver Riddle return; 5743e2ad376SRiver Riddle auto *stringValue = dyn_cast<llvm::StringInit>(value->getValue()); 5753e2ad376SRiver Riddle if (!stringValue) 5763e2ad376SRiver Riddle return; 5773e2ad376SRiver Riddle 5783e2ad376SRiver Riddle raw_indented_ostream ros(hoverOS); 5793e2ad376SRiver Riddle ros.printReindented(stringValue->getValue().rtrim(" \t")); 5803e2ad376SRiver Riddle hoverOS << "\n***\n"; 5813e2ad376SRiver Riddle }; 5823e2ad376SRiver Riddle printAndFormatField("summary"); 5833e2ad376SRiver Riddle printAndFormatField("description"); 5843e2ad376SRiver Riddle 5853e2ad376SRiver Riddle // Check for documentation in the source file. 5860a81ace0SKazu Hirata if (std::optional<std::string> doc = 5873e2ad376SRiver Riddle lsp::extractSourceDocComment(sourceMgr, record->getLoc().front())) { 5883e2ad376SRiver Riddle hoverOS << "\n" << *doc << "\n"; 5893e2ad376SRiver Riddle } 5903e2ad376SRiver Riddle } 5913e2ad376SRiver Riddle return hover; 5923e2ad376SRiver Riddle } 5933e2ad376SRiver Riddle 594429819f2SRahul Joshi lsp::Hover TableGenTextFile::buildHoverForTemplateArg( 595429819f2SRahul Joshi const Record *record, const RecordVal *value, const SMRange &hoverRange) { 5963e2ad376SRiver Riddle lsp::Hover hover(lsp::Range(sourceMgr, hoverRange)); 5973e2ad376SRiver Riddle { 5983e2ad376SRiver Riddle llvm::raw_string_ostream hoverOS(hover.contents.value); 5993e2ad376SRiver Riddle StringRef name = value->getName().rsplit(':').second; 6003e2ad376SRiver Riddle 6013e2ad376SRiver Riddle hoverOS << "**template arg** `" << name << "`\n***\nType: `"; 6023e2ad376SRiver Riddle value->getType()->print(hoverOS); 6033e2ad376SRiver Riddle hoverOS << "`\n"; 6043e2ad376SRiver Riddle } 6053e2ad376SRiver Riddle return hover; 6063e2ad376SRiver Riddle } 6073e2ad376SRiver Riddle 608429819f2SRahul Joshi lsp::Hover TableGenTextFile::buildHoverForField(const Record *record, 609429819f2SRahul Joshi const RecordVal *value, 6103e2ad376SRiver Riddle const SMRange &hoverRange) { 6113e2ad376SRiver Riddle lsp::Hover hover(lsp::Range(sourceMgr, hoverRange)); 6123e2ad376SRiver Riddle { 6133e2ad376SRiver Riddle llvm::raw_string_ostream hoverOS(hover.contents.value); 6143e2ad376SRiver Riddle hoverOS << "**field** `" << value->getName() << "`\n***\nType: `"; 6153e2ad376SRiver Riddle value->getType()->print(hoverOS); 6163e2ad376SRiver Riddle hoverOS << "`\n***\n"; 6173e2ad376SRiver Riddle 6183e2ad376SRiver Riddle // Check for documentation in the source file. 6190a81ace0SKazu Hirata if (std::optional<std::string> doc = 6203e2ad376SRiver Riddle lsp::extractSourceDocComment(sourceMgr, value->getLoc())) { 6213e2ad376SRiver Riddle hoverOS << "\n" << *doc << "\n"; 6223e2ad376SRiver Riddle hoverOS << "\n***\n"; 6233e2ad376SRiver Riddle } 6243e2ad376SRiver Riddle 6253e2ad376SRiver Riddle // Check to see if there is a base value that we can use for 6263e2ad376SRiver Riddle // documentation. 6273e2ad376SRiver Riddle auto [baseRecord, baseValue] = getBaseValue(record, value); 6283e2ad376SRiver Riddle if (baseValue) { 6290a81ace0SKazu Hirata if (std::optional<std::string> doc = 6303e2ad376SRiver Riddle lsp::extractSourceDocComment(sourceMgr, baseValue->getLoc())) { 6313e2ad376SRiver Riddle hoverOS << "\n *From `" << baseRecord->getName() << "`*:\n\n" 6323e2ad376SRiver Riddle << *doc << "\n"; 6333e2ad376SRiver Riddle } 6343e2ad376SRiver Riddle } 6353e2ad376SRiver Riddle } 6363e2ad376SRiver Riddle return hover; 637682ca00eSRiver Riddle } 638682ca00eSRiver Riddle 6395de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 6405de12bb7SRiver Riddle // TableGenServer::Impl 6415de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 6425de12bb7SRiver Riddle 6435de12bb7SRiver Riddle struct lsp::TableGenServer::Impl { 644dc9fb65cSRiver Riddle explicit Impl(const Options &options) 645dc9fb65cSRiver Riddle : options(options), compilationDatabase(options.compilationDatabases) {} 646dc9fb65cSRiver Riddle 647dc9fb65cSRiver Riddle /// TableGen LSP options. 648dc9fb65cSRiver Riddle const Options &options; 649dc9fb65cSRiver Riddle 650dc9fb65cSRiver Riddle /// The compilation database containing additional information for files 651dc9fb65cSRiver Riddle /// passed to the server. 652dc9fb65cSRiver Riddle lsp::CompilationDatabase compilationDatabase; 653dc9fb65cSRiver Riddle 6545de12bb7SRiver Riddle /// The files held by the server, mapped by their URI file name. 6555de12bb7SRiver Riddle llvm::StringMap<std::unique_ptr<TableGenTextFile>> files; 6565de12bb7SRiver Riddle }; 6575de12bb7SRiver Riddle 6585de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 6595de12bb7SRiver Riddle // TableGenServer 6605de12bb7SRiver Riddle //===----------------------------------------------------------------------===// 6615de12bb7SRiver Riddle 662dc9fb65cSRiver Riddle lsp::TableGenServer::TableGenServer(const Options &options) 663dc9fb65cSRiver Riddle : impl(std::make_unique<Impl>(options)) {} 6645de12bb7SRiver Riddle lsp::TableGenServer::~TableGenServer() = default; 6655de12bb7SRiver Riddle 6666187178eSRiver Riddle void lsp::TableGenServer::addDocument(const URIForFile &uri, StringRef contents, 6676187178eSRiver Riddle int64_t version, 6685de12bb7SRiver Riddle std::vector<Diagnostic> &diagnostics) { 669dc9fb65cSRiver Riddle // Build the set of additional include directories. 670dc9fb65cSRiver Riddle std::vector<std::string> additionalIncludeDirs = impl->options.extraDirs; 671dc9fb65cSRiver Riddle const auto &fileInfo = impl->compilationDatabase.getFileInfo(uri.file()); 672dc9fb65cSRiver Riddle llvm::append_range(additionalIncludeDirs, fileInfo.includeDirs); 673dc9fb65cSRiver Riddle 674dc9fb65cSRiver Riddle impl->files[uri.file()] = std::make_unique<TableGenTextFile>( 675dc9fb65cSRiver Riddle uri, contents, version, additionalIncludeDirs, diagnostics); 6765de12bb7SRiver Riddle } 6775de12bb7SRiver Riddle 6786187178eSRiver Riddle void lsp::TableGenServer::updateDocument( 6796187178eSRiver Riddle const URIForFile &uri, ArrayRef<TextDocumentContentChangeEvent> changes, 6806187178eSRiver Riddle int64_t version, std::vector<Diagnostic> &diagnostics) { 6816187178eSRiver Riddle // Check that we actually have a document for this uri. 6826187178eSRiver Riddle auto it = impl->files.find(uri.file()); 6836187178eSRiver Riddle if (it == impl->files.end()) 6846187178eSRiver Riddle return; 6856187178eSRiver Riddle 6866187178eSRiver Riddle // Try to update the document. If we fail, erase the file from the server. A 6876187178eSRiver Riddle // failed updated generally means we've fallen out of sync somewhere. 6886187178eSRiver Riddle if (failed(it->second->update(uri, version, changes, diagnostics))) 6896187178eSRiver Riddle impl->files.erase(it); 6906187178eSRiver Riddle } 6916187178eSRiver Riddle 6920a81ace0SKazu Hirata std::optional<int64_t> 6930a81ace0SKazu Hirata lsp::TableGenServer::removeDocument(const URIForFile &uri) { 6945de12bb7SRiver Riddle auto it = impl->files.find(uri.file()); 6955de12bb7SRiver Riddle if (it == impl->files.end()) 6961a36588eSKazu Hirata return std::nullopt; 6975de12bb7SRiver Riddle 6985de12bb7SRiver Riddle int64_t version = it->second->getVersion(); 6995de12bb7SRiver Riddle impl->files.erase(it); 7005de12bb7SRiver Riddle return version; 7015de12bb7SRiver Riddle } 702682ca00eSRiver Riddle 7038d021670SRiver Riddle void lsp::TableGenServer::getLocationsOf(const URIForFile &uri, 7048d021670SRiver Riddle const Position &defPos, 7058d021670SRiver Riddle std::vector<Location> &locations) { 7068d021670SRiver Riddle auto fileIt = impl->files.find(uri.file()); 7078d021670SRiver Riddle if (fileIt != impl->files.end()) 7088d021670SRiver Riddle fileIt->second->getLocationsOf(uri, defPos, locations); 7098d021670SRiver Riddle } 7108d021670SRiver Riddle 7118d021670SRiver Riddle void lsp::TableGenServer::findReferencesOf(const URIForFile &uri, 7128d021670SRiver Riddle const Position &pos, 7138d021670SRiver Riddle std::vector<Location> &references) { 7148d021670SRiver Riddle auto fileIt = impl->files.find(uri.file()); 7158d021670SRiver Riddle if (fileIt != impl->files.end()) 7168d021670SRiver Riddle fileIt->second->findReferencesOf(uri, pos, references); 7178d021670SRiver Riddle } 7188d021670SRiver Riddle 719682ca00eSRiver Riddle void lsp::TableGenServer::getDocumentLinks( 720682ca00eSRiver Riddle const URIForFile &uri, std::vector<DocumentLink> &documentLinks) { 721682ca00eSRiver Riddle auto fileIt = impl->files.find(uri.file()); 722682ca00eSRiver Riddle if (fileIt != impl->files.end()) 723682ca00eSRiver Riddle return fileIt->second->getDocumentLinks(uri, documentLinks); 724682ca00eSRiver Riddle } 725682ca00eSRiver Riddle 7261da3a795SFangrui Song std::optional<lsp::Hover> 7271da3a795SFangrui Song lsp::TableGenServer::findHover(const URIForFile &uri, 728682ca00eSRiver Riddle const Position &hoverPos) { 729682ca00eSRiver Riddle auto fileIt = impl->files.find(uri.file()); 730682ca00eSRiver Riddle if (fileIt != impl->files.end()) 731682ca00eSRiver Riddle return fileIt->second->findHover(uri, hoverPos); 7321a36588eSKazu Hirata return std::nullopt; 733682ca00eSRiver Riddle } 734