Skip to content

Commit

Permalink
Fixed class property completion when using nested states
Browse files Browse the repository at this point in the history
  • Loading branch information
ekvedaras committed Nov 27, 2022
1 parent f96a410 commit cd59cca
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### Fixed
- Incorrect reports of unknown columns when using nested states
- Class property inspection when using nested states
- Class property completion when using nested states

## [2.0.1]
### Fixed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
package com.github.ekvedaras.classfactoryphpstorm.domain.method.state

import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactory
import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactory.Companion.asClassFactory
import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactoryMethodReference
import com.github.ekvedaras.classfactoryphpstorm.domain.closureState.AttributeAccess
import com.github.ekvedaras.classfactoryphpstorm.integration.otherMethods.type.AttributesArrayValueTypeProvider
import com.github.ekvedaras.classfactoryphpstorm.support.DomainException
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.getActualClassReference
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.getClass
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactory
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactoryStateMethod
import com.intellij.psi.util.childrenOfType
import com.jetbrains.php.lang.psi.elements.ArrayAccessExpression
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression
import com.jetbrains.php.lang.psi.elements.ArrayHashElement
import com.jetbrains.php.lang.psi.elements.MethodReference

class StateMethodReferenceOutsideFactory(private val methodReference: MethodReference) : ClassFactoryMethodReference {
override val classFactory: ClassFactory
override val classFactory: ClassFactory = if (methodReference.firstPsiChild is ArrayAccessExpression) {
val attributeAccess = AttributeAccess(methodReference.firstPsiChild as ArrayAccessExpression)
val type = attributeAccess.getCompleteType(AttributesArrayValueTypeProvider())
if (! type.isClassFactory(methodReference.project)) throw StateMethodReferenceOutsideFactoryException.notStateMethodReference()

init {
type.asClassFactory(methodReference.project) ?: throw StateMethodReferenceOutsideFactoryException.unableToFindMethodClass()
} else {
if (!methodReference.isClassFactoryStateMethod()) throw StateMethodReferenceOutsideFactoryException.notStateMethodReference()
classFactory = ClassFactory(

ClassFactory(
methodReference.getActualClassReference()?.getClass()
?: throw StateMethodReferenceOutsideFactoryException.unableToFindMethodClass()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.github.ekvedaras.classfactoryphpstorm.integration.otherMethods.completion

import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactory.Companion.asClassFactory
import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactoryMethodReference
import com.github.ekvedaras.classfactoryphpstorm.domain.closureState.AttributeAccess
import com.github.ekvedaras.classfactoryphpstorm.domain.method.make.MakeMethodReference
import com.github.ekvedaras.classfactoryphpstorm.domain.method.state.StateMethodReferenceInsideFactory
import com.github.ekvedaras.classfactoryphpstorm.domain.method.state.StateMethodReferenceOutsideFactory
import com.github.ekvedaras.classfactoryphpstorm.integration.otherMethods.type.AttributesArrayValueTypeProvider
import com.github.ekvedaras.classfactoryphpstorm.support.DomainException
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isArrayHashValueOf
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactory
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactoryMakeMethod
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactoryState
import com.github.ekvedaras.classfactoryphpstorm.support.Utilities.Companion.isClassFactoryStateMethod
Expand All @@ -14,8 +18,10 @@ import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.openapi.project.DumbService
import com.intellij.psi.PsiReference
import com.intellij.psi.util.parentOfType
import com.intellij.util.ProcessingContext
import com.jetbrains.php.lang.psi.elements.ArrayAccessExpression
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression
import com.jetbrains.php.lang.psi.elements.ArrayHashElement
import com.jetbrains.php.lang.psi.elements.MethodReference
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.ekvedaras.classfactoryphpstorm.support

import com.github.ekvedaras.classfactoryphpstorm.domain.ClassFactory.Companion.asClassFactory
import com.github.ekvedaras.classfactoryphpstorm.domain.closureState.AttributeAccess
import com.github.ekvedaras.classfactoryphpstorm.integration.otherMethods.type.AttributesArrayValueTypeProvider
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.util.childrenOfType
Expand Down Expand Up @@ -79,7 +81,12 @@ class Utilities private constructor() {
this.name == "make" && this.getActualClassReference()?.getClass()?.isClassFactory() ?: false

fun MethodReference.isClassFactoryStateMethod() =
this.name == "state" && this.getActualClassReference()?.getClass()?.isClassFactory() ?: false
this.name == "state" && this.getActualClassReference()?.getClass()?.isClassFactory() ?: (
this.firstPsiChild is ArrayAccessExpression
&& AttributeAccess(this.firstPsiChild as ArrayAccessExpression)
.getCompleteType(AttributesArrayValueTypeProvider())
.isClassFactory(this.project)
)

fun PsiElement.isArrayHashValueOf(arrayHashElement: ArrayHashElement) = this == arrayHashElement.value

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ internal class StateMethodInsideFactoryTest : EssentialTestCase() {
assertCompletionContains("id", "exists", "accountReference", "name", "tradingName", "currency", "ratingInputs")
}

fun testNestedStateCalls() {
fun testNestedStateCallsProduceCorrectInspections() {
assertInspection("nestedStateCalls.php", this.incorrectPropertyTypeInspection())
assertInspection("nestedStateCalls.php", this.incorrectPropertyTypeInClosureReturnsInspection())
assertInspection("nestedStateCalls.php", this.incorrectPropertyTypeInDirectlyPassedClosureReturnedArrayValues())
assertInspection("nestedStateCalls.php", this.propertyNotFoundInspection())
assertInspection("nestedStateCalls.php", this.propertyNotFoundInAttributesArrayInspection())
assertInspection("nestedStateCalls.php", this.propertyNotFoundInArrayKeysInDirectlyPassedClosure())
}

fun testNestedStateCallsCorrectlyFindsReferences() {
val usages = myFixture.testFindUsagesUsingAction("nestedStateCalls.php")

assertEquals(2, usages.size)
Expand All @@ -52,4 +54,11 @@ internal class StateMethodInsideFactoryTest : EssentialTestCase() {
assertTrue(usage.element?.textRange?.endOffset == usage.navigationRange.endOffset + 1)
}
}

fun testNestedStateCallsCorrectlyComplete() {
myFixture.configureByFile("nestedStateCallsCaretAtNestedState.php")
myFixture.completeBasic()

assertCompletionContains("value")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

class Id {
public readonly string $value;
}

class Age {
public readonly int $value;
}


class Account {
public function __construct(
public readonly Id $id,
public readonly Age $age,
) {}
}

class IdFactory extends EKvedaras\ClassFactory\ClassFactory {
protected string $class = Id::class;

protected function definition(): array
{
return [
'value' => 'abc',
];
}
}

class AgeFactory extends EKvedaras\ClassFactory\ClassFactory {
protected string $class = Age::class;

protected function definition(): array
{
return [
'value' => 1,
];
}
}

class AccountFactory extends EKvedaras\ClassFactory\ClassFactory {
protected string $class = Account::class;

protected function definition(): array
{
return [
'id' => IdFactory::new(),
'age' => AgeFactory::new(),
];
}

public function specialState1(): static
{
return $this->state(fn (array $attributes) => [
'id' => 1,
'age' => $attributes['age']->state([
'<caret>'
]),
]);
}
}

0 comments on commit cd59cca

Please sign in to comment.