-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
59 changed files
with
2,148 additions
and
286 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.vk.kphpstorm | ||
|
||
import com.intellij.lang.DefaultASTFactoryImpl | ||
import com.intellij.psi.impl.source.tree.LeafElement | ||
import com.intellij.psi.impl.source.tree.PsiCommentImpl | ||
import com.intellij.psi.tree.IElementType | ||
import com.vk.kphpstorm.generics.psi.GenericInstantiationPsiCommentImpl | ||
|
||
class KphpStormASTFactory : DefaultASTFactoryImpl() { | ||
override fun createComment(type: IElementType, text: CharSequence): LeafElement { | ||
if (!text.startsWith("/*<") && !text.endsWith(">*/")) { | ||
return PsiCommentImpl(type, text) | ||
} | ||
|
||
return GenericInstantiationPsiCommentImpl(type, text) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/main/kotlin/com/vk/kphpstorm/completion/KphpGenericsReferenceContributor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package com.vk.kphpstorm.completion | ||
|
||
import com.intellij.openapi.util.TextRange | ||
import com.intellij.patterns.PlatformPatterns | ||
import com.intellij.psi.* | ||
import com.intellij.util.ProcessingContext | ||
import com.jetbrains.php.lang.psi.PhpPsiElementFactory | ||
import com.jetbrains.php.lang.psi.elements.FunctionReference | ||
import com.jetbrains.php.lang.psi.elements.PhpNamedElement | ||
import com.vk.kphpstorm.generics.psi.GenericInstantiationPsiCommentImpl | ||
|
||
/** | ||
* Контрибьютор который создает ссылки на классы внутри комментария | ||
* с описанием шаблонных типов при вызове функции. | ||
* | ||
* Подробнее в комментарии для [GenericInstantiationPsiCommentImpl]. | ||
*/ | ||
class KphpGenericsReferenceContributor : PsiReferenceContributor() { | ||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { | ||
registrar.registerReferenceProvider( | ||
PlatformPatterns.psiComment(), | ||
PhpPsiReferenceProvider() | ||
) | ||
} | ||
|
||
class PhpPsiReferenceProvider : PsiReferenceProvider() { | ||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> { | ||
if (element !is GenericInstantiationPsiCommentImpl) { | ||
return emptyArray() | ||
} | ||
|
||
val instances = element.extractInstances() | ||
|
||
return instances.map { (_, instance) -> | ||
instance.classes(element.project).map { klass -> | ||
PhpElementReference(element, klass, instance.pos.shiftLeft(element.startOffset)) | ||
} | ||
}.flatten().toTypedArray() | ||
} | ||
|
||
class PhpElementReference(element: PsiElement, result: PsiElement, private val myRange: TextRange? = null) : | ||
PsiReference { | ||
private val myElement: PsiElement | ||
private val myResult: PsiElement | ||
|
||
init { | ||
myElement = element | ||
myResult = result | ||
} | ||
|
||
override fun getElement() = myElement | ||
|
||
override fun getRangeInElement(): TextRange { | ||
if (myRange != null) { | ||
return myRange | ||
} | ||
val startOffset = 1 | ||
return TextRange(startOffset, myElement.textLength - 1) | ||
} | ||
|
||
override fun resolve() = myResult | ||
|
||
override fun getCanonicalText(): String = | ||
if (myResult is PhpNamedElement) myResult.fqn | ||
else myElement.parent.text | ||
|
||
override fun handleElementRename(newElementName: String): PsiElement { | ||
val text = element.text | ||
val start = text.slice(0 until rangeInElement.startOffset) | ||
val end = text.slice(rangeInElement.endOffset until text.length) | ||
|
||
val specText = start + newElementName + end | ||
|
||
val psi = PhpPsiElementFactory.createPhpPsiFromText( | ||
element.project, FunctionReference::class.java, "f$specText();" | ||
) | ||
|
||
val comment = psi.firstChild.nextSibling | ||
|
||
return myElement.replace(comment) | ||
} | ||
|
||
override fun bindToElement(element: PsiElement): PsiElement { | ||
throw UnsupportedOperationException() | ||
} | ||
|
||
override fun isReferenceTo(element: PsiElement): Boolean { | ||
return myResult === element | ||
} | ||
|
||
override fun isSoft() = true | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/main/kotlin/com/vk/kphpstorm/exphptype/ExPhpTypeClassString.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package com.vk.kphpstorm.exphptype | ||
|
||
import com.intellij.openapi.project.Project | ||
import com.jetbrains.php.lang.psi.elements.PhpPsiElement | ||
import com.jetbrains.php.lang.psi.resolve.types.PhpType | ||
|
||
/** | ||
* Type of special class constant (`Foo::class`). | ||
*/ | ||
class ExPhpTypeClassString(val inner: ExPhpType) : ExPhpType { | ||
override fun toString() = "class-string($inner)" | ||
|
||
override fun toHumanReadable(expr: PhpPsiElement) = "class-string($inner)" | ||
|
||
override fun equals(other: Any?) = other is ExPhpTypeClassString && inner == other.inner | ||
|
||
override fun hashCode() = 35 | ||
|
||
override fun toPhpType(): PhpType { | ||
return PhpType().add("class-string($inner)") | ||
} | ||
|
||
override fun getSubkeyByIndex(indexKey: String): ExPhpType? { | ||
return this | ||
} | ||
|
||
override fun instantiateGeneric(nameMap: Map<String, ExPhpType>): ExPhpType { | ||
// TODO: подумать тут | ||
val fqn = when (inner) { | ||
is ExPhpTypeInstance -> inner.fqn | ||
is ExPhpTypeGenericsT -> inner.nameT | ||
else -> "" | ||
} | ||
|
||
return nameMap[fqn]?.let { ExPhpTypeClassString(ExPhpTypeInstance(it.toString())) } ?: this | ||
} | ||
|
||
override fun isAssignableFrom(rhs: ExPhpType, project: Project): Boolean = when (rhs) { | ||
// нативный вывод типов дает тип string|class-string<T> для T::class, поэтому | ||
// необходимо обработать этот случай отдельно | ||
is ExPhpTypePipe -> { | ||
val containsString = rhs.items.any { it == ExPhpType.STRING } | ||
if (rhs.items.size == 2 && containsString) { | ||
val otherType = rhs.items.find { it != ExPhpType.STRING } | ||
if (otherType == null) false | ||
else inner.isAssignableFrom(otherType, project) | ||
} else false | ||
} | ||
// class-string<T> совместим только с class-string<E> при условии | ||
// что класс E является допустимым для класса T. | ||
is ExPhpTypeClassString -> inner.isAssignableFrom(rhs.inner, project) | ||
else -> false | ||
} | ||
|
||
companion object { | ||
// нативный вывод типов дает тип string|class-string<T> для T::class, | ||
// из-за этого в некоторых местах нужна дополнительная логика. | ||
fun isNativePipeWithString(pipe: ExPhpTypePipe): Boolean { | ||
if (pipe.items.size != 2) return false | ||
val otherType = pipe.items.find { it != ExPhpType.STRING } | ||
|
||
return otherType is ExPhpTypeClassString | ||
} | ||
|
||
fun getClassFromNativePipeWithString(pipe: ExPhpTypePipe): ExPhpType { | ||
return pipe.items.find { it != ExPhpType.STRING }!! | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/main/kotlin/com/vk/kphpstorm/exphptype/ExPhpTypeGenericT.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.vk.kphpstorm.exphptype | ||
|
||
import com.intellij.openapi.project.Project | ||
import com.jetbrains.php.lang.psi.elements.PhpPsiElement | ||
import com.jetbrains.php.lang.psi.resolve.types.PhpType | ||
|
||
/** | ||
* 'T' — is genericsT when it's defined in @kphp-generic, then it's genericsT on resolve, not class T | ||
* @see com.vk.kphpstorm.exphptype.psi.ExPhpTypeInstancePsiImpl.getType | ||
*/ | ||
class ExPhpTypeGenericsT(val nameT: String) : ExPhpType { | ||
override fun toString() = "%$nameT" | ||
|
||
override fun toHumanReadable(expr: PhpPsiElement) = "%$nameT" | ||
|
||
override fun toPhpType(): PhpType { | ||
return PhpType().add("%$nameT") | ||
} | ||
|
||
override fun getSubkeyByIndex(indexKey: String): ExPhpType? { | ||
return null | ||
} | ||
|
||
override fun instantiateGeneric(nameMap: Map<String, ExPhpType>): ExPhpType { | ||
return nameMap[nameT] ?: this | ||
} | ||
|
||
override fun isAssignableFrom(rhs: ExPhpType, project: Project): Boolean = when (rhs) { | ||
is ExPhpTypeAny -> true | ||
// todo shall we add any strict rules here? | ||
else -> true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.