mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Support textDocument/declaration & LocationLink
textDocument/{declaration,definition,typeDefinition} return either LocationLink[] or Location[]
Add an initialization option client.linkSupport . When it is false, ccls will return Location[] disregarding client's linkSupport.
`struct LocationLink` does not include originSelectionRange as it is wasteful.
			
			
This commit is contained in:
		
							parent
							
								
									e3133bea90
								
							
						
					
					
						commit
						49ae9e8912
					
				@ -73,6 +73,8 @@ struct Config {
 | 
			
		||||
  struct ClientCapability {
 | 
			
		||||
    // TextDocumentClientCapabilities.documentSymbol.hierarchicalDocumentSymbolSupport
 | 
			
		||||
    bool hierarchicalDocumentSymbolSupport = true;
 | 
			
		||||
    // TextDocumentClientCapabilities.definition.linkSupport
 | 
			
		||||
    bool linkSupport = true;
 | 
			
		||||
    // TextDocumentClientCapabilities.completion.completionItem.snippetSupport
 | 
			
		||||
    bool snippetSupport = true;
 | 
			
		||||
  } client;
 | 
			
		||||
@ -248,30 +250,28 @@ struct Config {
 | 
			
		||||
  } xref;
 | 
			
		||||
};
 | 
			
		||||
REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings,
 | 
			
		||||
                    resourceDir);
 | 
			
		||||
               resourceDir);
 | 
			
		||||
REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport,
 | 
			
		||||
                    snippetSupport);
 | 
			
		||||
               linkSupport, snippetSupport);
 | 
			
		||||
REFLECT_STRUCT(Config::CodeLens, localVariables);
 | 
			
		||||
REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize,
 | 
			
		||||
                    suffixWhitelist, whitelist);
 | 
			
		||||
               suffixWhitelist, whitelist);
 | 
			
		||||
REFLECT_STRUCT(Config::Completion, caseSensitivity, detailedLabel,
 | 
			
		||||
                    dropOldRequests, duplicateOptional, filterAndSort, include,
 | 
			
		||||
                    maxNum);
 | 
			
		||||
               dropOldRequests, duplicateOptional, filterAndSort, include,
 | 
			
		||||
               maxNum);
 | 
			
		||||
REFLECT_STRUCT(Config::Diagnostics, blacklist, onChange, onOpen, onSave,
 | 
			
		||||
                    spellChecking, whitelist)
 | 
			
		||||
REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist,
 | 
			
		||||
                    whitelist)
 | 
			
		||||
               spellChecking, whitelist)
 | 
			
		||||
REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist, whitelist)
 | 
			
		||||
REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
 | 
			
		||||
                    initialWhitelist, multiVersion, multiVersionBlacklist,
 | 
			
		||||
                    multiVersionWhitelist, onChange, threads, trackDependency,
 | 
			
		||||
                    whitelist);
 | 
			
		||||
               initialWhitelist, multiVersion, multiVersionBlacklist,
 | 
			
		||||
               multiVersionWhitelist, onChange, threads, trackDependency,
 | 
			
		||||
               whitelist);
 | 
			
		||||
REFLECT_STRUCT(Config::Session, maxNum);
 | 
			
		||||
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
 | 
			
		||||
REFLECT_STRUCT(Config::Xref, maxNum);
 | 
			
		||||
REFLECT_STRUCT(Config, compilationDatabaseCommand,
 | 
			
		||||
                    compilationDatabaseDirectory, cacheDirectory, cacheFormat,
 | 
			
		||||
                    clang, client, codeLens, completion, diagnostics, highlight,
 | 
			
		||||
                    index, session, workspaceSymbol, xref);
 | 
			
		||||
REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
 | 
			
		||||
               cacheDirectory, cacheFormat, clang, client, codeLens, completion,
 | 
			
		||||
               diagnostics, highlight, index, session, workspaceSymbol, xref);
 | 
			
		||||
 | 
			
		||||
