Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
i582 committed Jun 10, 2022
1 parent 25a39b8 commit 65d2c79
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 6 deletions.
11 changes: 11 additions & 0 deletions src/main/kotlin/com/vk/kphpstorm/generics/GenericUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import com.jetbrains.php.lang.psi.resolve.types.PhpType
import com.vk.kphpstorm.exphptype.*
import com.vk.kphpstorm.generics.psi.GenericInstantiationPsiCommentImpl
import com.vk.kphpstorm.kphptags.psi.KphpDocGenericParameterDecl
import com.vk.kphpstorm.kphptags.psi.KphpDocInheritParameterDeclPsiImpl
import com.vk.kphpstorm.kphptags.psi.KphpDocTagGenericPsiImpl
import com.vk.kphpstorm.kphptags.psi.KphpDocTagInheritPsiImpl

object GenericUtil {
fun PhpNamedElement.isGeneric() = docComment?.getTagElementsByName("@kphp-generic")?.firstOrNull() != null
Expand Down Expand Up @@ -60,6 +62,15 @@ object GenericUtil {
return extendsList.filter { it.isGeneric() } to implementsList.filter { it.isGeneric() }
}

fun PhpClass.genericInheritInstantiation(className: String): KphpDocInheritParameterDeclPsiImpl? {
val docT = docComment?.getTagElementsByName("@kphp-inherit")?.firstOrNull() as? KphpDocTagInheritPsiImpl
?: return null

return docT.types().find {
it.className() == className
}
}

fun ExPhpType.isGenericPipe(): Boolean {
if (this is ExPhpTypePipe) {
if (this.items.size != 2) return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract class ResolvingGenericBase(val project: Project) {
return instantiate()
}

protected fun specialization(): Map<String, ExPhpType> {
protected fun specialization(): MutableMap<String, ExPhpType> {
val specialization = specializationList()

val specializationNameMap = mutableMapOf<String, ExPhpType>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ package com.vk.kphpstorm.generics

import com.intellij.openapi.project.Project
import com.jetbrains.php.PhpIndex
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocReturnTag
import com.jetbrains.php.lang.psi.elements.Method
import com.jetbrains.php.lang.psi.elements.Parameter
import com.jetbrains.php.lang.psi.elements.PhpClass
import com.jetbrains.php.lang.psi.elements.impl.PhpClassImpl
import com.jetbrains.php.lang.psi.resolve.types.PhpType
import com.vk.kphpstorm.exphptype.ExPhpTypeGenericsT
import com.vk.kphpstorm.exphptype.ExPhpTypeTplInstantiation
import com.vk.kphpstorm.generics.GenericUtil.genericInheritInstantiation
import com.vk.kphpstorm.generics.GenericUtil.genericNames
import com.vk.kphpstorm.generics.GenericUtil.genericParents
import com.vk.kphpstorm.generics.GenericUtil.getInstantiations
import com.vk.kphpstorm.generics.GenericUtil.isReturnGeneric
import com.vk.kphpstorm.helpers.toExPhpType
import com.vk.kphpstorm.kphptags.psi.KphpDocGenericParameterDecl
import com.vk.kphpstorm.typeProviders.GenericMethodsTypeProvider
import java.lang.Integer.min

class ResolvingGenericMethodCall(project: Project) : ResolvingGenericBase(project) {
override var klass: PhpClass? = null
Expand All @@ -25,10 +30,62 @@ class ResolvingGenericMethodCall(project: Project) : ResolvingGenericBase(projec
override var classGenericType: ExPhpTypeTplInstantiation? = null

override fun instantiate(): PhpType? {
val klass = klass ?: return null

val specializationNameMap = specialization()

val returnTag = method?.docComment?.returnTag ?: return null
val exType = returnTag.type.toExPhpType(project) ?: return null
val (extendsList, implementsList) = klass.genericParents()

val parentsList = extendsList + implementsList
parentsList.forEach { parent ->
val extendsName = parent.fqn
val genericNames = parent.genericNames()
val inheritInstantiation = klass.genericInheritInstantiation(extendsName)
if (inheritInstantiation != null) {
val specList = inheritInstantiation.specializationList()

val classSpecializationMap = genericNames.associate {
it.name to it.defaultType
}.toMutableMap()

for (i in 0 until min(genericNames.size, specList.size)) {
val genericT = genericNames[i]
val spec = specList[i]

classSpecializationMap[genericT.name] = spec
}

classSpecializationMap.forEach classForEach@{ (name, type) ->
if (type == null) {
return@classForEach
}
specializationNameMap[name] = type.instantiateGeneric(specializationNameMap)
}
}
}

val classImpl = klass as PhpClassImpl

var returnTag: PhpDocReturnTag? = null

val ifaces = classImpl.directImplementedInterfaces
ifaces.forEach { iface ->
val method = iface.findMethodByName(method!!.name)
returnTag = method?.docComment?.returnTag ?: return@forEach
}

val classes = listOf(classImpl.superClass)
classes.forEach { parent ->
val method = parent?.findMethodByName(method!!.name)
returnTag = method?.docComment?.returnTag ?: return@forEach
}

val classMethodReturnTag = method?.docComment?.returnTag
if (classMethodReturnTag != null) {
returnTag = classMethodReturnTag
}

val exType = returnTag?.type?.toExPhpType(project) ?: return null
val specializedType = exType.instantiateGeneric(specializationNameMap)

return specializedType.toPhpType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocElementType
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocRef
import com.jetbrains.php.lang.documentation.phpdoc.psi.impl.PhpDocPsiElementImpl
import com.jetbrains.php.lang.documentation.phpdoc.psi.impl.PhpDocTypeImpl
import com.vk.kphpstorm.exphptype.ExPhpType
import com.vk.kphpstorm.exphptype.ExPhpTypeInstance
import com.vk.kphpstorm.exphptype.ExPhpTypeTplInstantiation
import com.vk.kphpstorm.exphptype.psi.ExPhpTypeInstancePsiImpl
Expand Down Expand Up @@ -36,4 +37,15 @@ class KphpDocInheritParameterDeclPsiImpl(node: ASTNode) : PhpDocPsiElementImpl(n

return exType.getInstantiation()?.classFqn
}

fun specializationList(): List<ExPhpType> {
val instantiationPsi = findChildByClass(PhpDocTypeImpl::class.java) ?: return emptyList()
if (instantiationPsi !is ExPhpTypeTplInstantiationPsiImpl)
return emptyList()

val exType = instantiationPsi.type.toExPhpType() ?: return emptyList()
val instantiation = exType.getInstantiation() ?: return emptyList()

return instantiation.specializationList
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,17 @@ object KphpDocTagInheritElementType :
}

override fun createStub(psi: PhpDocTag, parentStub: StubElement<*>?): PhpDocTagStub {
// stub value is 'T1,T2:ExtendsClass,T2=default' — without spaces
// TODO: add stubs
return KphpDocTagStubImpl(parentStub, this, psi.name, "stubValue")
val stubValue = (psi as KphpDocTagInheritPsiImpl).types()
.joinToString(",") {
val type = StringBuilder()

if (it.className() != null) {
type.append(it.className().toString())
}

type.toString()
}
return KphpDocTagStubImpl(parentStub, this, psi.name, stubValue)
}

override fun serialize(stub: PhpDocTagStub, dataStream: StubOutputStream) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package com.vk.kphpstorm.typeProviders

import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import com.jetbrains.php.lang.psi.elements.ClassReference
import com.jetbrains.php.lang.psi.elements.NewExpression
import com.jetbrains.php.lang.psi.elements.PhpClass
import com.jetbrains.php.lang.psi.resolve.types.PhpCharTypeKey
import com.jetbrains.php.lang.psi.resolve.types.PhpType
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider4
import com.vk.kphpstorm.exphptype.psi.ExPhpTypeTplInstantiationPsiImpl
import com.vk.kphpstorm.generics.GenericUtil.genericInheritInstantiation
import com.vk.kphpstorm.generics.IndexingGenericFunctionCall
import com.vk.kphpstorm.generics.ResolvingGenericConstructorCall

Expand All @@ -26,6 +31,16 @@ class GenericClassesTypeProvider : PhpTypeProvider4 {
return PhpType().add(KEY.sign(data))
}

if (p is ClassReference && p.name == "parent") {
val containingClass = p.parentOfType<PhpClass>()
if (containingClass != null) {
val superClass = containingClass.superClass
val instantiationParameter = containingClass.genericInheritInstantiation(superClass!!.fqn)
val instantiation = instantiationParameter?.firstChild as? ExPhpTypeTplInstantiationPsiImpl
return instantiation?.type
}
}

return null
}

Expand Down

0 comments on commit 65d2c79

Please sign in to comment.