From 0c64995ea28febcc7d38e1519da8d93391ce2e7d Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 7 Jun 2022 14:10:49 -0700 Subject: Major language server features. (#2264) * Major language server features. * Include slangd in binary release. * Fix compiler issues. * Fix compiler error. * Completion resolve. * Various improvements. * Update diagnostic test expected output. * Bug fix for source locations. * Adjust diagnostic update frequency. * Update github actions to store artifacts. * Fix infinite parser loop. * Fix parser recovery. * Fix parser recovery. * Update test. * Fix test. * Disable IR gen for language server. * Allow commit characters in auto completion. * Fix lookup for invoke exprs. * More parser robustness fixes. * update solution file Co-authored-by: Yong He --- .../slang/slang-language-server-collect-member.cpp | 156 +++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 source/slang/slang-language-server-collect-member.cpp (limited to 'source/slang/slang-language-server-collect-member.cpp') diff --git a/source/slang/slang-language-server-collect-member.cpp b/source/slang/slang-language-server-collect-member.cpp new file mode 100644 index 000000000..73539b9d9 --- /dev/null +++ b/source/slang/slang-language-server-collect-member.cpp @@ -0,0 +1,156 @@ +// slang-language-server-collect-member.cpp + +// This file implements the logic to collect all members from a parsed type.] +// The flow is mostly the same as `lookupMemberInType`, but instead of looking for a specific name, +// we collect all members we see. + +#include "slang-language-server-collect-member.h" + +namespace Slang +{ +void collectMembersInType(MemberCollectingContext* context, Type* type) +{ + if (auto pointerLikeType = as(type)) + { + collectMembersInType(context, pointerLikeType->elementType); + return; + } + + if (auto declRefType = as(type)) + { + auto declRef = declRefType->declRef; + + collectMembersInTypeDeclImpl( + context, + declRef); + } + else if (auto nsType = as(type)) + { + auto declRef = nsType->declRef; + + collectMembersInTypeDeclImpl(context, declRef); + } + else if (auto extractExistentialType = as(type)) + { + // We want lookup to be performed on the underlying interface type of the existential, + // but we need to have a this-type substitution applied to ensure that the result of + // lookup will have a comparable substitution applied (allowing things like associated + // types, etc. used in the signature of a method to resolve correctly). + // + auto interfaceDeclRef = extractExistentialType->getSpecializedInterfaceDeclRef(); + collectMembersInTypeDeclImpl(context, interfaceDeclRef); + } + else if (auto thisType = as(type)) + { + auto interfaceType = DeclRefType::create(context->astBuilder, thisType->interfaceDeclRef); + collectMembersInType(context, interfaceType); + } + else if (auto andType = as(type)) + { + auto leftType = andType->left; + auto rightType = andType->right; + collectMembersInType(context, leftType); + collectMembersInType(context, rightType); + } +} + +void collectMembersInTypeDeclImpl( + MemberCollectingContext* context, + DeclRef declRef) +{ + if (declRef.getDecl()->checkState.getState() < DeclCheckState::ReadyForLookup) + return; + + if (auto genericTypeParamDeclRef = declRef.as()) + { + // If the type we are doing lookup in is a generic type parameter, + // then the members it provides can only be discovered by looking + // at the constraints that are placed on that type. + auto genericDeclRef = genericTypeParamDeclRef.getParent().as(); + assert(genericDeclRef); + + for (auto constraintDeclRef : getMembersOfType(genericDeclRef)) + { + if (constraintDeclRef.decl->checkState.getState() < DeclCheckState::ReadyForLookup) + { + continue; + } + + collectMembersInType( + context, + getSup(context->astBuilder, constraintDeclRef)); + } + } + else if (declRef.as() || declRef.as()) + { + for (auto constraintDeclRef : + getMembersOfType(declRef.as())) + { + if (constraintDeclRef.decl->checkState.getState() < DeclCheckState::ReadyForLookup) + { + continue; + } + collectMembersInType(context, getSup(context->astBuilder, constraintDeclRef)); + } + } + else if (auto namespaceDecl = declRef.as()) + { + for (auto member : namespaceDecl.getDecl()->members) + { + if (member->getName()) + { + context->members.add(member); + } + } + } + else if (auto aggTypeDeclBaseRef = declRef.as()) + { + // In this case we are peforming lookup in the context of an aggregate + // type or an `extension`, so the first thing to do is to look for + // matching members declared directly in the body of the type/`extension`. + // + for (auto member : aggTypeDeclBaseRef.getDecl()->members) + { + if (member->getName()) + { + context->members.add(member); + } + } + + if (auto aggTypeDeclRef = aggTypeDeclBaseRef.as()) + { + auto extensions = + context->semanticsContext.getCandidateExtensionsForTypeDecl(aggTypeDeclRef); + for (auto extDecl : extensions) + { + // TODO: check if the extension can be applied before including its members. + // TODO: eventually we need to insert a breadcrumb here so that + // the constructed result can somehow indicate that a member + // was found through an extension. + // + collectMembersInTypeDeclImpl( + context, + DeclRef(extDecl, nullptr)); + } + } + + // For both aggregate types and their `extension`s, we want lookup to follow + // through the declared inheritance relationships on each declaration. + // + for (auto inheritanceDeclRef : getMembersOfType(aggTypeDeclBaseRef)) + { + // Some things that are syntactically `InheritanceDecl`s don't actually + // represent a subtype/supertype relationship, and thus we shouldn't + // include members from the base type when doing lookup in the + // derived type. + // + if (inheritanceDeclRef.getDecl()->hasModifier()) + continue; + + collectMembersInType( + context, getSup(context->astBuilder, inheritanceDeclRef)); + } + } +} + +} // namespace Slang -- cgit v1.2.3