extern Config *g_config;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,10 +48,6 @@ DocumentUri DocumentUri::FromPath(const std::string &path) {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DocumentUri::operator==(const DocumentUri &other) const {
 | 
			
		||||
  return raw_uri == other.raw_uri;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentUri::SetPath(const std::string &path) {
 | 
			
		||||
  // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests
 | 
			
		||||
  raw_uri = path;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								src/lsp.hh
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/lsp.hh
									
									
									
									
									
								
							@ -60,7 +60,8 @@ constexpr char window_showMessage[] = "window/showMessage";
 | 
			
		||||
struct DocumentUri {
 | 
			
		||||
  static DocumentUri FromPath(const std::string &path);
 | 
			
		||||
 | 
			
		||||
  bool operator==(const DocumentUri &other) const;
 | 
			
		||||
  bool operator==(const DocumentUri &o) const { return raw_uri == o.raw_uri; }
 | 
			
		||||
  bool operator<(const DocumentUri &o) const { return raw_uri < o.raw_uri; }
 | 
			
		||||
 | 
			
		||||
  void SetPath(const std::string &path);
 | 
			
		||||
  std::string GetPath() const;
 | 
			
		||||
@ -107,8 +108,26 @@ struct Location {
 | 
			
		||||
    return uri == o.uri && range == o.range;
 | 
			
		||||
  }
 | 
			
		||||
  bool operator<(const Location &o) const {
 | 
			
		||||
    return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri
 | 
			
		||||
                                           : range < o.range;
 | 
			
		||||
    return !(uri == o.uri) ? uri < o.uri : range < o.range;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LocationLink {
 | 
			
		||||
  std::string targetUri;
 | 
			
		||||
  lsRange targetRange;
 | 
			
		||||
  lsRange targetSelectionRange;
 | 
			
		||||
  explicit operator bool() const { return targetUri.size(); }
 | 
			
		||||
  explicit operator Location() && {
 | 
			
		||||
    return {DocumentUri{std::move(targetUri)}, targetSelectionRange};
 | 
			
		||||
  }
 | 
			
		||||
  bool operator==(const LocationLink &o) const {
 | 
			
		||||
    return targetUri == o.targetUri &&
 | 
			
		||||
           targetSelectionRange == o.targetSelectionRange;
 | 
			
		||||
  }
 | 
			
		||||
  bool operator<(const LocationLink &o) const {
 | 
			
		||||
    return !(targetUri == o.targetUri)
 | 
			
		||||
               ? targetUri < o.targetUri
 | 
			
		||||
               : targetSelectionRange < o.targetSelectionRange;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -104,6 +104,21 @@ void ReplyOnce::NotReady(bool file) {
 | 
			
		||||
    Error(ErrorCode::InternalError, "not indexed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
 | 
			
		||||
  std::sort(result.begin(), result.end());
 | 
			
		||||
  result.erase(std::unique(result.begin(), result.end()), result.end());
 | 
			
		||||
  if (result.size() > g_config->xref.maxNum)
 | 
			
		||||
    result.resize(g_config->xref.maxNum);
 | 
			
		||||
  if (g_config->client.linkSupport) {
 | 
			
		||||
    (*this)(result);
 | 
			
		||||
  } else {
 | 
			
		||||
    std::vector<Location> result1;
 | 
			
		||||
    for (auto &loc : result)
 | 
			
		||||
      result1.emplace_back(std::move(loc));
 | 
			
		||||
    (*this)(result1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MessageHandler::Bind(const char *method,
 | 
			
		||||
                          void (MessageHandler::*handler)(JsonReader &)) {
 | 
			
		||||
  method2notification[method] = [this, handler](JsonReader &reader) {
 | 
			
		||||
@ -143,6 +158,7 @@ void MessageHandler::Bind(const char *method,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MessageHandler::MessageHandler() {
 | 
			
		||||
  // clang-format off
 | 
			
		||||
  Bind("$ccls/call", &MessageHandler::ccls_call);
 | 
			
		||||
  Bind("$ccls/fileInfo", &MessageHandler::ccls_fileInfo);
 | 
			
		||||
  Bind("$ccls/info", &MessageHandler::ccls_info);
 | 
			
		||||
@ -157,39 +173,31 @@ MessageHandler::MessageHandler() {
 | 
			
		||||
  Bind("textDocument/codeAction", &MessageHandler::textDocument_codeAction);
 | 
			
		||||
  Bind("textDocument/codeLens", &MessageHandler::textDocument_codeLens);
 | 
			
		||||
  Bind("textDocument/completion", &MessageHandler::textDocument_completion);
 | 
			
		||||
  Bind("textDocument/declaration", &MessageHandler::textDocument_declaration);
 | 
			
		||||
  Bind("textDocument/definition", &MessageHandler::textDocument_definition);
 | 
			
		||||
  Bind("textDocument/didChange", &MessageHandler::textDocument_didChange);
 | 
			
		||||
  Bind("textDocument/didClose", &MessageHandler::textDocument_didClose);
 | 
			
		||||
  Bind("textDocument/didOpen", &MessageHandler::textDocument_didOpen);
 | 
			
		||||
  Bind("textDocument/didSave", &MessageHandler::textDocument_didSave);
 | 
			
		||||
  Bind("textDocument/documentHighlight",
 | 
			
		||||
       &MessageHandler::textDocument_documentHighlight);
 | 
			
		||||
  Bind("textDocument/documentHighlight", &MessageHandler::textDocument_documentHighlight);
 | 
			
		||||
  Bind("textDocument/documentLink", &MessageHandler::textDocument_documentLink);
 | 
			
		||||
  Bind("textDocument/documentSymbol",
 | 
			
		||||
       &MessageHandler::textDocument_documentSymbol);
 | 
			
		||||
  Bind("textDocument/documentSymbol", &MessageHandler::textDocument_documentSymbol);
 | 
			
		||||
  Bind("textDocument/foldingRange", &MessageHandler::textDocument_foldingRange);
 | 
			
		||||
  Bind("textDocument/formatting", &MessageHandler::textDocument_formatting);
 | 
			
		||||
  Bind("textDocument/hover", &MessageHandler::textDocument_hover);
 | 
			
		||||
  Bind("textDocument/implementation",
 | 
			
		||||
       &MessageHandler::textDocument_implementation);
 | 
			
		||||
  Bind("textDocument/onTypeFormatting",
 | 
			
		||||
       &MessageHandler::textDocument_onTypeFormatting);
 | 
			
		||||
  Bind("textDocument/rangeFormatting",
 | 
			
		||||
       &MessageHandler::textDocument_rangeFormatting);
 | 
			
		||||
  Bind("textDocument/implementation", &MessageHandler::textDocument_implementation);
 | 
			
		||||
  Bind("textDocument/onTypeFormatting", &MessageHandler::textDocument_onTypeFormatting);
 | 
			
		||||
  Bind("textDocument/rangeFormatting", &MessageHandler::textDocument_rangeFormatting);
 | 
			
		||||
  Bind("textDocument/references", &MessageHandler::textDocument_references);
 | 
			
		||||
  Bind("textDocument/rename", &MessageHandler::textDocument_rename);
 | 
			
		||||
  Bind("textDocument/signatureHelp",
 | 
			
		||||
       &MessageHandler::textDocument_signatureHelp);
 | 
			
		||||
  Bind("textDocument/typeDefinition",
 | 
			
		||||
       &MessageHandler::textDocument_typeDefinition);
 | 
			
		||||
  Bind("workspace/didChangeConfiguration",
 | 
			
		||||
       &MessageHandler::workspace_didChangeConfiguration);
 | 
			
		||||
  Bind("workspace/didChangeWatchedFiles",
 | 
			
		||||
       &MessageHandler::workspace_didChangeWatchedFiles);
 | 
			
		||||
  Bind("workspace/didChangeWorkspaceFolders",
 | 
			
		||||
       &MessageHandler::workspace_didChangeWorkspaceFolders);
 | 
			
		||||
  Bind("textDocument/signatureHelp", &MessageHandler::textDocument_signatureHelp);
 | 
			
		||||
  Bind("textDocument/typeDefinition", &MessageHandler::textDocument_typeDefinition);
 | 
			
		||||
  Bind("workspace/didChangeConfiguration", &MessageHandler::workspace_didChangeConfiguration);
 | 
			
		||||
  Bind("workspace/didChangeWatchedFiles", &MessageHandler::workspace_didChangeWatchedFiles);
 | 
			
		||||
  Bind("workspace/didChangeWorkspaceFolders", &MessageHandler::workspace_didChangeWorkspaceFolders);
 | 
			
		||||
  Bind("workspace/executeCommand", &MessageHandler::workspace_executeCommand);
 | 
			
		||||
  Bind("workspace/symbol", &MessageHandler::workspace_symbol);
 | 
			
		||||
  // clang-format on
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MessageHandler::Run(InMessage &msg) {
 | 
			
		||||
 | 
			
		||||
@ -177,6 +177,7 @@ REFLECT_STRUCT(ResponseError, code, message);
 | 
			
		||||
REFLECT_STRUCT(Position, line, character);
 | 
			
		||||
REFLECT_STRUCT(lsRange, start, end);
 | 
			
		||||
REFLECT_STRUCT(Location, uri, range);
 | 
			
		||||
REFLECT_STRUCT(LocationLink, targetUri, targetRange, targetSelectionRange);
 | 
			
		||||
REFLECT_UNDERLYING_B(SymbolKind);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentIdentifier, uri);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
 | 
			
		||||
@ -198,6 +199,7 @@ struct ReplyOnce {
 | 
			
		||||
      pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
 | 
			
		||||
  }
 | 
			
		||||
  void NotReady(bool file);
 | 
			
		||||
  void ReplyLocationLink(std::vector<LocationLink> &result);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MessageHandler {
 | 
			
		||||
@ -240,6 +242,7 @@ private:
 | 
			
		||||
  void textDocument_codeAction(CodeActionParam &, ReplyOnce &);
 | 
			
		||||
  void textDocument_codeLens(TextDocumentParam &, ReplyOnce &);
 | 
			
		||||
  void textDocument_completion(CompletionParam &, ReplyOnce &);
 | 
			
		||||
  void textDocument_declaration(TextDocumentPositionParam &, ReplyOnce &);
 | 
			
		||||
  void textDocument_definition(TextDocumentPositionParam &, ReplyOnce &);
 | 
			
		||||
  void textDocument_didChange(TextDocumentDidChangeParam &);
 | 
			
		||||
  void textDocument_didClose(TextDocumentParam &);
 | 
			
		||||
 | 
			
		||||
@ -39,12 +39,14 @@ void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
 | 
			
		||||
      usr = def->type;
 | 
			
		||||
      [[fallthrough]];
 | 
			
		||||
    }
 | 
			
		||||
    case Kind::Type:
 | 
			
		||||
      result = GetLsLocations(
 | 
			
		||||
          db, wfiles,
 | 
			
		||||
          GetVarDeclarations(db, db->Type(usr).instances, param.kind));
 | 
			
		||||
    case Kind::Type: {
 | 
			
		||||
      for (DeclRef dr :
 | 
			
		||||
           GetVarDeclarations(db, db->Type(usr).instances, param.kind))
 | 
			
		||||
        if (auto loc = GetLocationLink(db, wfiles, dr))
 | 
			
		||||
          result.push_back(Location(std::move(loc)));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  reply(result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,7 @@ struct ServerCap {
 | 
			
		||||
  struct SignatureHelpOptions {
 | 
			
		||||
    std::vector<const char *> triggerCharacters = {"(", ","};
 | 
			
		||||
  } signatureHelpProvider;
 | 
			
		||||
  bool declarationProvider = true;
 | 
			
		||||
  bool definitionProvider = true;
 | 
			
		||||
  bool typeDefinitionProvider = true;
 | 
			
		||||
  bool implementationProvider = true;
 | 
			
		||||
@ -109,7 +110,7 @@ REFLECT_STRUCT(ServerCap::Workspace::WorkspaceFolders, supported,
 | 
			
		||||
               changeNotifications);
 | 
			
		||||
REFLECT_STRUCT(ServerCap::Workspace, workspaceFolders);
 | 
			
		||||
REFLECT_STRUCT(ServerCap, textDocumentSync, hoverProvider, completionProvider,
 | 
			
		||||
               signatureHelpProvider, definitionProvider,
 | 
			
		||||
               signatureHelpProvider, declarationProvider, definitionProvider,
 | 
			
		||||
               implementationProvider, typeDefinitionProvider,
 | 
			
		||||
               referencesProvider, documentHighlightProvider,
 | 
			
		||||
               documentSymbolProvider, workspaceSymbolProvider,
 | 
			
		||||
@ -161,6 +162,11 @@ struct TextDocumentClientCap {
 | 
			
		||||
    } completionItem;
 | 
			
		||||
  } completion;
 | 
			
		||||
 | 
			
		||||
  // Ignore declaration, implementation, typeDefinition
 | 
			
		||||
  struct LinkSupport {
 | 
			
		||||
    bool linkSupport = false;
 | 
			
		||||
  } definition;
 | 
			
		||||
 | 
			
		||||
  struct DocumentSymbol {
 | 
			
		||||
    bool hierarchicalDocumentSymbolSupport = false;
 | 
			
		||||
  } documentSymbol;
 | 
			
		||||
@ -171,7 +177,8 @@ REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem,
 | 
			
		||||
REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
 | 
			
		||||
               hierarchicalDocumentSymbolSupport);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentClientCap, completion, documentSymbol);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport);
 | 
			
		||||
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol);
 | 
			
		||||
 | 
			
		||||
struct ClientCap {
 | 
			
		||||
  WorkspaceClientCap workspace;
 | 
			
		||||
@ -272,11 +279,13 @@ void Initialize(MessageHandler *m, InitializeParam ¶m, ReplyOnce &reply) {
 | 
			
		||||
 | 
			
		||||
  // Client capabilities
 | 
			
		||||
  const auto &capabilities = param.capabilities;
 | 
			
		||||
  g_config->client.snippetSupport &=
 | 
			
		||||
      capabilities.textDocument.completion.completionItem.snippetSupport;
 | 
			
		||||
  g_config->client.hierarchicalDocumentSymbolSupport &=
 | 
			
		||||
      capabilities.textDocument.documentSymbol
 | 
			
		||||
          .hierarchicalDocumentSymbolSupport;
 | 
			
		||||
  g_config->client.linkSupport &=
 | 
			
		||||
      capabilities.textDocument.definition.linkSupport;
 | 
			
		||||
  g_config->client.snippetSupport &=
 | 
			
		||||
      capabilities.textDocument.completion.completionItem.snippetSupport;
 | 
			
		||||
 | 
			
		||||
  // Ensure there is a resource directory.
 | 
			
		||||
  if (g_config->clang.resourceDir.empty())
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,27 @@ std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
void MessageHandler::textDocument_declaration(TextDocumentPositionParam ¶m,
 | 
			
		||||
                                              ReplyOnce &reply) {
 | 
			
		||||
  int file_id;
 | 
			
		||||
  QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
 | 
			
		||||
  WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
 | 
			
		||||
  if (!wf) {
 | 
			
		||||
    reply.NotReady(file);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<LocationLink> result;
 | 
			
		||||
  Position &ls_pos = param.position;
 | 
			
		||||
  for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
 | 
			
		||||
    for (DeclRef dr : GetNonDefDeclarations(db, sym))
 | 
			
		||||
      if (!(dr.file_id == file_id &&
 | 
			
		||||
            dr.range.Contains(ls_pos.line, ls_pos.character)))
 | 
			
		||||
        if (auto loc = GetLocationLink(db, wfiles, dr))
 | 
			
		||||
          result.push_back(loc);
 | 
			
		||||
  reply.ReplyLocationLink(result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
 | 
			
		||||
                                             ReplyOnce &reply) {
 | 
			
		||||
  int file_id;
 | 
			
		||||
@ -43,54 +64,52 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<Location> result;
 | 
			
		||||
  Maybe<Use> on_def;
 | 
			
		||||
  std::vector<LocationLink> result;
 | 
			
		||||
  Maybe<DeclRef> on_def;
 | 
			
		||||
  Position &ls_pos = param.position;
 | 
			
		||||
 | 
			
		||||
  for (SymbolRef sym : FindSymbolsAtLocation(wf, file, ls_pos, true)) {
 | 
			
		||||
    // Special cases which are handled:
 | 
			
		||||
    //  - symbol has declaration but no definition (ie, pure virtual)
 | 
			
		||||
    //  - goto declaration while in definition of recursive type
 | 
			
		||||
    std::vector<Use> uses;
 | 
			
		||||
    std::vector<DeclRef> drs;
 | 
			
		||||
    EachEntityDef(db, sym, [&](const auto &def) {
 | 
			
		||||
      if (def.spell) {
 | 
			
		||||
        Use spell = *def.spell;
 | 
			
		||||
        DeclRef spell = *def.spell;
 | 
			
		||||
        if (spell.file_id == file_id &&
 | 
			
		||||
            spell.range.Contains(ls_pos.line, ls_pos.character)) {
 | 
			
		||||
          on_def = spell;
 | 
			
		||||
          uses.clear();
 | 
			
		||||
          drs.clear();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        uses.push_back(spell);
 | 
			
		||||
        drs.push_back(spell);
 | 
			
		||||
      }
 | 
			
		||||
      return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // |uses| is empty if on a declaration/definition, otherwise it includes
 | 
			
		||||
    // all declarations/definitions.
 | 
			
		||||
    if (uses.empty()) {
 | 
			
		||||
      for (Use use : GetNonDefDeclarationTargets(db, sym))
 | 
			
		||||
        if (!(use.file_id == file_id &&
 | 
			
		||||
              use.range.Contains(ls_pos.line, ls_pos.character)))
 | 
			
		||||
          uses.push_back(use);
 | 
			
		||||
    if (drs.empty()) {
 | 
			
		||||
      for (DeclRef dr : GetNonDefDeclarationTargets(db, sym))
 | 
			
		||||
        if (!(dr.file_id == file_id &&
 | 
			
		||||
              dr.range.Contains(ls_pos.line, ls_pos.character)))
 | 
			
		||||
          drs.push_back(dr);
 | 
			
		||||
      // There is no declaration but the cursor is on a definition.
 | 
			
		||||
      if (uses.empty() && on_def)
 | 
			
		||||
        uses.push_back(*on_def);
 | 
			
		||||
      if (drs.empty() && on_def)
 | 
			
		||||
        drs.push_back(*on_def);
 | 
			
		||||
    }
 | 
			
		||||
    auto locs = GetLsLocations(db, wfiles, uses);
 | 
			
		||||
    result.insert(result.end(), locs.begin(), locs.end());
 | 
			
		||||
    for (DeclRef dr : drs)
 | 
			
		||||
      if (auto loc = GetLocationLink(db, wfiles, dr))
 | 
			
		||||
        result.push_back(loc);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (result.size()) {
 | 
			
		||||
    std::sort(result.begin(), result.end());
 | 
			
		||||
    result.erase(std::unique(result.begin(), result.end()), result.end());
 | 
			
		||||
  } else {
 | 
			
		||||
  if (result.empty()) {
 | 
			
		||||
    Maybe<Range> range;
 | 
			
		||||
    // Check #include
 | 
			
		||||
    for (const IndexInclude &include : file->def->includes) {
 | 
			
		||||
      if (include.line == ls_pos.line) {
 | 
			
		||||
        result.push_back(
 | 
			
		||||
            Location{DocumentUri::FromPath(include.resolved_path)});
 | 
			
		||||
            {DocumentUri::FromPath(include.resolved_path).raw_uri});
 | 
			
		||||
        range = {{0, 0}, {0, 0}};
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
@ -148,13 +167,13 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
 | 
			
		||||
      if (best_sym.kind != Kind::Invalid) {
 | 
			
		||||
        Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym);
 | 
			
		||||
        assert(dr);
 | 
			
		||||
        if (auto loc = GetLsLocation(db, wfiles, *dr))
 | 
			
		||||
          result.push_back(*loc);
 | 
			
		||||
        if (auto loc = GetLocationLink(db, wfiles, *dr))
 | 
			
		||||
          result.push_back(loc);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  reply(result);
 | 
			
		||||
  reply.ReplyLocationLink(result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MessageHandler::textDocument_typeDefinition(
 | 
			
		||||
@ -166,17 +185,16 @@ void MessageHandler::textDocument_typeDefinition(
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<Location> result;
 | 
			
		||||
  std::vector<LocationLink> result;
 | 
			
		||||
  auto Add = [&](const QueryType &type) {
 | 
			
		||||
    for (const auto &def : type.def)
 | 
			
		||||
      if (def.spell) {
 | 
			
		||||
        if (auto ls_loc = GetLsLocation(db, wfiles, *def.spell))
 | 
			
		||||
          result.push_back(*ls_loc);
 | 
			
		||||
      }
 | 
			
		||||
      if (def.spell)
 | 
			
		||||
        if (auto loc = GetLocationLink(db, wfiles, *def.spell))
 | 
			
		||||
          result.push_back(loc);
 | 
			
		||||
    if (result.empty())
 | 
			
		||||
      for (const DeclRef &dr : type.declarations)
 | 
			
		||||
        if (auto ls_loc = GetLsLocation(db, wfiles, dr))
 | 
			
		||||
          result.push_back(*ls_loc);
 | 
			
		||||
        if (auto loc = GetLocationLink(db, wfiles, dr))
 | 
			
		||||
          result.push_back(loc);
 | 
			
		||||
  };
 | 
			
		||||
  for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
 | 
			
		||||
    switch (sym.kind) {
 | 
			
		||||
@ -199,8 +217,6 @@ void MessageHandler::textDocument_typeDefinition(
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::sort(result.begin(), result.end());
 | 
			
		||||
  result.erase(std::unique(result.begin(), result.end()), result.end());
 | 
			
		||||
  reply(result);
 | 
			
		||||
  reply.ReplyLocationLink(result);
 | 
			
		||||
}
 | 
			
		||||
} // namespace ccls
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/query.cc
									
									
									
									
									
								
							@ -520,9 +520,9 @@ std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
			
		||||
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
			
		||||
  return GetDeclarations(db->type_usr, db->types, usrs);
 | 
			
		||||
}
 | 
			
		||||
std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
 | 
			
		||||
                                    unsigned kind) {
 | 
			
		||||
  std::vector<Use> ret;
 | 
			
		||||
std::vector<DeclRef> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
 | 
			
		||||
                                        unsigned kind) {
 | 
			
		||||
  std::vector<DeclRef> ret;
 | 
			
		||||
  ret.reserve(usrs.size());
 | 
			
		||||
  for (Usr usr : usrs) {
 | 
			
		||||
    QueryVar &var = db->Var(usr);
 | 
			
		||||
@ -669,17 +669,18 @@ std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
			
		||||
  return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
			
		||||
                                     const std::vector<Use> &uses) {
 | 
			
		||||
  std::vector<Location> ret;
 | 
			
		||||
  for (Use use : uses)
 | 
			
		||||
    if (auto loc = GetLsLocation(db, wfiles, use))
 | 
			
		||||
      ret.push_back(*loc);
 | 
			
		||||
  std::sort(ret.begin(), ret.end());
 | 
			
		||||
  ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
 | 
			
		||||
  if (ret.size() > g_config->xref.maxNum)
 | 
			
		||||
    ret.resize(g_config->xref.maxNum);
 | 
			
		||||
  return ret;
 | 
			
		||||
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr) {
 | 
			
		||||
  std::string path;
 | 
			
		||||
  DocumentUri uri = GetLsDocumentUri(db, dr.file_id, &path);
 | 
			
		||||
  if (auto range = GetLsRange(wfiles->GetFile(path), dr.range))
 | 
			
		||||
    if (auto extent = GetLsRange(wfiles->GetFile(path), dr.extent)) {
 | 
			
		||||
      LocationLink ret;
 | 
			
		||||
      ret.targetUri = uri.raw_uri;
 | 
			
		||||
      ret.targetSelectionRange = *range;
 | 
			
		||||
      ret.targetRange = extent->Includes(*range) ? *extent : *range;
 | 
			
		||||
      return ret;
 | 
			
		||||
    }
 | 
			
		||||
  return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
 | 
			
		||||
 | 
			
		||||
@ -189,7 +189,7 @@ Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
 | 
			
		||||
// for each id.
 | 
			
		||||
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
 | 
			
		||||
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
 | 
			
		||||
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
 | 
			
		||||
std::vector<DeclRef> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
 | 
			
		||||
 | 
			
		||||
// Get non-defining declarations.
 | 
			
		||||
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
 | 
			
		||||
@ -204,8 +204,8 @@ DocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
			
		||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
 | 
			
		||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
			
		||||
                                        SymbolRef sym, int file_id);
 | 
			
		||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
			
		||||
                                           const std::vector<Use> &uses);
 | 
			
		||||
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr);
 | 
			
		||||
 | 
			
		||||
// Returns a symbol. The symbol will *NOT* have a location assigned.
 | 
			
		||||
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
			
		||||
                                                 bool detailed);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user