mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 14:17:07 +00:00 
			
		
		
		
	Redesign SymbolRef, Ref, Use
Remove lsLocationEx
This commit is contained in:
		
							parent
							
								
									38feb8d277
								
							
						
					
					
						commit
						6ec032c2a0
					
				@ -249,8 +249,6 @@ struct Config {
 | 
				
			|||||||
  } workspaceSymbol;
 | 
					  } workspaceSymbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct Xref {
 | 
					  struct Xref {
 | 
				
			||||||
    // If true, |Location[]| response will include lexical container.
 | 
					 | 
				
			||||||
    bool container = false;
 | 
					 | 
				
			||||||
    // Maximum number of definition/reference/... results.
 | 
					    // Maximum number of definition/reference/... results.
 | 
				
			||||||
    int maxNum = 2000;
 | 
					    int maxNum = 2000;
 | 
				
			||||||
  } xref;
 | 
					  } xref;
 | 
				
			||||||
@ -274,7 +272,7 @@ MAKE_REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
 | 
				
			|||||||
                    multiVersionWhitelist, onChange, threads, trackDependency,
 | 
					                    multiVersionWhitelist, onChange, threads, trackDependency,
 | 
				
			||||||
                    whitelist);
 | 
					                    whitelist);
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
 | 
					MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
 | 
					MAKE_REFLECT_STRUCT(Config::Xref, maxNum);
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
 | 
					MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
 | 
				
			||||||
                    compilationDatabaseDirectory, cacheDirectory, cacheFormat,
 | 
					                    compilationDatabaseDirectory, cacheDirectory, cacheFormat,
 | 
				
			||||||
                    clang, client, codeLens, completion, diagnostics, highlight,
 | 
					                    clang, client, codeLens, completion, diagnostics, highlight,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										289
									
								
								src/indexer.cc
									
									
									
									
									
								
							
							
						
						
									
										289
									
								
								src/indexer.cc
									
									
									
									
									
								
							@ -117,50 +117,109 @@ StringRef GetSourceInRange(const SourceManager &SM, const LangOptions &LangOpts,
 | 
				
			|||||||
                        BInfo.second);
 | 
					                        BInfo.second);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SymbolKind GetSymbolKind(const Decl *D) {
 | 
					SymbolKind GetSymbolKind(const Decl *D, lsSymbolKind &kind) {
 | 
				
			||||||
  switch (D->getKind()) {
 | 
					  switch (D->getKind()) {
 | 
				
			||||||
  case Decl::TranslationUnit:
 | 
					  case Decl::LinkageSpec:
 | 
				
			||||||
    return SymbolKind::File;
 | 
					    return SymbolKind::Invalid;
 | 
				
			||||||
  case Decl::ObjCMethod:
 | 
					 | 
				
			||||||
  case Decl::FunctionTemplate:
 | 
					 | 
				
			||||||
  case Decl::Function:
 | 
					 | 
				
			||||||
  case Decl::CXXMethod:
 | 
					 | 
				
			||||||
  case Decl::CXXConstructor:
 | 
					 | 
				
			||||||
  case Decl::CXXConversion:
 | 
					 | 
				
			||||||
  case Decl::CXXDestructor:
 | 
					 | 
				
			||||||
    return SymbolKind::Func;
 | 
					 | 
				
			||||||
  case Decl::Namespace:
 | 
					  case Decl::Namespace:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Namespace;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::NamespaceAlias:
 | 
					  case Decl::NamespaceAlias:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::TypeAlias;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::ObjCCategory:
 | 
					  case Decl::ObjCCategory:
 | 
				
			||||||
 | 
					  case Decl::ObjCImplementation:
 | 
				
			||||||
  case Decl::ObjCInterface:
 | 
					  case Decl::ObjCInterface:
 | 
				
			||||||
  case Decl::ObjCProtocol:
 | 
					  case Decl::ObjCProtocol:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Interface;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
 | 
					  case Decl::ObjCMethod:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Method;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
 | 
					  case Decl::ObjCProperty:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Property;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::ClassTemplate:
 | 
					  case Decl::ClassTemplate:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Class;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
 | 
					  case Decl::FunctionTemplate:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Function;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
  case Decl::TypeAliasTemplate:
 | 
					  case Decl::TypeAliasTemplate:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::TypeAlias;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
 | 
					  case Decl::VarTemplate:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Variable;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
  case Decl::TemplateTemplateParm:
 | 
					  case Decl::TemplateTemplateParm:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::TypeParameter;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::Enum:
 | 
					  case Decl::Enum:
 | 
				
			||||||
  case Decl::Record:
 | 
					    kind = lsSymbolKind::Enum;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::CXXRecord:
 | 
					  case Decl::CXXRecord:
 | 
				
			||||||
 | 
					  case Decl::Record:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Class;
 | 
				
			||||||
 | 
					    // spec has no Union, use Class
 | 
				
			||||||
 | 
					    if (auto *RD = dyn_cast<RecordDecl>(D))
 | 
				
			||||||
 | 
					      if (RD->getTagKind() == TTK_Struct)
 | 
				
			||||||
 | 
					        kind = lsSymbolKind::Struct;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::ClassTemplateSpecialization:
 | 
					  case Decl::ClassTemplateSpecialization:
 | 
				
			||||||
  case Decl::ClassTemplatePartialSpecialization:
 | 
					  case Decl::ClassTemplatePartialSpecialization:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Class;
 | 
				
			||||||
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::TypeAlias:
 | 
					  case Decl::TypeAlias:
 | 
				
			||||||
  case Decl::Typedef:
 | 
					  case Decl::Typedef:
 | 
				
			||||||
  case Decl::UnresolvedUsingTypename:
 | 
					  case Decl::UnresolvedUsingTypename:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::TypeAlias;
 | 
				
			||||||
    return SymbolKind::Type;
 | 
					    return SymbolKind::Type;
 | 
				
			||||||
  case Decl::ObjCProperty:
 | 
					 | 
				
			||||||
  case Decl::VarTemplate:
 | 
					 | 
				
			||||||
  case Decl::Binding:
 | 
					  case Decl::Binding:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Variable;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
  case Decl::Field:
 | 
					  case Decl::Field:
 | 
				
			||||||
  case Decl::ObjCIvar:
 | 
					  case Decl::ObjCIvar:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Field;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
 | 
					  case Decl::Function:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Function;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
 | 
					  case Decl::CXXMethod: {
 | 
				
			||||||
 | 
					    const auto *MD = cast<CXXMethodDecl>(D);
 | 
				
			||||||
 | 
					    kind = MD->isStatic() ? lsSymbolKind::StaticMethod : lsSymbolKind::Method;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  case Decl::CXXConstructor:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Constructor;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
 | 
					  case Decl::CXXConversion:
 | 
				
			||||||
 | 
					  case Decl::CXXDestructor:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Method;
 | 
				
			||||||
 | 
					    return SymbolKind::Func;
 | 
				
			||||||
  case Decl::Var:
 | 
					  case Decl::Var:
 | 
				
			||||||
  case Decl::ParmVar:
 | 
					 | 
				
			||||||
  case Decl::ImplicitParam:
 | 
					 | 
				
			||||||
  case Decl::Decomposition:
 | 
					  case Decl::Decomposition:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Variable;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
 | 
					  case Decl::ImplicitParam:
 | 
				
			||||||
 | 
					  case Decl::ParmVar:
 | 
				
			||||||
 | 
					    // ccls extension
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Parameter;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
  case Decl::VarTemplateSpecialization:
 | 
					  case Decl::VarTemplateSpecialization:
 | 
				
			||||||
  case Decl::VarTemplatePartialSpecialization:
 | 
					  case Decl::VarTemplatePartialSpecialization:
 | 
				
			||||||
  case Decl::EnumConstant:
 | 
					    kind = lsSymbolKind::Variable;
 | 
				
			||||||
  case Decl::UnresolvedUsingValue:
 | 
					 | 
				
			||||||
    return SymbolKind::Var;
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
 | 
					  case Decl::EnumConstant:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::EnumMember;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
 | 
					  case Decl::UnresolvedUsingValue:
 | 
				
			||||||
 | 
					    kind = lsSymbolKind::Variable;
 | 
				
			||||||
 | 
					    return SymbolKind::Var;
 | 
				
			||||||
 | 
					  case Decl::TranslationUnit:
 | 
				
			||||||
 | 
					    return SymbolKind::Invalid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
 | 
					    LOG_S(INFO) << "unhandled " << int(D->getKind());
 | 
				
			||||||
    return SymbolKind::Invalid;
 | 
					    return SymbolKind::Invalid;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -421,23 +480,6 @@ public:
 | 
				
			|||||||
    return it->second.usr;
 | 
					    return it->second.usr;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Use GetUse(IndexFile *db, int lid, Range range, const DeclContext *DC,
 | 
					 | 
				
			||||||
             Role role) const {
 | 
					 | 
				
			||||||
    if (!DC)
 | 
					 | 
				
			||||||
      return {{range, 0, SymbolKind::File, role}, lid};
 | 
					 | 
				
			||||||
    const Decl *D = cast<Decl>(DC);
 | 
					 | 
				
			||||||
    switch (GetSymbolKind(D)) {
 | 
					 | 
				
			||||||
    case SymbolKind::Func:
 | 
					 | 
				
			||||||
      return {{range, db->ToFunc(GetUsr(D)).usr, SymbolKind::Func, role}, lid};
 | 
					 | 
				
			||||||
    case SymbolKind::Type:
 | 
					 | 
				
			||||||
      return {{range, db->ToType(GetUsr(D)).usr, SymbolKind::Type, role}, lid};
 | 
					 | 
				
			||||||
    case SymbolKind::Var:
 | 
					 | 
				
			||||||
      return {{range, db->ToVar(GetUsr(D)).usr, SymbolKind::Var, role}, lid};
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      return {{range, 0, SymbolKind::File, role}, lid};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  PrintingPolicy GetDefaultPolicy() const {
 | 
					  PrintingPolicy GetDefaultPolicy() const {
 | 
				
			||||||
    PrintingPolicy PP(Ctx->getLangOpts());
 | 
					    PrintingPolicy PP(Ctx->getLangOpts());
 | 
				
			||||||
    PP.AnonymousTagLocations = false;
 | 
					    PP.AnonymousTagLocations = false;
 | 
				
			||||||
@ -590,7 +632,7 @@ public:
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    Range spell =
 | 
					    Range spell =
 | 
				
			||||||
        FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
 | 
					        FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
 | 
				
			||||||
    Use use{{spell, 0, SymbolKind::File, Role::Dynamic}, lid};
 | 
					    Use use{{spell, Role::Dynamic}, lid};
 | 
				
			||||||
    switch (kind) {
 | 
					    switch (kind) {
 | 
				
			||||||
    case SymbolKind::Func:
 | 
					    case SymbolKind::Func:
 | 
				
			||||||
      db->ToFunc(usr).uses.push_back(use);
 | 
					      db->ToFunc(usr).uses.push_back(use);
 | 
				
			||||||
@ -704,7 +746,8 @@ public:
 | 
				
			|||||||
    IndexFunc *func = nullptr;
 | 
					    IndexFunc *func = nullptr;
 | 
				
			||||||
    IndexType *type = nullptr;
 | 
					    IndexType *type = nullptr;
 | 
				
			||||||
    IndexVar *var = nullptr;
 | 
					    IndexVar *var = nullptr;
 | 
				
			||||||
    SymbolKind kind = GetSymbolKind(D);
 | 
					    lsSymbolKind ls_kind;
 | 
				
			||||||
 | 
					    SymbolKind kind = GetSymbolKind(D, ls_kind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (is_def)
 | 
					    if (is_def)
 | 
				
			||||||
      switch (D->getKind()) {
 | 
					      switch (D->getKind()) {
 | 
				
			||||||
@ -734,19 +777,20 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    auto do_def_decl = [&](auto *entity) {
 | 
					    auto do_def_decl = [&](auto *entity) {
 | 
				
			||||||
      if (is_def) {
 | 
					      if (is_def) {
 | 
				
			||||||
        entity->def.spell = GetUse(db, lid, loc, SemDC, role);
 | 
					        entity->def.spell = {{loc, role}, lid};
 | 
				
			||||||
        SourceRange R = OrigD->getSourceRange();
 | 
					        SourceRange R = OrigD->getSourceRange();
 | 
				
			||||||
        entity->def.extent =
 | 
					        entity->def.extent = {
 | 
				
			||||||
            GetUse(db, lid,
 | 
					            {R.getBegin().isFileID() ? FromTokenRange(SM, Lang, R) : loc,
 | 
				
			||||||
                   R.getBegin().isFileID() ? FromTokenRange(SM, Lang, R) : loc,
 | 
					             Role::None},
 | 
				
			||||||
                   LexDC, Role::None);
 | 
					            lid};
 | 
				
			||||||
 | 
					        GetSymbolKind(cast<Decl>(SemDC), entity->def.parent_kind);
 | 
				
			||||||
      } else if (is_decl) {
 | 
					      } else if (is_decl) {
 | 
				
			||||||
        DeclRef &dr = entity->declarations.emplace_back();
 | 
					        DeclRef &dr = entity->declarations.emplace_back();
 | 
				
			||||||
        static_cast<Use&>(dr) = GetUse(db, lid, loc, LexDC, role);
 | 
					        static_cast<Use&>(dr) = {{loc, role}, lid};
 | 
				
			||||||
        SourceRange R = OrigD->getSourceRange();
 | 
					        SourceRange R = OrigD->getSourceRange();
 | 
				
			||||||
        dr.extent = R.getBegin().isFileID() ? FromTokenRange(SM, Lang, R) : loc;
 | 
					        dr.extent = R.getBegin().isFileID() ? FromTokenRange(SM, Lang, R) : loc;
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        entity->uses.push_back(GetUse(db, lid, loc, LexDC, role));
 | 
					        entity->uses.push_back({{loc, role}, lid});
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (entity->def.comments[0] == '\0' && g_config->index.comments)
 | 
					      if (entity->def.comments[0] == '\0' && g_config->index.comments)
 | 
				
			||||||
@ -761,6 +805,7 @@ public:
 | 
				
			|||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    case SymbolKind::Func:
 | 
					    case SymbolKind::Func:
 | 
				
			||||||
      func = &db->ToFunc(usr);
 | 
					      func = &db->ToFunc(usr);
 | 
				
			||||||
 | 
					      func->def.kind = ls_kind;
 | 
				
			||||||
      // Mark as Role::Implicit to span one more column to the left/right.
 | 
					      // Mark as Role::Implicit to span one more column to the left/right.
 | 
				
			||||||
      if (!is_def && !is_decl &&
 | 
					      if (!is_def && !is_decl &&
 | 
				
			||||||
          (D->getKind() == Decl::CXXConstructor ||
 | 
					          (D->getKind() == Decl::CXXConstructor ||
 | 
				
			||||||
@ -773,17 +818,18 @@ public:
 | 
				
			|||||||
        SetName(D, info->short_name, info->qualified, func->def);
 | 
					        SetName(D, info->short_name, info->qualified, func->def);
 | 
				
			||||||
      if (is_def || is_decl) {
 | 
					      if (is_def || is_decl) {
 | 
				
			||||||
        const Decl *DC = cast<Decl>(SemDC);
 | 
					        const Decl *DC = cast<Decl>(SemDC);
 | 
				
			||||||
        if (GetSymbolKind(DC) == SymbolKind::Type)
 | 
					        if (GetSymbolKind(DC, ls_kind) == SymbolKind::Type)
 | 
				
			||||||
          db->ToType(GetUsr(DC)).def.funcs.push_back(usr);
 | 
					          db->ToType(GetUsr(DC)).def.funcs.push_back(usr);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        const Decl *DC = cast<Decl>(LexDC);
 | 
					        const Decl *DC = cast<Decl>(LexDC);
 | 
				
			||||||
        if (GetSymbolKind(DC) == SymbolKind::Func)
 | 
					        if (GetSymbolKind(DC, ls_kind) == SymbolKind::Func)
 | 
				
			||||||
          db->ToFunc(GetUsr(DC))
 | 
					          db->ToFunc(GetUsr(DC))
 | 
				
			||||||
              .def.callees.push_back({{loc, usr, SymbolKind::Func, role}});
 | 
					              .def.callees.push_back({loc, usr, SymbolKind::Func, role});
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SymbolKind::Type:
 | 
					    case SymbolKind::Type:
 | 
				
			||||||
      type = &db->ToType(usr);
 | 
					      type = &db->ToType(usr);
 | 
				
			||||||
 | 
					      type->def.kind = ls_kind;
 | 
				
			||||||
      do_def_decl(type);
 | 
					      do_def_decl(type);
 | 
				
			||||||
      if (Spell != Loc)
 | 
					      if (Spell != Loc)
 | 
				
			||||||
        AddMacroUse(db, SM, usr, SymbolKind::Type, Spell);
 | 
					        AddMacroUse(db, SM, usr, SymbolKind::Type, Spell);
 | 
				
			||||||
@ -791,12 +837,13 @@ public:
 | 
				
			|||||||
        SetName(D, info->short_name, info->qualified, type->def);
 | 
					        SetName(D, info->short_name, info->qualified, type->def);
 | 
				
			||||||
      if (is_def || is_decl) {
 | 
					      if (is_def || is_decl) {
 | 
				
			||||||
        const Decl *DC = cast<Decl>(SemDC);
 | 
					        const Decl *DC = cast<Decl>(SemDC);
 | 
				
			||||||
        if (GetSymbolKind(DC) == SymbolKind::Type)
 | 
					        if (GetSymbolKind(DC, ls_kind) == SymbolKind::Type)
 | 
				
			||||||
          db->ToType(GetUsr(DC)).def.types.push_back(usr);
 | 
					          db->ToType(GetUsr(DC)).def.types.push_back(usr);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case SymbolKind::Var:
 | 
					    case SymbolKind::Var:
 | 
				
			||||||
      var = &db->ToVar(usr);
 | 
					      var = &db->ToVar(usr);
 | 
				
			||||||
 | 
					      var->def.kind = ls_kind;
 | 
				
			||||||
      do_def_decl(var);
 | 
					      do_def_decl(var);
 | 
				
			||||||
      if (Spell != Loc)
 | 
					      if (Spell != Loc)
 | 
				
			||||||
        AddMacroUse(db, SM, usr, SymbolKind::Var, Spell);
 | 
					        AddMacroUse(db, SM, usr, SymbolKind::Var, Spell);
 | 
				
			||||||
@ -809,7 +856,7 @@ public:
 | 
				
			|||||||
        T = FD->getType();
 | 
					        T = FD->getType();
 | 
				
			||||||
      if (is_def || is_decl) {
 | 
					      if (is_def || is_decl) {
 | 
				
			||||||
        const Decl *DC = cast<Decl>(SemDC);
 | 
					        const Decl *DC = cast<Decl>(SemDC);
 | 
				
			||||||
        if (GetSymbolKind(DC) == SymbolKind::Func)
 | 
					        if (GetSymbolKind(DC, ls_kind) == SymbolKind::Func)
 | 
				
			||||||
          db->ToFunc(GetUsr(DC)).def.vars.push_back(usr);
 | 
					          db->ToFunc(GetUsr(DC)).def.vars.push_back(usr);
 | 
				
			||||||
        else if (auto *ND = dyn_cast<NamespaceDecl>(SemDC))
 | 
					        else if (auto *ND = dyn_cast<NamespaceDecl>(SemDC))
 | 
				
			||||||
          db->ToType(GetUsr(ND)).def.vars.emplace_back(usr, -1);
 | 
					          db->ToType(GetUsr(ND)).def.vars.emplace_back(usr, -1);
 | 
				
			||||||
@ -828,14 +875,15 @@ public:
 | 
				
			|||||||
                Usr usr1 = GetUsr(D1, &info1);
 | 
					                Usr usr1 = GetUsr(D1, &info1);
 | 
				
			||||||
                IndexType &type1 = db->ToType(usr1);
 | 
					                IndexType &type1 = db->ToType(usr1);
 | 
				
			||||||
                SourceLocation L1 = D1->getLocation();
 | 
					                SourceLocation L1 = D1->getLocation();
 | 
				
			||||||
                type1.def.spell =
 | 
					                type1.def.spell = {
 | 
				
			||||||
                    GetUse(db, lid, FromTokenRange(SM, Lang, {L1, L1}), SemDC,
 | 
					                    {FromTokenRange(SM, Lang, {L1, L1}), Role::Definition},
 | 
				
			||||||
                           Role::Definition);
 | 
					                    lid};
 | 
				
			||||||
                type1.def.extent = GetUse(db, lid, FromTokenRange(SM, Lang, R1),
 | 
					                type1.def.extent = {{FromTokenRange(SM, Lang, R1), Role::None},
 | 
				
			||||||
                                          LexDC, Role::None);
 | 
					                                    lid};
 | 
				
			||||||
                type1.def.detailed_name = Intern(info1->short_name);
 | 
					                type1.def.detailed_name = Intern(info1->short_name);
 | 
				
			||||||
                type1.def.short_name_size = int16_t(info1->short_name.size());
 | 
					                type1.def.short_name_size = int16_t(info1->short_name.size());
 | 
				
			||||||
                type1.def.kind = lsSymbolKind::TypeParameter;
 | 
					                type1.def.kind = lsSymbolKind::TypeParameter;
 | 
				
			||||||
 | 
					                type1.def.parent_kind = lsSymbolKind::Class;
 | 
				
			||||||
                var->def.type = usr1;
 | 
					                var->def.type = usr1;
 | 
				
			||||||
                type1.instances.push_back(usr);
 | 
					                type1.instances.push_back(usr);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -852,11 +900,11 @@ public:
 | 
				
			|||||||
        // e.g. lambda parameter
 | 
					        // e.g. lambda parameter
 | 
				
			||||||
        SourceLocation L = D->getLocation();
 | 
					        SourceLocation L = D->getLocation();
 | 
				
			||||||
        if (SM.getFileID(L) == LocFID) {
 | 
					        if (SM.getFileID(L) == LocFID) {
 | 
				
			||||||
          var->def.spell = GetUse(db, lid, FromTokenRange(SM, Lang, {L, L}),
 | 
					          var->def.spell = {
 | 
				
			||||||
                                  SemDC, Role::Definition);
 | 
					              {FromTokenRange(SM, Lang, {L, L}), Role::Definition}, lid};
 | 
				
			||||||
          var->def.extent =
 | 
					          var->def.extent = {
 | 
				
			||||||
              GetUse(db, lid, FromTokenRange(SM, Lang, D->getSourceRange()),
 | 
					              {FromTokenRange(SM, Lang, D->getSourceRange()), Role::None}, lid};
 | 
				
			||||||
                     LexDC, Role::None);
 | 
					          var->def.parent_kind = lsSymbolKind::Method;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
@ -864,7 +912,6 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    switch (D->getKind()) {
 | 
					    switch (D->getKind()) {
 | 
				
			||||||
    case Decl::Namespace:
 | 
					    case Decl::Namespace:
 | 
				
			||||||
      type->def.kind = lsSymbolKind::Namespace;
 | 
					 | 
				
			||||||
      if (D->isFirstDecl()) {
 | 
					      if (D->isFirstDecl()) {
 | 
				
			||||||
        auto *ND = cast<NamespaceDecl>(D);
 | 
					        auto *ND = cast<NamespaceDecl>(D);
 | 
				
			||||||
        auto *ND1 = cast<Decl>(ND->getParent());
 | 
					        auto *ND1 = cast<Decl>(ND->getParent());
 | 
				
			||||||
@ -876,7 +923,6 @@ public:
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case Decl::NamespaceAlias: {
 | 
					    case Decl::NamespaceAlias: {
 | 
				
			||||||
      type->def.kind = lsSymbolKind::TypeAlias;
 | 
					 | 
				
			||||||
      auto *NAD = cast<NamespaceAliasDecl>(D);
 | 
					      auto *NAD = cast<NamespaceAliasDecl>(D);
 | 
				
			||||||
      if (const NamespaceDecl *ND = NAD->getNamespace()) {
 | 
					      if (const NamespaceDecl *ND = NAD->getNamespace()) {
 | 
				
			||||||
        Usr usr1 = GetUsr(ND);
 | 
					        Usr usr1 = GetUsr(ND);
 | 
				
			||||||
@ -885,36 +931,6 @@ public:
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case Decl::ObjCCategory:
 | 
					 | 
				
			||||||
    case Decl::ObjCImplementation:
 | 
					 | 
				
			||||||
    case Decl::ObjCInterface:
 | 
					 | 
				
			||||||
    case Decl::ObjCProtocol:
 | 
					 | 
				
			||||||
      type->def.kind = lsSymbolKind::Interface;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::ObjCMethod:
 | 
					 | 
				
			||||||
      func->def.kind = lsSymbolKind::Method;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::ObjCProperty:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Property;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::ClassTemplate:
 | 
					 | 
				
			||||||
      type->def.kind = lsSymbolKind::Class;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::FunctionTemplate:
 | 
					 | 
				
			||||||
      func->def.kind = lsSymbolKind::Function;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::TypeAliasTemplate:
 | 
					 | 
				
			||||||
      type->def.kind = lsSymbolKind::TypeAlias;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::VarTemplate:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Variable;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::TemplateTemplateParm:
 | 
					 | 
				
			||||||
      type->def.kind = lsSymbolKind::TypeParameter;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::Enum:
 | 
					 | 
				
			||||||
      type->def.kind = lsSymbolKind::Enum;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::CXXRecord:
 | 
					    case Decl::CXXRecord:
 | 
				
			||||||
      if (is_def) {
 | 
					      if (is_def) {
 | 
				
			||||||
        auto *RD = dyn_cast<CXXRecordDecl>(D);
 | 
					        auto *RD = dyn_cast<CXXRecordDecl>(D);
 | 
				
			||||||
@ -930,9 +946,6 @@ public:
 | 
				
			|||||||
      [[fallthrough]];
 | 
					      [[fallthrough]];
 | 
				
			||||||
    case Decl::Record:
 | 
					    case Decl::Record:
 | 
				
			||||||
      if (auto *RD = dyn_cast<RecordDecl>(D)) {
 | 
					      if (auto *RD = dyn_cast<RecordDecl>(D)) {
 | 
				
			||||||
        // spec has no Union, use Class
 | 
					 | 
				
			||||||
        type->def.kind = RD->getTagKind() == TTK_Struct ? lsSymbolKind::Struct
 | 
					 | 
				
			||||||
                                                        : lsSymbolKind::Class;
 | 
					 | 
				
			||||||
        if (type->def.detailed_name[0] == '\0' && info->short_name.empty()) {
 | 
					        if (type->def.detailed_name[0] == '\0' && info->short_name.empty()) {
 | 
				
			||||||
          StringRef Tag;
 | 
					          StringRef Tag;
 | 
				
			||||||
          switch (RD->getTagKind()) {
 | 
					          switch (RD->getTagKind()) {
 | 
				
			||||||
@ -990,7 +1003,6 @@ public:
 | 
				
			|||||||
    case Decl::TypeAlias:
 | 
					    case Decl::TypeAlias:
 | 
				
			||||||
    case Decl::Typedef:
 | 
					    case Decl::Typedef:
 | 
				
			||||||
    case Decl::UnresolvedUsingTypename:
 | 
					    case Decl::UnresolvedUsingTypename:
 | 
				
			||||||
      type->def.kind = lsSymbolKind::TypeAlias;
 | 
					 | 
				
			||||||
      if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
 | 
					      if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
 | 
				
			||||||
        bool specialization = false;
 | 
					        bool specialization = false;
 | 
				
			||||||
        QualType T = TD->getUnderlyingType();
 | 
					        QualType T = TD->getUnderlyingType();
 | 
				
			||||||
@ -1002,29 +1014,14 @@ public:
 | 
				
			|||||||
          if (specialization) {
 | 
					          if (specialization) {
 | 
				
			||||||
            const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
 | 
					            const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
 | 
				
			||||||
            SourceLocation L1 = TSI->getTypeLoc().getBeginLoc();
 | 
					            SourceLocation L1 = TSI->getTypeLoc().getBeginLoc();
 | 
				
			||||||
            if (SM.getFileID(L1) == LocFID) {
 | 
					            if (SM.getFileID(L1) == LocFID)
 | 
				
			||||||
              Range loc1 = FromTokenRange(SM, Lang, {L1, L1});
 | 
					 | 
				
			||||||
              type1.uses.push_back(
 | 
					              type1.uses.push_back(
 | 
				
			||||||
                  GetUse(db, lid, loc1, LexDC, Role::Reference));
 | 
					                  {{FromTokenRange(SM, Lang, {L1, L1}), Role::Reference}, lid});
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case Decl::Binding:
 | 
					    case Decl::CXXMethod:
 | 
				
			||||||
      var->def.kind = lsSymbolKind::Variable;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::Field:
 | 
					 | 
				
			||||||
    case Decl::ObjCIvar:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Field;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::Function:
 | 
					 | 
				
			||||||
      func->def.kind = lsSymbolKind::Function;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::CXXMethod: {
 | 
					 | 
				
			||||||
      const auto *MD = cast<CXXMethodDecl>(D);
 | 
					 | 
				
			||||||
      func->def.kind =
 | 
					 | 
				
			||||||
          MD->isStatic() ? lsSymbolKind::StaticMethod : lsSymbolKind::Method;
 | 
					 | 
				
			||||||
      if (is_def || is_decl) {
 | 
					      if (is_def || is_decl) {
 | 
				
			||||||
        if (auto *ND = dyn_cast<NamedDecl>(D)) {
 | 
					        if (auto *ND = dyn_cast<NamedDecl>(D)) {
 | 
				
			||||||
          SmallVector<const NamedDecl *, 8> OverDecls;
 | 
					          SmallVector<const NamedDecl *, 8> OverDecls;
 | 
				
			||||||
@ -1037,29 +1034,7 @@ public:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    case Decl::CXXConstructor:
 | 
					 | 
				
			||||||
      func->def.kind = lsSymbolKind::Constructor;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::CXXConversion:
 | 
					 | 
				
			||||||
    case Decl::CXXDestructor:
 | 
					 | 
				
			||||||
      func->def.kind = lsSymbolKind::Method;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::Var:
 | 
					 | 
				
			||||||
    case Decl::Decomposition:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Variable;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::ImplicitParam:
 | 
					 | 
				
			||||||
    case Decl::ParmVar:
 | 
					 | 
				
			||||||
      // ccls extension
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Parameter;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::VarTemplateSpecialization:
 | 
					 | 
				
			||||||
    case Decl::VarTemplatePartialSpecialization:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Variable;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case Decl::EnumConstant:
 | 
					    case Decl::EnumConstant:
 | 
				
			||||||
      var->def.kind = lsSymbolKind::EnumMember;
 | 
					 | 
				
			||||||
      if (is_def && strchr(var->def.detailed_name, '=') == nullptr) {
 | 
					      if (is_def && strchr(var->def.detailed_name, '=') == nullptr) {
 | 
				
			||||||
        auto *ECD = cast<EnumConstantDecl>(D);
 | 
					        auto *ECD = cast<EnumConstantDecl>(D);
 | 
				
			||||||
        const auto &Val = ECD->getInitVal();
 | 
					        const auto &Val = ECD->getInitVal();
 | 
				
			||||||
@ -1069,11 +1044,7 @@ public:
 | 
				
			|||||||
        var->def.hover = Intern(var->def.detailed_name + init);
 | 
					        var->def.hover = Intern(var->def.detailed_name + init);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case Decl::UnresolvedUsingValue:
 | 
					 | 
				
			||||||
      var->def.kind = lsSymbolKind::Variable;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      LOG_S(INFO) << "Unhandled " << int(D->getKind());
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
@ -1131,16 +1102,17 @@ public:
 | 
				
			|||||||
      IndexVar &var = db->ToVar(usr);
 | 
					      IndexVar &var = db->ToVar(usr);
 | 
				
			||||||
      auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID);
 | 
					      auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID);
 | 
				
			||||||
      var.def.kind = lsSymbolKind::Macro;
 | 
					      var.def.kind = lsSymbolKind::Macro;
 | 
				
			||||||
 | 
					      var.def.parent_kind = lsSymbolKind::File;
 | 
				
			||||||
      if (var.def.spell) {
 | 
					      if (var.def.spell) {
 | 
				
			||||||
        DeclRef &d = var.declarations.emplace_back();
 | 
					        DeclRef &d = var.declarations.emplace_back();
 | 
				
			||||||
        static_cast<Use&>(d) = *var.def.spell;
 | 
					        static_cast<Use&>(d) = *var.def.spell;
 | 
				
			||||||
        d.extent = var.def.spell->range;
 | 
					        d.extent = var.def.spell->range;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      var.def.spell = Use{{range, 0, SymbolKind::File, Role::Definition}};
 | 
					      var.def.spell = Use{{range, Role::Definition}};
 | 
				
			||||||
      const MacroInfo *MI = MD->getMacroInfo();
 | 
					      const MacroInfo *MI = MD->getMacroInfo();
 | 
				
			||||||
      SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
 | 
					      SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
 | 
				
			||||||
      range = FromTokenRange(SM, param.Ctx->getLangOpts(), R);
 | 
					      range = FromTokenRange(SM, param.Ctx->getLangOpts(), R);
 | 
				
			||||||
      var.def.extent = Use{{range, 0, SymbolKind::File, Role::None}};
 | 
					      var.def.extent = Use{{range, Role::None}};
 | 
				
			||||||
      if (var.def.detailed_name[0] == '\0') {
 | 
					      if (var.def.detailed_name[0] == '\0') {
 | 
				
			||||||
        var.def.detailed_name = Intern(Name);
 | 
					        var.def.detailed_name = Intern(Name);
 | 
				
			||||||
        var.def.short_name_size = Name.size();
 | 
					        var.def.short_name_size = Name.size();
 | 
				
			||||||
@ -1162,8 +1134,8 @@ public:
 | 
				
			|||||||
    if (IndexFile *db = param.ConsumeFile(*FE)) {
 | 
					    if (IndexFile *db = param.ConsumeFile(*FE)) {
 | 
				
			||||||
      IndexVar &var = db->ToVar(GetMacro(Tok).second);
 | 
					      IndexVar &var = db->ToVar(GetMacro(Tok).second);
 | 
				
			||||||
      var.uses.push_back(
 | 
					      var.uses.push_back(
 | 
				
			||||||
          {{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
 | 
					          {{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID),
 | 
				
			||||||
            SymbolKind::File, Role::Dynamic}});
 | 
					            Role::Dynamic}});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void MacroUndefined(const Token &Tok, const MacroDefinition &MD,
 | 
					  void MacroUndefined(const Token &Tok, const MacroDefinition &MD,
 | 
				
			||||||
@ -1198,7 +1170,7 @@ public:
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const int IndexFile::kMajorVersion = 18;
 | 
					const int IndexFile::kMajorVersion = 19;
 | 
				
			||||||
const int IndexFile::kMinorVersion = 0;
 | 
					const int IndexFile::kMinorVersion = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
 | 
					IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
 | 
				
			||||||
@ -1390,10 +1362,7 @@ Index(CompletionManager *completion, WorkingFiles *wfiles, VFS *vfs,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
} // namespace ccls::idx
 | 
					} // namespace ccls::idx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// |SymbolRef| is serialized this way.
 | 
					void Reflect(Reader &vis, SymbolRef &v) {
 | 
				
			||||||
// |Use| also uses this though it has an extra field |file|,
 | 
					 | 
				
			||||||
// which is not used by Index* so it does not need to be serialized.
 | 
					 | 
				
			||||||
void Reflect(Reader &vis, Reference &v) {
 | 
					 | 
				
			||||||
  if (vis.Format() == SerializeFormat::Json) {
 | 
					  if (vis.Format() == SerializeFormat::Json) {
 | 
				
			||||||
    std::string t = vis.GetString();
 | 
					    std::string t = vis.GetString();
 | 
				
			||||||
    char *s = const_cast<char *>(t.c_str());
 | 
					    char *s = const_cast<char *>(t.c_str());
 | 
				
			||||||
@ -1409,7 +1378,7 @@ void Reflect(Reader &vis, Reference &v) {
 | 
				
			|||||||
    Reflect(vis, v.role);
 | 
					    Reflect(vis, v.role);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void Reflect(Writer &vis, Reference &v) {
 | 
					void Reflect(Writer &vis, SymbolRef &v) {
 | 
				
			||||||
  if (vis.Format() == SerializeFormat::Json) {
 | 
					  if (vis.Format() == SerializeFormat::Json) {
 | 
				
			||||||
    char buf[99];
 | 
					    char buf[99];
 | 
				
			||||||
    snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
 | 
					    snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
 | 
				
			||||||
@ -1430,25 +1399,24 @@ void Reflect(Reader &vis, Use &v) {
 | 
				
			|||||||
    char *s = const_cast<char *>(t.c_str());
 | 
					    char *s = const_cast<char *>(t.c_str());
 | 
				
			||||||
    v.range = Range::FromString(s);
 | 
					    v.range = Range::FromString(s);
 | 
				
			||||||
    s = strchr(s, '|');
 | 
					    s = strchr(s, '|');
 | 
				
			||||||
    v.usr = strtoull(s + 1, &s, 10);
 | 
					 | 
				
			||||||
    v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
 | 
					 | 
				
			||||||
    v.role = static_cast<Role>(strtol(s + 1, &s, 10));
 | 
					    v.role = static_cast<Role>(strtol(s + 1, &s, 10));
 | 
				
			||||||
    v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
 | 
					    v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    Reflect(vis, static_cast<Reference &>(v));
 | 
					    Reflect(vis, v.range);
 | 
				
			||||||
 | 
					    Reflect(vis, v.role);
 | 
				
			||||||
    Reflect(vis, v.file_id);
 | 
					    Reflect(vis, v.file_id);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void Reflect(Writer &vis, Use &v) {
 | 
					void Reflect(Writer &vis, Use &v) {
 | 
				
			||||||
  if (vis.Format() == SerializeFormat::Json) {
 | 
					  if (vis.Format() == SerializeFormat::Json) {
 | 
				
			||||||
    char buf[99];
 | 
					    char buf[99];
 | 
				
			||||||
    snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d|%d",
 | 
					    snprintf(buf, sizeof buf, "%s|%d|%d", v.range.ToString().c_str(),
 | 
				
			||||||
             v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role),
 | 
					             int(v.role), v.file_id);
 | 
				
			||||||
             v.file_id);
 | 
					 | 
				
			||||||
    std::string s(buf);
 | 
					    std::string s(buf);
 | 
				
			||||||
    Reflect(vis, s);
 | 
					    Reflect(vis, s);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    Reflect(vis, static_cast<Reference &>(v));
 | 
					    Reflect(vis, v.range);
 | 
				
			||||||
 | 
					    Reflect(vis, v.role);
 | 
				
			||||||
    Reflect(vis, v.file_id);
 | 
					    Reflect(vis, v.file_id);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1460,9 +1428,7 @@ void Reflect(Reader &vis, DeclRef &v) {
 | 
				
			|||||||
    v.range = Range::FromString(s);
 | 
					    v.range = Range::FromString(s);
 | 
				
			||||||
    s = strchr(s, '|') + 1;
 | 
					    s = strchr(s, '|') + 1;
 | 
				
			||||||
    v.extent = Range::FromString(s);
 | 
					    v.extent = Range::FromString(s);
 | 
				
			||||||
    s = strchr(s, '|') + 1;
 | 
					    s = strchr(s, '|');
 | 
				
			||||||
    v.usr = strtoull(s, &s, 10);
 | 
					 | 
				
			||||||
    v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
 | 
					 | 
				
			||||||
    v.role = static_cast<Role>(strtol(s + 1, &s, 10));
 | 
					    v.role = static_cast<Role>(strtol(s + 1, &s, 10));
 | 
				
			||||||
    v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
 | 
					    v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
@ -1473,9 +1439,8 @@ void Reflect(Reader &vis, DeclRef &v) {
 | 
				
			|||||||
void Reflect(Writer &vis, DeclRef &v) {
 | 
					void Reflect(Writer &vis, DeclRef &v) {
 | 
				
			||||||
  if (vis.Format() == SerializeFormat::Json) {
 | 
					  if (vis.Format() == SerializeFormat::Json) {
 | 
				
			||||||
    char buf[99];
 | 
					    char buf[99];
 | 
				
			||||||
    snprintf(buf, sizeof buf, "%s|%s|%" PRIu64 "|%d|%d|%d",
 | 
					    snprintf(buf, sizeof buf, "%s|%s|%d|%d", v.range.ToString().c_str(),
 | 
				
			||||||
             v.range.ToString().c_str(), v.extent.ToString().c_str(), v.usr,
 | 
					             v.extent.ToString().c_str(), int(v.role), v.file_id);
 | 
				
			||||||
             int(v.kind), int(v.role), v.file_id);
 | 
					 | 
				
			||||||
    std::string s(buf);
 | 
					    std::string s(buf);
 | 
				
			||||||
    Reflect(vis, s);
 | 
					    Reflect(vis, s);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -49,28 +49,36 @@ struct SymbolIdx {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(SymbolIdx, usr, kind);
 | 
					MAKE_REFLECT_STRUCT(SymbolIdx, usr, kind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Reference {
 | 
					// |id,kind| refer to the referenced entity.
 | 
				
			||||||
 | 
					struct SymbolRef {
 | 
				
			||||||
  Range range;
 | 
					  Range range;
 | 
				
			||||||
  Usr usr;
 | 
					  Usr usr;
 | 
				
			||||||
  SymbolKind kind;
 | 
					  SymbolKind kind;
 | 
				
			||||||
  Role role;
 | 
					  Role role;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool Valid() const { return range.Valid(); }
 | 
					 | 
				
			||||||
  operator SymbolIdx() const { return {usr, kind}; }
 | 
					  operator SymbolIdx() const { return {usr, kind}; }
 | 
				
			||||||
  std::tuple<Range, Usr, SymbolKind, Role> ToTuple() const {
 | 
					  std::tuple<Range, Usr, SymbolKind, Role> ToTuple() const {
 | 
				
			||||||
    return std::make_tuple(range, usr, kind, role);
 | 
					    return std::make_tuple(range, usr, kind, role);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  bool operator==(const Reference &o) const { return ToTuple() == o.ToTuple(); }
 | 
					  bool operator==(const SymbolRef &o) const { return ToTuple() == o.ToTuple(); }
 | 
				
			||||||
  bool operator<(const Reference &o) const { return ToTuple() < o.ToTuple(); }
 | 
					  bool Valid() const { return range.Valid(); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
// |id,kind| refer to the referenced entity.
 | 
					 | 
				
			||||||
struct SymbolRef : Reference {};
 | 
					 | 
				
			||||||
MAKE_HASHABLE(SymbolRef, t.range, t.usr, t.kind, t.role);
 | 
					MAKE_HASHABLE(SymbolRef, t.range, t.usr, t.kind, t.role);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Ref {
 | 
				
			||||||
 | 
					  Range range;
 | 
				
			||||||
 | 
					  Role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool Valid() const { return range.Valid(); }
 | 
				
			||||||
 | 
					  std::tuple<Range, Role> ToTuple() const {
 | 
				
			||||||
 | 
					    return std::make_tuple(range, role);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  bool operator==(const Ref &o) const { return ToTuple() == o.ToTuple(); }
 | 
				
			||||||
 | 
					  bool operator<(const Ref &o) const { return ToTuple() < o.ToTuple(); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
 | 
					// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
 | 
				
			||||||
// parent.
 | 
					// parent.
 | 
				
			||||||
struct Use : Reference {
 | 
					struct Use : Ref {
 | 
				
			||||||
  // |file| is used in Query* but not in Index*
 | 
					  // |file| is used in Query* but not in Index*
 | 
				
			||||||
  int file_id = -1;
 | 
					  int file_id = -1;
 | 
				
			||||||
  bool operator==(const Use &o) const {
 | 
					  bool operator==(const Use &o) const {
 | 
				
			||||||
@ -85,8 +93,8 @@ struct DeclRef : Use {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
MAKE_HASHABLE(DeclRef, t.range, t.file_id)
 | 
					MAKE_HASHABLE(DeclRef, t.range, t.file_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Reflect(Reader &visitor, Reference &value);
 | 
					void Reflect(Reader &visitor, SymbolRef &value);
 | 
				
			||||||
void Reflect(Writer &visitor, Reference &value);
 | 
					void Reflect(Writer &visitor, SymbolRef &value);
 | 
				
			||||||
void Reflect(Reader &visitor, Use &value);
 | 
					void Reflect(Reader &visitor, Use &value);
 | 
				
			||||||
void Reflect(Writer &visitor, Use &value);
 | 
					void Reflect(Writer &visitor, Use &value);
 | 
				
			||||||
void Reflect(Reader &visitor, DeclRef &value);
 | 
					void Reflect(Reader &visitor, DeclRef &value);
 | 
				
			||||||
@ -115,74 +123,71 @@ struct FuncDef : NameMixin<FuncDef> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Method this method overrides.
 | 
					  // Method this method overrides.
 | 
				
			||||||
  std::vector<Usr> bases;
 | 
					  std::vector<Usr> bases;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Local variables or parameters.
 | 
					  // Local variables or parameters.
 | 
				
			||||||
  std::vector<Usr> vars;
 | 
					  std::vector<Usr> vars;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Functions that this function calls.
 | 
					  // Functions that this function calls.
 | 
				
			||||||
  std::vector<SymbolRef> callees;
 | 
					  std::vector<SymbolRef> callees;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int file_id = -1;
 | 
					  int file_id = -1; // not serialized
 | 
				
			||||||
  int16_t qual_name_offset = 0;
 | 
					  int16_t qual_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_offset = 0;
 | 
					  int16_t short_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_size = 0;
 | 
					  int16_t short_name_size = 0;
 | 
				
			||||||
  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
					  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
				
			||||||
 | 
					  lsSymbolKind parent_kind = lsSymbolKind::Unknown;
 | 
				
			||||||
  uint8_t storage = clang::SC_None;
 | 
					  uint8_t storage = clang::SC_None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Usr> GetBases() const { return bases; }
 | 
					  std::vector<Usr> GetBases() const { return bases; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(FuncDef, detailed_name, qual_name_offset, short_name_offset,
 | 
					MAKE_REFLECT_STRUCT(FuncDef, detailed_name, hover, comments, spell, extent,
 | 
				
			||||||
                    short_name_size, kind, storage, hover, comments, spell,
 | 
					                    bases, vars, callees, qual_name_offset, short_name_offset,
 | 
				
			||||||
                    extent, bases, vars, callees);
 | 
					                    short_name_size, kind, parent_kind, storage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct IndexFunc : NameMixin<IndexFunc> {
 | 
					struct IndexFunc : NameMixin<IndexFunc> {
 | 
				
			||||||
  using Def = FuncDef;
 | 
					  using Def = FuncDef;
 | 
				
			||||||
  Usr usr;
 | 
					  Usr usr;
 | 
				
			||||||
  Def def;
 | 
					  Def def;
 | 
				
			||||||
  std::vector<DeclRef> declarations;
 | 
					  std::vector<DeclRef> declarations;
 | 
				
			||||||
  std::vector<Use> uses;
 | 
					 | 
				
			||||||
  std::vector<Usr> derived;
 | 
					  std::vector<Usr> derived;
 | 
				
			||||||
 | 
					  std::vector<Use> uses;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TypeDef : NameMixin<TypeDef> {
 | 
					struct TypeDef : NameMixin<TypeDef> {
 | 
				
			||||||
  const char *detailed_name = "";
 | 
					  const char *detailed_name = "";
 | 
				
			||||||
  const char *hover = "";
 | 
					  const char *hover = "";
 | 
				
			||||||
  const char *comments = "";
 | 
					  const char *comments = "";
 | 
				
			||||||
 | 
					 | 
				
			||||||
  Maybe<Use> spell;
 | 
					  Maybe<Use> spell;
 | 
				
			||||||
  Maybe<Use> extent;
 | 
					  Maybe<Use> extent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Usr> bases;
 | 
					  std::vector<Usr> bases;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Types, functions, and variables defined in this type.
 | 
					  // Types, functions, and variables defined in this type.
 | 
				
			||||||
  std::vector<Usr> types;
 | 
					 | 
				
			||||||
  std::vector<Usr> funcs;
 | 
					  std::vector<Usr> funcs;
 | 
				
			||||||
 | 
					  std::vector<Usr> types;
 | 
				
			||||||
  std::vector<std::pair<Usr, int64_t>> vars;
 | 
					  std::vector<std::pair<Usr, int64_t>> vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // If set, then this is the same underlying type as the given value (ie, this
 | 
					  // If set, then this is the same underlying type as the given value (ie, this
 | 
				
			||||||
  // type comes from a using or typedef statement).
 | 
					  // type comes from a using or typedef statement).
 | 
				
			||||||
  Usr alias_of = 0;
 | 
					  Usr alias_of = 0;
 | 
				
			||||||
 | 
					  int file_id = -1; // not serialized
 | 
				
			||||||
  int file_id = -1;
 | 
					 | 
				
			||||||
  int16_t qual_name_offset = 0;
 | 
					  int16_t qual_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_offset = 0;
 | 
					  int16_t short_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_size = 0;
 | 
					  int16_t short_name_size = 0;
 | 
				
			||||||
  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
					  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
				
			||||||
 | 
					  lsSymbolKind parent_kind = lsSymbolKind::Unknown;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Usr> GetBases() const { return bases; }
 | 
					  std::vector<Usr> GetBases() const { return bases; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(TypeDef, detailed_name, qual_name_offset, short_name_offset,
 | 
					MAKE_REFLECT_STRUCT(TypeDef, detailed_name, hover, comments, spell, extent,
 | 
				
			||||||
                    short_name_size, kind, hover, comments, spell, extent,
 | 
					                    bases, funcs, types, vars, alias_of, qual_name_offset,
 | 
				
			||||||
                    alias_of, bases, types, funcs, vars);
 | 
					                    short_name_offset, short_name_size, kind, parent_kind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct IndexType {
 | 
					struct IndexType {
 | 
				
			||||||
  using Def = TypeDef;
 | 
					  using Def = TypeDef;
 | 
				
			||||||
  Usr usr;
 | 
					  Usr usr;
 | 
				
			||||||
  Def def;
 | 
					  Def def;
 | 
				
			||||||
  std::vector<DeclRef> declarations;
 | 
					  std::vector<DeclRef> declarations;
 | 
				
			||||||
  std::vector<Use> uses;
 | 
					 | 
				
			||||||
  std::vector<Usr> derived;
 | 
					  std::vector<Usr> derived;
 | 
				
			||||||
  std::vector<Usr> instances;
 | 
					  std::vector<Usr> instances;
 | 
				
			||||||
 | 
					  std::vector<Use> uses;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct VarDef : NameMixin<VarDef> {
 | 
					struct VarDef : NameMixin<VarDef> {
 | 
				
			||||||
@ -195,27 +200,29 @@ struct VarDef : NameMixin<VarDef> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Type of the variable.
 | 
					  // Type of the variable.
 | 
				
			||||||
  Usr type = 0;
 | 
					  Usr type = 0;
 | 
				
			||||||
 | 
					  int file_id = -1; // not serialized
 | 
				
			||||||
  int file_id = -1;
 | 
					 | 
				
			||||||
  int16_t qual_name_offset = 0;
 | 
					  int16_t qual_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_offset = 0;
 | 
					  int16_t short_name_offset = 0;
 | 
				
			||||||
  int16_t short_name_size = 0;
 | 
					  int16_t short_name_size = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
					  lsSymbolKind kind = lsSymbolKind::Unknown;
 | 
				
			||||||
 | 
					  lsSymbolKind parent_kind = lsSymbolKind::Unknown;
 | 
				
			||||||
  // Note a variable may have instances of both |None| and |Extern|
 | 
					  // Note a variable may have instances of both |None| and |Extern|
 | 
				
			||||||
  // (declaration).
 | 
					  // (declaration).
 | 
				
			||||||
  uint8_t storage = clang::SC_None;
 | 
					  uint8_t storage = clang::SC_None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool is_local() const {
 | 
					  bool is_local() const {
 | 
				
			||||||
    return spell && spell->kind == SymbolKind::Func &&
 | 
					    return spell &&
 | 
				
			||||||
 | 
					           (parent_kind == lsSymbolKind::Function ||
 | 
				
			||||||
 | 
					            parent_kind == lsSymbolKind::Method ||
 | 
				
			||||||
 | 
					            parent_kind == lsSymbolKind::StaticMethod) &&
 | 
				
			||||||
           storage == clang::SC_None;
 | 
					           storage == clang::SC_None;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<Usr> GetBases() const { return {}; }
 | 
					  std::vector<Usr> GetBases() const { return {}; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(VarDef, detailed_name, qual_name_offset, short_name_offset,
 | 
					MAKE_REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, extent, type,
 | 
				
			||||||
                    short_name_size, hover, comments, spell, extent, type, kind,
 | 
					                    qual_name_offset, short_name_offset, short_name_size, kind,
 | 
				
			||||||
                    storage);
 | 
					                    parent_kind, storage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct IndexVar {
 | 
					struct IndexVar {
 | 
				
			||||||
  using Def = VarDef;
 | 
					  using Def = VarDef;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/lsp.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/lsp.h
									
									
									
									
									
								
							@ -198,15 +198,6 @@ enum class lsSymbolKind : uint8_t {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_TYPE_PROXY(lsSymbolKind);
 | 
					MAKE_REFLECT_TYPE_PROXY(lsSymbolKind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ccls extension
 | 
					 | 
				
			||||||
struct lsLocationEx : lsLocation {
 | 
					 | 
				
			||||||
  std::optional<std::string_view> containerName;
 | 
					 | 
				
			||||||
  std::optional<lsSymbolKind> parentKind;
 | 
					 | 
				
			||||||
  // Avoid circular dependency on symbol.h
 | 
					 | 
				
			||||||
  std::optional<uint16_t> role;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct lsTextDocumentIdentifier {
 | 
					struct lsTextDocumentIdentifier {
 | 
				
			||||||
  lsDocumentUri uri;
 | 
					  lsDocumentUri uri;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -346,6 +337,6 @@ void Reflect(TVisitor &visitor, Out_ShowLogMessage &value) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct Out_LocationList : public lsOutMessage<Out_LocationList> {
 | 
					struct Out_LocationList : public lsOutMessage<Out_LocationList> {
 | 
				
			||||||
  lsRequestId id;
 | 
					  lsRequestId id;
 | 
				
			||||||
  std::vector<lsLocationEx> result;
 | 
					  std::vector<lsLocation> result;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);
 | 
					MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);
 | 
				
			||||||
 | 
				
			|||||||
@ -156,24 +156,15 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
 | 
				
			|||||||
      const QueryFunc::Def *def = func.AnyDef();
 | 
					      const QueryFunc::Def *def = func.AnyDef();
 | 
				
			||||||
      if (!def)
 | 
					      if (!def)
 | 
				
			||||||
        continue; // applies to for loop
 | 
					        continue; // applies to for loop
 | 
				
			||||||
      if (def->spell)
 | 
					 | 
				
			||||||
        parent_kind = GetSymbolKind(db, *def->spell);
 | 
					 | 
				
			||||||
      if (parent_kind == lsSymbolKind::Unknown) {
 | 
					 | 
				
			||||||
        for (Use use : func.declarations) {
 | 
					 | 
				
			||||||
          parent_kind = GetSymbolKind(db, use);
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // Don't highlight overloadable operators or implicit lambda ->
 | 
					      // Don't highlight overloadable operators or implicit lambda ->
 | 
				
			||||||
      // std::function constructor.
 | 
					      // std::function constructor.
 | 
				
			||||||
      std::string_view short_name = def->Name(false);
 | 
					      std::string_view short_name = def->Name(false);
 | 
				
			||||||
      if (short_name.compare(0, 8, "operator") == 0)
 | 
					      if (short_name.compare(0, 8, "operator") == 0)
 | 
				
			||||||
        continue; // applies to for loop
 | 
					        continue; // applies to for loop
 | 
				
			||||||
      if (def->spell)
 | 
					 | 
				
			||||||
        parent_kind = GetSymbolKind(db, *def->spell);
 | 
					 | 
				
			||||||
      kind = def->kind;
 | 
					      kind = def->kind;
 | 
				
			||||||
      storage = def->storage;
 | 
					      storage = def->storage;
 | 
				
			||||||
      detailed_name = short_name;
 | 
					      detailed_name = short_name;
 | 
				
			||||||
 | 
					      parent_kind = def->parent_kind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Check whether the function name is actually there.
 | 
					      // Check whether the function name is actually there.
 | 
				
			||||||
      // If not, do not publish the semantic highlight.
 | 
					      // If not, do not publish the semantic highlight.
 | 
				
			||||||
@ -200,7 +191,7 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
 | 
				
			|||||||
        kind = def.kind;
 | 
					        kind = def.kind;
 | 
				
			||||||
        detailed_name = def.detailed_name;
 | 
					        detailed_name = def.detailed_name;
 | 
				
			||||||
        if (def.spell) {
 | 
					        if (def.spell) {
 | 
				
			||||||
          parent_kind = GetSymbolKind(db, *def.spell);
 | 
					          parent_kind = def.parent_kind;
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -214,13 +205,7 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
 | 
				
			|||||||
        storage = def.storage;
 | 
					        storage = def.storage;
 | 
				
			||||||
        detailed_name = def.detailed_name;
 | 
					        detailed_name = def.detailed_name;
 | 
				
			||||||
        if (def.spell) {
 | 
					        if (def.spell) {
 | 
				
			||||||
          parent_kind = GetSymbolKind(db, *def.spell);
 | 
					          parent_kind = def.parent_kind;
 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (parent_kind == lsSymbolKind::Unknown) {
 | 
					 | 
				
			||||||
        for (Use use : var.declarations) {
 | 
					 | 
				
			||||||
          parent_kind = GetSymbolKind(db, use);
 | 
					 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -77,6 +77,8 @@ struct Out_CclsCall : public lsOutMessage<Out_CclsCall> {
 | 
				
			|||||||
    int numChildren;
 | 
					    int numChildren;
 | 
				
			||||||
    // Empty if the |levels| limit is reached.
 | 
					    // Empty if the |levels| limit is reached.
 | 
				
			||||||
    std::vector<Entry> children;
 | 
					    std::vector<Entry> children;
 | 
				
			||||||
 | 
					    bool operator==(const Entry &o) const { return location == o.location; }
 | 
				
			||||||
 | 
					    bool operator<(const Entry &o) const { return location < o.location; }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lsRequestId id;
 | 
					  lsRequestId id;
 | 
				
			||||||
@ -94,13 +96,14 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee,
 | 
				
			|||||||
  entry->numChildren = 0;
 | 
					  entry->numChildren = 0;
 | 
				
			||||||
  if (!def)
 | 
					  if (!def)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  auto handle = [&](Use use, CallType call_type1) {
 | 
					  auto handle = [&](SymbolRef sym, int file_id, CallType call_type1) {
 | 
				
			||||||
    entry->numChildren++;
 | 
					    entry->numChildren++;
 | 
				
			||||||
    if (levels > 0) {
 | 
					    if (levels > 0) {
 | 
				
			||||||
      Out_CclsCall::Entry entry1;
 | 
					      Out_CclsCall::Entry entry1;
 | 
				
			||||||
      entry1.id = std::to_string(use.usr);
 | 
					      entry1.id = std::to_string(sym.usr);
 | 
				
			||||||
      entry1.usr = use.usr;
 | 
					      entry1.usr = sym.usr;
 | 
				
			||||||
      if (auto loc = GetLsLocation(m->db, m->working_files, use))
 | 
					      if (auto loc = GetLsLocation(m->db, m->working_files,
 | 
				
			||||||
 | 
					                                   Use{{sym.range, sym.role}, file_id}))
 | 
				
			||||||
        entry1.location = *loc;
 | 
					        entry1.location = *loc;
 | 
				
			||||||
      entry1.callType = call_type1;
 | 
					      entry1.callType = call_type1;
 | 
				
			||||||
      if (Expand(m, &entry1, callee, call_type, qualified, levels - 1))
 | 
					      if (Expand(m, &entry1, callee, call_type, qualified, levels - 1))
 | 
				
			||||||
@ -110,14 +113,22 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee,
 | 
				
			|||||||
  auto handle_uses = [&](const QueryFunc &func, CallType call_type) {
 | 
					  auto handle_uses = [&](const QueryFunc &func, CallType call_type) {
 | 
				
			||||||
    if (callee) {
 | 
					    if (callee) {
 | 
				
			||||||
      if (const auto *def = func.AnyDef())
 | 
					      if (const auto *def = func.AnyDef())
 | 
				
			||||||
        for (SymbolRef ref : def->callees)
 | 
					        for (SymbolRef sym : def->callees)
 | 
				
			||||||
          if (ref.kind == SymbolKind::Func)
 | 
					          if (sym.kind == SymbolKind::Func)
 | 
				
			||||||
            handle(Use{{ref.range, ref.usr, ref.kind, ref.role}, def->file_id},
 | 
					            handle(sym, def->file_id, call_type);
 | 
				
			||||||
                   call_type);
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      for (Use use : func.uses)
 | 
					      for (Use use : func.uses) {
 | 
				
			||||||
        if (use.kind == SymbolKind::Func)
 | 
					        const QueryFile &file1 = m->db->files[use.file_id];
 | 
				
			||||||
          handle(use, call_type);
 | 
					        Maybe<SymbolRef> best_sym;
 | 
				
			||||||
 | 
					        for (auto [sym, refcnt] : file1.outline2refcnt)
 | 
				
			||||||
 | 
					          if (refcnt > 0 && sym.kind == SymbolKind::Func &&
 | 
				
			||||||
 | 
					              sym.range.start <= use.range.start &&
 | 
				
			||||||
 | 
					              use.range.end <= sym.range.end &&
 | 
				
			||||||
 | 
					              (!best_sym || best_sym->range.start < sym.range.start))
 | 
				
			||||||
 | 
					            best_sym = sym;
 | 
				
			||||||
 | 
					        if (best_sym)
 | 
				
			||||||
 | 
					          handle(*best_sym, use.file_id, call_type);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -160,6 +171,11 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee,
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::sort(entry->children.begin(), entry->children.end());
 | 
				
			||||||
 | 
					  entry->children.erase(
 | 
				
			||||||
 | 
					      std::unique(entry->children.begin(), entry->children.end()),
 | 
				
			||||||
 | 
					      entry->children.end());
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -104,7 +104,7 @@ struct Handler_CclsNavigate : BaseMessageHandler<In_CclsNavigate> {
 | 
				
			|||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
    if (res)
 | 
					    if (res)
 | 
				
			||||||
      if (auto ls_range = GetLsRange(wfile, *res)) {
 | 
					      if (auto ls_range = GetLsRange(wfile, *res)) {
 | 
				
			||||||
        lsLocationEx &ls_loc = out.result.emplace_back();
 | 
					        lsLocation &ls_loc = out.result.emplace_back();
 | 
				
			||||||
        ls_loc.uri = params.textDocument.uri;
 | 
					        ls_loc.uri = params.textDocument.uri;
 | 
				
			||||||
        ls_loc.range = *ls_range;
 | 
					        ls_loc.range = *ls_range;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -63,7 +63,7 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
 | 
				
			|||||||
        [[fallthrough]];
 | 
					        [[fallthrough]];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      case SymbolKind::Type:
 | 
					      case SymbolKind::Type:
 | 
				
			||||||
        out.result = GetLsLocationExs(
 | 
					        out.result = GetLsLocations(
 | 
				
			||||||
            db, working_files,
 | 
					            db, working_files,
 | 
				
			||||||
            GetVarDeclarations(db, db->Type(usr).instances, params.kind));
 | 
					            GetVarDeclarations(db, db->Type(usr).instances, params.kind));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
				
			|||||||
@ -117,19 +117,19 @@ struct Handler_TextDocumentCodeLens
 | 
				
			|||||||
      code_lens.command->arguments.push_back(ToString(show));
 | 
					      code_lens.command->arguments.push_back(ToString(show));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto ToSpell = [&](Use use) {
 | 
					    auto ToSpell = [&](SymbolRef sym, int file_id) -> Use {
 | 
				
			||||||
      Maybe<Use> def = GetDefinitionSpell(db, use);
 | 
					      Maybe<Use> def = GetDefinitionSpell(db, sym);
 | 
				
			||||||
      if (def && def->file_id == use.file_id &&
 | 
					      if (def && def->file_id == file_id &&
 | 
				
			||||||
          def->range.start.line == use.range.start.line)
 | 
					          def->range.start.line == sym.range.start.line)
 | 
				
			||||||
        return *def;
 | 
					        return *def;
 | 
				
			||||||
      return use;
 | 
					      return {{sym.range, sym.role}, file_id};
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unordered_set<Range> seen;
 | 
					    std::unordered_set<Range> seen;
 | 
				
			||||||
    for (auto [sym, refcnt] : file->outline2refcnt) {
 | 
					    for (auto [sym, refcnt] : file->outline2refcnt) {
 | 
				
			||||||
      if (refcnt <= 0 || !seen.insert(sym.range).second)
 | 
					      if (refcnt <= 0 || !seen.insert(sym.range).second)
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      Use use = ToSpell({{sym.range, sym.usr, sym.kind, sym.role}, file->id});
 | 
					      Use use = ToSpell(sym, file->id);
 | 
				
			||||||
      switch (sym.kind) {
 | 
					      switch (sym.kind) {
 | 
				
			||||||
      case SymbolKind::Func: {
 | 
					      case SymbolKind::Func: {
 | 
				
			||||||
        QueryFunc &func = db->GetFunc(sym);
 | 
					        QueryFunc &func = db->GetFunc(sym);
 | 
				
			||||||
 | 
				
			|||||||
@ -33,13 +33,6 @@ struct In_TextDocumentDefinition : public RequestInMessage {
 | 
				
			|||||||
MAKE_REFLECT_STRUCT(In_TextDocumentDefinition, id, params);
 | 
					MAKE_REFLECT_STRUCT(In_TextDocumentDefinition, id, params);
 | 
				
			||||||
REGISTER_IN_MESSAGE(In_TextDocumentDefinition);
 | 
					REGISTER_IN_MESSAGE(In_TextDocumentDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Out_TextDocumentDefinition
 | 
					 | 
				
			||||||
    : public lsOutMessage<Out_TextDocumentDefinition> {
 | 
					 | 
				
			||||||
  lsRequestId id;
 | 
					 | 
				
			||||||
  std::vector<lsLocationEx> result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Use> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
 | 
					std::vector<Use> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
 | 
				
			||||||
  switch (sym.kind) {
 | 
					  switch (sym.kind) {
 | 
				
			||||||
  case SymbolKind::Var: {
 | 
					  case SymbolKind::Var: {
 | 
				
			||||||
@ -73,7 +66,7 @@ struct Handler_TextDocumentDefinition
 | 
				
			|||||||
                        params.textDocument.uri.GetPath(), &file, &file_id))
 | 
					                        params.textDocument.uri.GetPath(), &file, &file_id))
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Out_TextDocumentDefinition out;
 | 
					    Out_LocationList out;
 | 
				
			||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Maybe<Use> on_def;
 | 
					    Maybe<Use> on_def;
 | 
				
			||||||
@ -110,7 +103,7 @@ struct Handler_TextDocumentDefinition
 | 
				
			|||||||
        if (uses.empty() && on_def)
 | 
					        if (uses.empty() && on_def)
 | 
				
			||||||
          uses.push_back(*on_def);
 | 
					          uses.push_back(*on_def);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      auto locs = GetLsLocationExs(db, working_files, uses);
 | 
					      auto locs = GetLsLocations(db, working_files, uses);
 | 
				
			||||||
      out.result.insert(out.result.end(), locs.begin(), locs.end());
 | 
					      out.result.insert(out.result.end(), locs.begin(), locs.end());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -123,9 +116,8 @@ struct Handler_TextDocumentDefinition
 | 
				
			|||||||
      // Check #include
 | 
					      // Check #include
 | 
				
			||||||
      for (const IndexInclude &include : file->def->includes) {
 | 
					      for (const IndexInclude &include : file->def->includes) {
 | 
				
			||||||
        if (include.line == ls_pos.line) {
 | 
					        if (include.line == ls_pos.line) {
 | 
				
			||||||
          lsLocationEx result;
 | 
					          out.result.push_back(
 | 
				
			||||||
          result.uri = lsDocumentUri::FromPath(include.resolved_path);
 | 
					              lsLocation{lsDocumentUri::FromPath(include.resolved_path)});
 | 
				
			||||||
          out.result.push_back(result);
 | 
					 | 
				
			||||||
          range = {{0, 0}, {0, 0}};
 | 
					          range = {{0, 0}, {0, 0}};
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -184,9 +176,8 @@ struct Handler_TextDocumentDefinition
 | 
				
			|||||||
        if (best_sym.kind != SymbolKind::Invalid) {
 | 
					        if (best_sym.kind != SymbolKind::Invalid) {
 | 
				
			||||||
          Maybe<Use> use = GetDefinitionSpell(db, best_sym);
 | 
					          Maybe<Use> use = GetDefinitionSpell(db, best_sym);
 | 
				
			||||||
          assert(use);
 | 
					          assert(use);
 | 
				
			||||||
          if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
 | 
					          if (auto loc = GetLsLocation(db, working_files, *use))
 | 
				
			||||||
                                            g_config->xref.container))
 | 
					            out.result.push_back(*loc);
 | 
				
			||||||
            out.result.push_back(*ls_loc);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -80,11 +80,9 @@ struct Handler_TextDocumentDocumentHighlight
 | 
				
			|||||||
            return usr == sym1.usr && kind == sym1.kind;
 | 
					            return usr == sym1.usr && kind == sym1.kind;
 | 
				
			||||||
          }))
 | 
					          }))
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      if (auto ls_loc =
 | 
					      if (auto loc = GetLsLocation(db, working_files, sym, file_id)) {
 | 
				
			||||||
              GetLsLocation(db, working_files,
 | 
					 | 
				
			||||||
                            Use{{sym.range, usr, kind, sym.role}, file_id})) {
 | 
					 | 
				
			||||||
        lsDocumentHighlight highlight;
 | 
					        lsDocumentHighlight highlight;
 | 
				
			||||||
        highlight.range = ls_loc->range;
 | 
					        highlight.range = loc->range;
 | 
				
			||||||
        if (sym.role & Role::Write)
 | 
					        if (sym.role & Role::Write)
 | 
				
			||||||
          highlight.kind = lsDocumentHighlight::Write;
 | 
					          highlight.kind = lsDocumentHighlight::Write;
 | 
				
			||||||
        else if (sym.role & Role::Read)
 | 
					        else if (sym.role & Role::Read)
 | 
				
			||||||
 | 
				
			|||||||
@ -107,10 +107,8 @@ struct Handler_TextDocumentDocumentSymbol
 | 
				
			|||||||
      for (auto [sym, refcnt] : symbol2refcnt)
 | 
					      for (auto [sym, refcnt] : symbol2refcnt)
 | 
				
			||||||
        if (refcnt > 0 && params.startLine <= sym.range.start.line &&
 | 
					        if (refcnt > 0 && params.startLine <= sym.range.start.line &&
 | 
				
			||||||
            sym.range.start.line <= params.endLine)
 | 
					            sym.range.start.line <= params.endLine)
 | 
				
			||||||
          if (auto ls_loc = GetLsLocation(
 | 
					          if (auto loc = GetLsLocation(db, working_files, sym, file_id))
 | 
				
			||||||
                  db, working_files,
 | 
					            out.result.push_back(loc->range);
 | 
				
			||||||
                  Use{{sym.range, sym.usr, sym.kind, sym.role}, file_id}))
 | 
					 | 
				
			||||||
            out.result.push_back(ls_loc->range);
 | 
					 | 
				
			||||||
      std::sort(out.result.begin(), out.result.end());
 | 
					      std::sort(out.result.begin(), out.result.end());
 | 
				
			||||||
      pipeline::WriteStdout(kMethodType, out);
 | 
					      pipeline::WriteStdout(kMethodType, out);
 | 
				
			||||||
    } else if (g_config->client.hierarchicalDocumentSymbolSupport) {
 | 
					    } else if (g_config->client.hierarchicalDocumentSymbolSupport) {
 | 
				
			||||||
@ -213,10 +211,8 @@ struct Handler_TextDocumentDocumentSymbol
 | 
				
			|||||||
              (sym.kind == SymbolKind::Var &&
 | 
					              (sym.kind == SymbolKind::Var &&
 | 
				
			||||||
               IgnoreVar(db->GetVar(sym).AnyDef())))
 | 
					               IgnoreVar(db->GetVar(sym).AnyDef())))
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
          if (std::optional<lsLocation> location = GetLsLocation(
 | 
					          if (auto loc = GetLsLocation(db, working_files, sym, file_id)) {
 | 
				
			||||||
                  db, working_files,
 | 
					            info->location = *loc;
 | 
				
			||||||
                  Use{{sym.range, sym.usr, sym.kind, sym.role}, file_id})) {
 | 
					 | 
				
			||||||
            info->location = *location;
 | 
					 | 
				
			||||||
            out.result.push_back(*info);
 | 
					            out.result.push_back(*info);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -47,12 +47,12 @@ struct Handler_TextDocumentImplementation
 | 
				
			|||||||
         FindSymbolsAtLocation(working_file, file, request->params.position)) {
 | 
					         FindSymbolsAtLocation(working_file, file, request->params.position)) {
 | 
				
			||||||
      if (sym.kind == SymbolKind::Type) {
 | 
					      if (sym.kind == SymbolKind::Type) {
 | 
				
			||||||
        QueryType &type = db->GetType(sym);
 | 
					        QueryType &type = db->GetType(sym);
 | 
				
			||||||
        out.result = GetLsLocationExs(db, working_files,
 | 
					        out.result = GetLsLocations(db, working_files,
 | 
				
			||||||
                                    GetTypeDeclarations(db, type.derived));
 | 
					                                    GetTypeDeclarations(db, type.derived));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      } else if (sym.kind == SymbolKind::Func) {
 | 
					      } else if (sym.kind == SymbolKind::Func) {
 | 
				
			||||||
        QueryFunc &func = db->GetFunc(sym);
 | 
					        QueryFunc &func = db->GetFunc(sym);
 | 
				
			||||||
        out.result = GetLsLocationExs(db, working_files,
 | 
					        out.result = GetLsLocations(db, working_files,
 | 
				
			||||||
                                    GetFuncDeclarations(db, func.derived));
 | 
					                                    GetFuncDeclarations(db, func.derived));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -50,13 +50,6 @@ MAKE_REFLECT_STRUCT(In_TextDocumentReferences::Params, textDocument, position,
 | 
				
			|||||||
MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params);
 | 
					MAKE_REFLECT_STRUCT(In_TextDocumentReferences, id, params);
 | 
				
			||||||
REGISTER_IN_MESSAGE(In_TextDocumentReferences);
 | 
					REGISTER_IN_MESSAGE(In_TextDocumentReferences);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Out_TextDocumentReferences
 | 
					 | 
				
			||||||
    : public lsOutMessage<Out_TextDocumentReferences> {
 | 
					 | 
				
			||||||
  lsRequestId id;
 | 
					 | 
				
			||||||
  std::vector<lsLocationEx> result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentReferences, jsonrpc, id, result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Handler_TextDocumentReferences
 | 
					struct Handler_TextDocumentReferences
 | 
				
			||||||
    : BaseMessageHandler<In_TextDocumentReferences> {
 | 
					    : BaseMessageHandler<In_TextDocumentReferences> {
 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					  MethodType GetMethodType() const override { return kMethodType; }
 | 
				
			||||||
@ -67,7 +60,7 @@ struct Handler_TextDocumentReferences
 | 
				
			|||||||
    if (!FindFileOrFail(db, project, request->id,
 | 
					    if (!FindFileOrFail(db, project, request->id,
 | 
				
			||||||
                        params.textDocument.uri.GetPath(), &file))
 | 
					                        params.textDocument.uri.GetPath(), &file))
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    Out_TextDocumentReferences out;
 | 
					    Out_LocationList out;
 | 
				
			||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
    WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
					    WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
 | 
				
			||||||
    if (!file) {
 | 
					    if (!file) {
 | 
				
			||||||
@ -75,7 +68,6 @@ struct Handler_TextDocumentReferences
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool container = g_config->xref.container;
 | 
					 | 
				
			||||||
    std::unordered_set<Use> seen_uses;
 | 
					    std::unordered_set<Use> seen_uses;
 | 
				
			||||||
    int line = params.position.line;
 | 
					    int line = params.position.line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,11 +85,8 @@ struct Handler_TextDocumentReferences
 | 
				
			|||||||
          if (Role(use.role & params.context.role) == params.context.role &&
 | 
					          if (Role(use.role & params.context.role) == params.context.role &&
 | 
				
			||||||
              !(use.role & params.context.excludeRole) &&
 | 
					              !(use.role & params.context.excludeRole) &&
 | 
				
			||||||
              seen_uses.insert(use).second)
 | 
					              seen_uses.insert(use).second)
 | 
				
			||||||
            if (std::optional<lsLocationEx> ls_loc =
 | 
					            if (auto loc = GetLsLocation(db, working_files, use)) {
 | 
				
			||||||
                    GetLsLocationEx(db, working_files, use, container)) {
 | 
					              out.result.push_back(*loc);
 | 
				
			||||||
              if (container)
 | 
					 | 
				
			||||||
                ls_loc->parentKind = parent_kind;
 | 
					 | 
				
			||||||
              out.result.push_back(*ls_loc);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        WithEntity(db, sym, [&](const auto &entity) {
 | 
					        WithEntity(db, sym, [&](const auto &entity) {
 | 
				
			||||||
@ -145,10 +134,9 @@ struct Handler_TextDocumentReferences
 | 
				
			|||||||
            for (const IndexInclude &include : file1.def->includes)
 | 
					            for (const IndexInclude &include : file1.def->includes)
 | 
				
			||||||
              if (include.resolved_path == path) {
 | 
					              if (include.resolved_path == path) {
 | 
				
			||||||
                // Another file |file1| has the same include line.
 | 
					                // Another file |file1| has the same include line.
 | 
				
			||||||
                lsLocationEx result;
 | 
					                lsLocation &loc = out.result.emplace_back();
 | 
				
			||||||
                result.uri = lsDocumentUri::FromPath(file1.def->path);
 | 
					                loc.uri = lsDocumentUri::FromPath(file1.def->path);
 | 
				
			||||||
                result.range.start.line = result.range.end.line = include.line;
 | 
					                loc.range.start.line = loc.range.end.line = include.line;
 | 
				
			||||||
                out.result.push_back(std::move(result));
 | 
					 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -28,13 +28,6 @@ struct In_TextDocumentTypeDefinition : public RequestInMessage {
 | 
				
			|||||||
MAKE_REFLECT_STRUCT(In_TextDocumentTypeDefinition, id, params);
 | 
					MAKE_REFLECT_STRUCT(In_TextDocumentTypeDefinition, id, params);
 | 
				
			||||||
REGISTER_IN_MESSAGE(In_TextDocumentTypeDefinition);
 | 
					REGISTER_IN_MESSAGE(In_TextDocumentTypeDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Out_TextDocumentTypeDefinition
 | 
					 | 
				
			||||||
    : public lsOutMessage<Out_TextDocumentTypeDefinition> {
 | 
					 | 
				
			||||||
  lsRequestId id;
 | 
					 | 
				
			||||||
  std::vector<lsLocationEx> result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentTypeDefinition, jsonrpc, id, result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Handler_TextDocumentTypeDefinition
 | 
					struct Handler_TextDocumentTypeDefinition
 | 
				
			||||||
    : BaseMessageHandler<In_TextDocumentTypeDefinition> {
 | 
					    : BaseMessageHandler<In_TextDocumentTypeDefinition> {
 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					  MethodType GetMethodType() const override { return kMethodType; }
 | 
				
			||||||
@ -47,19 +40,17 @@ struct Handler_TextDocumentTypeDefinition
 | 
				
			|||||||
    WorkingFile *working_file =
 | 
					    WorkingFile *working_file =
 | 
				
			||||||
        working_files->GetFileByFilename(file->def->path);
 | 
					        working_files->GetFileByFilename(file->def->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Out_TextDocumentTypeDefinition out;
 | 
					    Out_LocationList out;
 | 
				
			||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
    auto Add = [&](const QueryType &type) {
 | 
					    auto Add = [&](const QueryType &type) {
 | 
				
			||||||
      for (const auto &def : type.def)
 | 
					      for (const auto &def : type.def)
 | 
				
			||||||
        if (def.spell) {
 | 
					        if (def.spell) {
 | 
				
			||||||
          if (auto ls_loc = GetLsLocationEx(db, working_files, *def.spell,
 | 
					          if (auto ls_loc = GetLsLocation(db, working_files, *def.spell))
 | 
				
			||||||
                                            g_config->xref.container))
 | 
					 | 
				
			||||||
            out.result.push_back(*ls_loc);
 | 
					            out.result.push_back(*ls_loc);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      if (out.result.empty())
 | 
					      if (out.result.empty())
 | 
				
			||||||
        for (const DeclRef &dr : type.declarations)
 | 
					        for (const DeclRef &dr : type.declarations)
 | 
				
			||||||
          if (auto ls_loc = GetLsLocationEx(db, working_files, dr,
 | 
					          if (auto ls_loc = GetLsLocation(db, working_files, dr))
 | 
				
			||||||
                                            g_config->xref.container))
 | 
					 | 
				
			||||||
            out.result.push_back(*ls_loc);
 | 
					            out.result.push_back(*ls_loc);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    for (SymbolRef sym :
 | 
					    for (SymbolRef sym :
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/query.cc
									
									
									
									
									
								
							@ -34,8 +34,6 @@ void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
 | 
				
			|||||||
    use.file_id = file_id;
 | 
					    use.file_id = file_id;
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    use.file_id = lid2file_id.find(use.file_id)->second;
 | 
					    use.file_id = lid2file_id.find(use.file_id)->second;
 | 
				
			||||||
  if (use.kind == SymbolKind::File)
 | 
					 | 
				
			||||||
    use.usr = use.file_id;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
@ -238,7 +236,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
 | 
				
			|||||||
                 SymbolKind kind, Use &use, int delta, int k = 1) {
 | 
					                 SymbolKind kind, Use &use, int delta, int k = 1) {
 | 
				
			||||||
    use.file_id =
 | 
					    use.file_id =
 | 
				
			||||||
        use.file_id == -1 ? u->file_id : lid2fid.find(use.file_id)->second;
 | 
					        use.file_id == -1 ? u->file_id : lid2fid.find(use.file_id)->second;
 | 
				
			||||||
    SymbolRef sym{{use.range, usr, kind, use.role}};
 | 
					    SymbolRef sym{use.range, usr, kind, use.role};
 | 
				
			||||||
    if (k & 1) {
 | 
					    if (k & 1) {
 | 
				
			||||||
      int &v = files[use.file_id].symbol2refcnt[sym];
 | 
					      int &v = files[use.file_id].symbol2refcnt[sym];
 | 
				
			||||||
      v += delta;
 | 
					      v += delta;
 | 
				
			||||||
@ -258,7 +256,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
 | 
				
			|||||||
                     SymbolKind kind, DeclRef &dr, int delta) {
 | 
					                     SymbolKind kind, DeclRef &dr, int delta) {
 | 
				
			||||||
    Ref(lid2fid, usr, kind, dr, delta, 1);
 | 
					    Ref(lid2fid, usr, kind, dr, delta, 1);
 | 
				
			||||||
    files[dr.file_id]
 | 
					    files[dr.file_id]
 | 
				
			||||||
        .outline2refcnt[SymbolRef{{dr.extent, usr, kind, dr.role}}] += delta;
 | 
					        .outline2refcnt[SymbolRef{dr.extent, usr, kind, dr.role}] += delta;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto UpdateUses =
 | 
					  auto UpdateUses =
 | 
				
			||||||
@ -401,12 +399,12 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
 | 
				
			|||||||
    if (def.spell) {
 | 
					    if (def.spell) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
					      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
				
			||||||
      files[def.spell->file_id].symbol2refcnt[{
 | 
					      files[def.spell->file_id].symbol2refcnt[{
 | 
				
			||||||
          {def.spell->range, u.first, SymbolKind::Func, def.spell->role}}]++;
 | 
					          def.spell->range, u.first, SymbolKind::Func, def.spell->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (def.extent) {
 | 
					    if (def.extent) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
					      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
				
			||||||
      files[def.extent->file_id].outline2refcnt[{
 | 
					      files[def.extent->file_id].outline2refcnt[{
 | 
				
			||||||
          {def.extent->range, u.first, SymbolKind::Func, def.extent->role}}]++;
 | 
					          def.extent->range, u.first, SymbolKind::Func, def.extent->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto R = func_usr.try_emplace({u.first}, func_usr.size());
 | 
					    auto R = func_usr.try_emplace({u.first}, func_usr.size());
 | 
				
			||||||
@ -428,12 +426,12 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
 | 
				
			|||||||
    if (def.spell) {
 | 
					    if (def.spell) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
					      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
				
			||||||
      files[def.spell->file_id].symbol2refcnt[{
 | 
					      files[def.spell->file_id].symbol2refcnt[{
 | 
				
			||||||
          {def.spell->range, u.first, SymbolKind::Type, def.spell->role}}]++;
 | 
					          def.spell->range, u.first, SymbolKind::Type, def.spell->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (def.extent) {
 | 
					    if (def.extent) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
					      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
				
			||||||
      files[def.extent->file_id].outline2refcnt[{
 | 
					      files[def.extent->file_id].outline2refcnt[{
 | 
				
			||||||
          {def.extent->range, u.first, SymbolKind::Type, def.extent->role}}]++;
 | 
					          def.extent->range, u.first, SymbolKind::Type, def.extent->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto R = type_usr.try_emplace({u.first}, type_usr.size());
 | 
					    auto R = type_usr.try_emplace({u.first}, type_usr.size());
 | 
				
			||||||
    if (R.second)
 | 
					    if (R.second)
 | 
				
			||||||
@ -454,12 +452,12 @@ void DB::Update(const Lid2file_id &lid2file_id, int file_id,
 | 
				
			|||||||
    if (def.spell) {
 | 
					    if (def.spell) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
					      AssignFileId(lid2file_id, file_id, *def.spell);
 | 
				
			||||||
      files[def.spell->file_id].symbol2refcnt[{
 | 
					      files[def.spell->file_id].symbol2refcnt[{
 | 
				
			||||||
          {def.spell->range, u.first, SymbolKind::Var, def.spell->role}}]++;
 | 
					          def.spell->range, u.first, SymbolKind::Var, def.spell->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (def.extent) {
 | 
					    if (def.extent) {
 | 
				
			||||||
      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
					      AssignFileId(lid2file_id, file_id, *def.extent);
 | 
				
			||||||
      files[def.extent->file_id].outline2refcnt[{
 | 
					      files[def.extent->file_id].outline2refcnt[{
 | 
				
			||||||
          {def.extent->range, u.first, SymbolKind::Var, def.extent->role}}]++;
 | 
					          def.extent->range, u.first, SymbolKind::Var, def.extent->role}]++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto R = var_usr.try_emplace({u.first}, var_usr.size());
 | 
					    auto R = var_usr.try_emplace({u.first}, var_usr.size());
 | 
				
			||||||
    if (R.second)
 | 
					    if (R.second)
 | 
				
			||||||
 | 
				
			|||||||
@ -85,17 +85,17 @@ struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
 | 
				
			|||||||
  Usr usr;
 | 
					  Usr usr;
 | 
				
			||||||
  llvm::SmallVector<Def, 1> def;
 | 
					  llvm::SmallVector<Def, 1> def;
 | 
				
			||||||
  std::vector<DeclRef> declarations;
 | 
					  std::vector<DeclRef> declarations;
 | 
				
			||||||
  std::vector<Use> uses;
 | 
					 | 
				
			||||||
  std::vector<Usr> derived;
 | 
					  std::vector<Usr> derived;
 | 
				
			||||||
 | 
					  std::vector<Use> uses;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct QueryType : QueryEntity<QueryType, TypeDef> {
 | 
					struct QueryType : QueryEntity<QueryType, TypeDef> {
 | 
				
			||||||
  Usr usr;
 | 
					  Usr usr;
 | 
				
			||||||
  llvm::SmallVector<Def, 1> def;
 | 
					  llvm::SmallVector<Def, 1> def;
 | 
				
			||||||
  std::vector<DeclRef> declarations;
 | 
					  std::vector<DeclRef> declarations;
 | 
				
			||||||
  std::vector<Use> uses;
 | 
					 | 
				
			||||||
  std::vector<Usr> derived;
 | 
					  std::vector<Usr> derived;
 | 
				
			||||||
  std::vector<Usr> instances;
 | 
					  std::vector<Usr> instances;
 | 
				
			||||||
 | 
					  std::vector<Use> uses;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct QueryVar : QueryEntity<QueryVar, VarDef> {
 | 
					struct QueryVar : QueryEntity<QueryVar, VarDef> {
 | 
				
			||||||
 | 
				
			|||||||
@ -61,8 +61,7 @@ Maybe<Use> GetDefinitionSpell(DB *db, SymbolIdx sym) {
 | 
				
			|||||||
Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym) {
 | 
					Maybe<Use> GetDefinitionExtent(DB *db, SymbolIdx sym) {
 | 
				
			||||||
  // Used to jump to file.
 | 
					  // Used to jump to file.
 | 
				
			||||||
  if (sym.kind == SymbolKind::File)
 | 
					  if (sym.kind == SymbolKind::File)
 | 
				
			||||||
    return Use{{Range{{0, 0}, {0, 0}}, sym.usr, sym.kind, Role::None},
 | 
					    return Use{{Range{{0, 0}, {0, 0}}, Role::None}, int(sym.usr)};
 | 
				
			||||||
               int(sym.usr)};
 | 
					 | 
				
			||||||
  Maybe<Use> ret;
 | 
					  Maybe<Use> ret;
 | 
				
			||||||
  EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.extent); });
 | 
					  EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.extent); });
 | 
				
			||||||
  return ret;
 | 
					  return ret;
 | 
				
			||||||
@ -216,40 +215,27 @@ lsDocumentUri GetLsDocumentUri(DB *db, int file_id) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
 | 
					std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
                                        Use use) {
 | 
					                                        Use use) {
 | 
				
			||||||
  std::string path;
 | 
					  std::string path;
 | 
				
			||||||
  lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
 | 
					  lsDocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
 | 
				
			||||||
  std::optional<lsRange> range =
 | 
					  std::optional<lsRange> range =
 | 
				
			||||||
      GetLsRange(working_files->GetFileByFilename(path), use.range);
 | 
					      GetLsRange(wfiles->GetFileByFilename(path), use.range);
 | 
				
			||||||
  if (!range)
 | 
					  if (!range)
 | 
				
			||||||
    return std::nullopt;
 | 
					    return std::nullopt;
 | 
				
			||||||
  return lsLocation{uri, *range};
 | 
					  return lsLocation{uri, *range};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
 | 
					std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
                                            Use use, bool container) {
 | 
					                                        SymbolRef sym, int file_id) {
 | 
				
			||||||
  std::optional<lsLocation> ls_loc = GetLsLocation(db, working_files, use);
 | 
					  return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
 | 
				
			||||||
  if (!ls_loc)
 | 
					 | 
				
			||||||
    return std::nullopt;
 | 
					 | 
				
			||||||
  lsLocationEx ret;
 | 
					 | 
				
			||||||
  ret.lsLocation::operator=(*ls_loc);
 | 
					 | 
				
			||||||
  if (container) {
 | 
					 | 
				
			||||||
    ret.role = uint16_t(use.role);
 | 
					 | 
				
			||||||
    EachEntityDef(db, use, [&](const auto &def) {
 | 
					 | 
				
			||||||
      ret.containerName = std::string_view(def.detailed_name);
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
 | 
					std::vector<lsLocation> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
                                       const std::vector<Use> &uses) {
 | 
					                                       const std::vector<Use> &uses) {
 | 
				
			||||||
  std::vector<lsLocationEx> ret;
 | 
					  std::vector<lsLocation> ret;
 | 
				
			||||||
  for (Use use : uses)
 | 
					  for (Use use : uses)
 | 
				
			||||||
    if (auto loc =
 | 
					    if (auto loc = GetLsLocation(db, wfiles, use))
 | 
				
			||||||
            GetLsLocationEx(db, working_files, use, g_config->xref.container))
 | 
					 | 
				
			||||||
      ret.push_back(*loc);
 | 
					      ret.push_back(*loc);
 | 
				
			||||||
  std::sort(ret.begin(), ret.end());
 | 
					  std::sort(ret.begin(), ret.end());
 | 
				
			||||||
  ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
 | 
					  ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
 | 
				
			||||||
 | 
				
			|||||||
@ -39,12 +39,11 @@ std::optional<lsRange> GetLsRange(WorkingFile *working_file,
 | 
				
			|||||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
 | 
					lsDocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
 | 
				
			||||||
lsDocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
					lsDocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *working_files,
 | 
					std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
 | 
				
			||||||
                                        Use use);
 | 
					std::optional<lsLocation> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
std::optional<lsLocationEx> GetLsLocationEx(DB *db, WorkingFiles *working_files,
 | 
					                                        SymbolRef sym, int file_id);
 | 
				
			||||||
                                            Use use, bool container);
 | 
					std::vector<lsLocation> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
std::vector<lsLocationEx> GetLsLocationExs(DB *db, WorkingFiles *working_files,
 | 
					                                           const std::vector<Use> &uses);
 | 
				
			||||||
                                           const std::vector<Use> &refs);
 | 
					 | 
				
			||||||
// Returns a symbol. The symbol will *NOT* have a location assigned.
 | 
					// Returns a symbol. The symbol will *NOT* have a location assigned.
 | 
				
			||||||
std::optional<lsSymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
					std::optional<lsSymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
				
			||||||
                                                 bool detailed);
 | 
					                                                 bool detailed);
 | 
				
			||||||
 | 
				
			|||||||
@ -255,45 +255,49 @@ template <typename Def> void ReflectShortName(Writer &visitor, Def &def) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexType &value) {
 | 
					 | 
				
			||||||
  REFLECT_MEMBER_START();
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("usr", value.usr);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
					 | 
				
			||||||
  ReflectShortName(visitor, value.def);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("kind", value.def.kind);
 | 
					 | 
				
			||||||
  ReflectHoverAndComments(visitor, value.def);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("declarations", value.declarations);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("spell", value.def.spell);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("extent", value.def.extent);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("alias_of", value.def.alias_of);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("bases", value.def.bases);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("derived", value.derived);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("types", value.def.types);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("funcs", value.def.funcs);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("vars", value.def.vars);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("instances", value.instances);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("uses", value.uses);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER_END();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFunc &value) {
 | 
					template <typename TVisitor> void Reflect(TVisitor &visitor, IndexFunc &value) {
 | 
				
			||||||
  REFLECT_MEMBER_START();
 | 
					  REFLECT_MEMBER_START();
 | 
				
			||||||
  REFLECT_MEMBER2("usr", value.usr);
 | 
					  REFLECT_MEMBER2("usr", value.usr);
 | 
				
			||||||
  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
					  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
				
			||||||
  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
					  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
				
			||||||
  ReflectShortName(visitor, value.def);
 | 
					  ReflectShortName(visitor, value.def);
 | 
				
			||||||
  REFLECT_MEMBER2("kind", value.def.kind);
 | 
					  REFLECT_MEMBER2("spell", value.def.spell);
 | 
				
			||||||
  REFLECT_MEMBER2("storage", value.def.storage);
 | 
					  REFLECT_MEMBER2("extent", value.def.extent);
 | 
				
			||||||
  ReflectHoverAndComments(visitor, value.def);
 | 
					  ReflectHoverAndComments(visitor, value.def);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("bases", value.def.bases);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("vars", value.def.vars);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("callees", value.def.callees);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("kind", value.def.kind);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("parent_kind", value.def.parent_kind);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("storage", value.def.storage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  REFLECT_MEMBER2("declarations", value.declarations);
 | 
					  REFLECT_MEMBER2("declarations", value.declarations);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("derived", value.derived);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("uses", value.uses);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER_END();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename TVisitor> void Reflect(TVisitor &visitor, IndexType &value) {
 | 
				
			||||||
 | 
					  REFLECT_MEMBER_START();
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("usr", value.usr);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("detailed_name", value.def.detailed_name);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
				
			||||||
 | 
					  ReflectShortName(visitor, value.def);
 | 
				
			||||||
 | 
					  ReflectHoverAndComments(visitor, value.def);
 | 
				
			||||||
  REFLECT_MEMBER2("spell", value.def.spell);
 | 
					  REFLECT_MEMBER2("spell", value.def.spell);
 | 
				
			||||||
  REFLECT_MEMBER2("extent", value.def.extent);
 | 
					  REFLECT_MEMBER2("extent", value.def.extent);
 | 
				
			||||||
  REFLECT_MEMBER2("bases", value.def.bases);
 | 
					  REFLECT_MEMBER2("bases", value.def.bases);
 | 
				
			||||||
  REFLECT_MEMBER2("derived", value.derived);
 | 
					  REFLECT_MEMBER2("funcs", value.def.funcs);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("types", value.def.types);
 | 
				
			||||||
  REFLECT_MEMBER2("vars", value.def.vars);
 | 
					  REFLECT_MEMBER2("vars", value.def.vars);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("alias_of", value.def.alias_of);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("kind", value.def.kind);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("parent_kind", value.def.parent_kind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("declarations", value.declarations);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("derived", value.derived);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("instances", value.instances);
 | 
				
			||||||
  REFLECT_MEMBER2("uses", value.uses);
 | 
					  REFLECT_MEMBER2("uses", value.uses);
 | 
				
			||||||
  REFLECT_MEMBER2("callees", value.def.callees);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER_END();
 | 
					  REFLECT_MEMBER_END();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -304,13 +308,15 @@ template <typename TVisitor> void Reflect(TVisitor &visitor, IndexVar &value) {
 | 
				
			|||||||
  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
					  REFLECT_MEMBER2("qual_name_offset", value.def.qual_name_offset);
 | 
				
			||||||
  ReflectShortName(visitor, value.def);
 | 
					  ReflectShortName(visitor, value.def);
 | 
				
			||||||
  ReflectHoverAndComments(visitor, value.def);
 | 
					  ReflectHoverAndComments(visitor, value.def);
 | 
				
			||||||
  REFLECT_MEMBER2("declarations", value.declarations);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("spell", value.def.spell);
 | 
					  REFLECT_MEMBER2("spell", value.def.spell);
 | 
				
			||||||
  REFLECT_MEMBER2("extent", value.def.extent);
 | 
					  REFLECT_MEMBER2("extent", value.def.extent);
 | 
				
			||||||
  REFLECT_MEMBER2("type", value.def.type);
 | 
					  REFLECT_MEMBER2("type", value.def.type);
 | 
				
			||||||
  REFLECT_MEMBER2("uses", value.uses);
 | 
					 | 
				
			||||||
  REFLECT_MEMBER2("kind", value.def.kind);
 | 
					  REFLECT_MEMBER2("kind", value.def.kind);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("parent_kind", value.def.parent_kind);
 | 
				
			||||||
  REFLECT_MEMBER2("storage", value.def.storage);
 | 
					  REFLECT_MEMBER2("storage", value.def.storage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("declarations", value.declarations);
 | 
				
			||||||
 | 
					  REFLECT_MEMBER2("uses", value.uses);
 | 
				
			||||||
  REFLECT_MEMBER_END();
 | 
					  REFLECT_MEMBER_END();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user