From fad36d452ad6dc5274479410f137c8edea70f291 Mon Sep 17 00:00:00 2001 From: Benoit Date: Sun, 20 Jan 2019 02:18:13 +0100 Subject: [PATCH 1/3] Type hint repositories when using custom getRepository()-like method --- .../ObjectRepositoryTypeProvider.java | 21 +++++--- .../ObjectRepositoryTypeProviderTest.java | 53 ++++++++++++++++++- .../tests/doctrine/fixtures/classes.php | 10 +++- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java index 4d0ff45db..a867dd4b3 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java @@ -4,10 +4,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.jetbrains.php.PhpIndex; -import com.jetbrains.php.lang.psi.elements.Method; -import com.jetbrains.php.lang.psi.elements.MethodReference; -import com.jetbrains.php.lang.psi.elements.PhpClass; -import com.jetbrains.php.lang.psi.elements.PhpNamedElement; +import com.jetbrains.php.lang.psi.elements.*; import com.jetbrains.php.lang.psi.resolve.types.PhpType; import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3; import fr.adrienbrault.idea.symfony2plugin.Settings; @@ -27,6 +24,8 @@ public class ObjectRepositoryTypeProvider implements PhpTypeProvider3 { private static MethodMatcher.CallToSignature[] GET_REPOSITORIES_SIGNATURES = new MethodMatcher.CallToSignature[] { new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ManagerRegistry", "getRepository"), new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectManager", "getRepository"), + /*new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\EntityController", "getRepo"), + new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\SecurityController", "getRepo"),*/ }; final public static char TRIM_KEY = '\u0185'; @@ -43,7 +42,9 @@ public PhpType getType(PsiElement e) { return null; } - if(!(e instanceof MethodReference) || !PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepository")) { + if(!(e instanceof MethodReference) + || (!PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepository") + && !PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepo"))) { return null; } @@ -80,7 +81,15 @@ public Collection getBySignature(String expression, S return phpNamedElementCollections; } - if (!PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, GET_REPOSITORIES_SIGNATURES)) { + String returnType = ((Method) phpNamedElement).getReturnType() == null + ? null + : ((Method) phpNamedElement).getReturnType().getType().toString(); + String repoClass = "\\Doctrine\\Common\\Persistence\\ObjectRepository"; + + boolean isMethod = PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, GET_REPOSITORIES_SIGNATURES); + boolean isReturnType = returnType != null && PhpElementsUtil.isInstanceOf(project, returnType, repoClass); + + if (!isMethod && !isReturnType) { return phpNamedElementCollections; } diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java index 6fd4b1b2f..85c66181e 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java @@ -45,7 +45,6 @@ public void testGetRepositoryResolveByRepository() { "$em->getRepository(\\Foo\\Bar::class)->bar();", PlatformPatterns.psiElement(Method.class).withName("bar") ); - } /** @@ -61,6 +60,58 @@ public void testGetRepositoryResolveByRepositoryApiClassConstantCompatibility() ); } + /** + * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider + */ + public void testGetRepositoryResolveByReturnTypeMethod() { + //System.out.println("YESSSSSSS MONGAGA"); + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepo('\\Foo\\Bar')->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + + assertPhpReferenceSignatureContains(PhpFileType.INSTANCE, + "getRepo('\\Foo\\Bar')->bar();", + "#M#" + '\u0151' + "#M#C\\Foo\\BarController.getRepo" + '\u0185' + "\\Foo\\Bar.bar" + ); + + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepo(\\Foo\\Bar::class)->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + + } + + public void testGetRepositoryNotResolveByWrongMethod() { + System.out.println("testGetRepositoryNotResolveByWrongMethod"); + + assertPhpReferenceNotResolveTo(PhpFileType.INSTANCE, + "getBoo(\\Foo\\Bar::class)->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + } + + /** + * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider + */ + public void testGetRepositoryResolveByReturnTypeMethodApiClassConstantCompatibility() { + String result = "#M#" + '\u0151' + "#M#C\\Foo\\BarController.getRepo" + '\u0185' + "#K#C\\Foo\\Bar.class.bar"; + + assertPhpReferenceSignatureContains(PhpFileType.INSTANCE, "getRepo(\\Foo\\Bar::class)->bar();", + result + ); + } + /** * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider */ diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php index a348e2c6f..794e5c46a 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php @@ -11,14 +11,20 @@ function getRepository(); } namespace Foo { - use Doctrine\Common\Persistence\ObjectRepository; abstract class Bar implements ObjectRepository {} - class BarRepository { + class BarRepository implements ObjectRepository { public function bar() {} } + + class WrongClass {} + + class BarController { + public function getRepo($name): BarRepository {} + public function getBoo($name): WrongClass {} + } } namespace Doctrine\Common\Persistence From 58397add8feec4f0a0464e05b00bcdaeb3c99941 Mon Sep 17 00:00:00 2001 From: Benoit Date: Sun, 20 Jan 2019 02:18:13 +0100 Subject: [PATCH 2/3] Type hint repositories when using custom getRepository()-like method --- .../ObjectRepositoryTypeProvider.java | 22 +++++--- .../ObjectRepositoryTypeProviderTest.java | 50 ++++++++++++++++++- .../tests/doctrine/fixtures/classes.php | 10 +++- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java index 4d0ff45db..7f8e579a4 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java @@ -4,10 +4,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.jetbrains.php.PhpIndex; -import com.jetbrains.php.lang.psi.elements.Method; -import com.jetbrains.php.lang.psi.elements.MethodReference; -import com.jetbrains.php.lang.psi.elements.PhpClass; -import com.jetbrains.php.lang.psi.elements.PhpNamedElement; +import com.jetbrains.php.lang.psi.elements.*; import com.jetbrains.php.lang.psi.resolve.types.PhpType; import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3; import fr.adrienbrault.idea.symfony2plugin.Settings; @@ -27,8 +24,12 @@ public class ObjectRepositoryTypeProvider implements PhpTypeProvider3 { private static MethodMatcher.CallToSignature[] GET_REPOSITORIES_SIGNATURES = new MethodMatcher.CallToSignature[] { new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ManagerRegistry", "getRepository"), new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectManager", "getRepository"), + /*new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\EntityController", "getRepo"), + new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\SecurityController", "getRepo"),*/ }; + private static String repositoryClass = "\\Doctrine\\Common\\Persistence\\ObjectRepository"; + final public static char TRIM_KEY = '\u0185'; @Override @@ -43,11 +44,12 @@ public PhpType getType(PsiElement e) { return null; } - if(!(e instanceof MethodReference) || !PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepository")) { + if(!(e instanceof MethodReference) + || (!PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepository") + && !PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepo"))) { return null; } - String refSignature = ((MethodReference)e).getSignature(); if(StringUtil.isEmpty(refSignature)) { return null; @@ -80,7 +82,13 @@ public Collection getBySignature(String expression, S return phpNamedElementCollections; } - if (!PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, GET_REPOSITORIES_SIGNATURES)) { + PhpReturnType returnType = ((Method) phpNamedElement).getReturnType(); + String returnTypeName = returnType == null ? null : returnType.getType().toString(); + + boolean isMethod = PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, GET_REPOSITORIES_SIGNATURES); + boolean isReturnType = returnType != null && PhpElementsUtil.isInstanceOf(project, returnTypeName, repositoryClass); + + if (!isMethod && !isReturnType) { return phpNamedElementCollections; } diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java index 6fd4b1b2f..dc9a2d9f8 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryTypeProviderTest.java @@ -45,7 +45,6 @@ public void testGetRepositoryResolveByRepository() { "$em->getRepository(\\Foo\\Bar::class)->bar();", PlatformPatterns.psiElement(Method.class).withName("bar") ); - } /** @@ -61,6 +60,55 @@ public void testGetRepositoryResolveByRepositoryApiClassConstantCompatibility() ); } + /** + * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider + */ + public void testGetRepositoryResolveByReturnTypeMethod() { + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepo('\\Foo\\Bar')->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + + assertPhpReferenceSignatureContains(PhpFileType.INSTANCE, + "getRepo('\\Foo\\Bar')->bar();", + "#M#" + '\u0151' + "#M#C\\Foo\\BarController.getRepo" + '\u0185' + "\\Foo\\Bar.bar" + ); + + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepo(\\Foo\\Bar::class)->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + + } + + public void testGetRepositoryNotResolveByWrongMethod() { + assertPhpReferenceNotResolveTo(PhpFileType.INSTANCE, + "getBoo(\\Foo\\Bar::class)->bar();", + PlatformPatterns.psiElement(Method.class).withName("bar") + ); + } + + /** + * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider + */ + public void testGetRepositoryResolveByReturnTypeMethodApiClassConstantCompatibility() { + String result = "#M#" + '\u0151' + "#M#C\\Foo\\BarController.getRepo" + '\u0185' + "#K#C\\Foo\\Bar.class.bar"; + + assertPhpReferenceSignatureContains(PhpFileType.INSTANCE, "getRepo(\\Foo\\Bar::class)->bar();", + result + ); + } + /** * @see fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider */ diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php index a348e2c6f..794e5c46a 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/fixtures/classes.php @@ -11,14 +11,20 @@ function getRepository(); } namespace Foo { - use Doctrine\Common\Persistence\ObjectRepository; abstract class Bar implements ObjectRepository {} - class BarRepository { + class BarRepository implements ObjectRepository { public function bar() {} } + + class WrongClass {} + + class BarController { + public function getRepo($name): BarRepository {} + public function getBoo($name): WrongClass {} + } } namespace Doctrine\Common\Persistence From d29f265276f85270ad1e8419e3e028f32c14450f Mon Sep 17 00:00:00 2001 From: Benoit Date: Sun, 20 Jan 2019 03:25:37 +0100 Subject: [PATCH 3/3] a --- .../doctrine/ObjectRepositoryTypeProvider.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java index 7f8e579a4..993add997 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryTypeProvider.java @@ -24,8 +24,6 @@ public class ObjectRepositoryTypeProvider implements PhpTypeProvider3 { private static MethodMatcher.CallToSignature[] GET_REPOSITORIES_SIGNATURES = new MethodMatcher.CallToSignature[] { new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ManagerRegistry", "getRepository"), new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectManager", "getRepository"), - /*new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\EntityController", "getRepo"), - new MethodMatcher.CallToSignature("\\QsGeneralBundle\\Controller\\SecurityController", "getRepo"),*/ }; private static String repositoryClass = "\\Doctrine\\Common\\Persistence\\ObjectRepository"; @@ -44,9 +42,7 @@ public PhpType getType(PsiElement e) { return null; } - if(!(e instanceof MethodReference) - || (!PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepository") - && !PhpElementsUtil.isMethodWithFirstStringOrFieldReference(e, "getRepo"))) { + if(!(e instanceof MethodReference)) { return null; }