/src/main/java/de/espend/idea/php/generics/utils/PhpTypeProviderUtil.java

https://github.com/Haehnchen/idea-php-generics-plugin · Java · 196 lines · 114 code · 36 blank · 46 comment · 30 complexity · 4e78839f0e496e3b778f48dd220ceabc MD5 · raw file

  1. package de.espend.idea.php.generics.utils;
  2. import com.intellij.openapi.util.text.StringUtil;
  3. import com.intellij.psi.PsiElement;
  4. import com.jetbrains.php.PhpIndex;
  5. import com.jetbrains.php.lang.psi.elements.*;
  6. import org.apache.commons.lang.StringUtils;
  7. import org.jetbrains.annotations.NotNull;
  8. import org.jetbrains.annotations.Nullable;
  9. import java.util.ArrayList;
  10. import java.util.Collection;
  11. import java.util.Set;
  12. /**
  13. * @author Daniel Espendiller <daniel@espendiller.net>
  14. */
  15. public class PhpTypeProviderUtil {
  16. /**
  17. * Creates a signature for PhpType implementation which must be resolved inside 'getBySignature'
  18. *
  19. * eg. foo(MyClass::class) => "#F\\foo|#K#C\\Foo.class"
  20. *
  21. * foo($this->foo), foo('foobar')
  22. */
  23. @Nullable
  24. public static String getReferenceSignatureByIndex(@NotNull FunctionReference functionReference, int index) {
  25. PsiElement[] parameters = functionReference.getParameters();
  26. if(parameters.length < index) {
  27. return null;
  28. }
  29. PsiElement parameter = parameters[index];
  30. // we already have a string value
  31. if ((parameter instanceof StringLiteralExpression)) {
  32. String param = ((StringLiteralExpression)parameter).getContents();
  33. if (StringUtil.isNotEmpty(param)) {
  34. return param;
  35. }
  36. return null;
  37. }
  38. // whitelist here; we can also provide some more but think of performance
  39. // Service::NAME, $this->name and Entity::CLASS;
  40. if ((parameter instanceof ClassConstantReference || parameter instanceof FieldReference)) {
  41. String signature = ((PhpReference) parameter).getSignature();
  42. if (StringUtil.isNotEmpty(signature)) {
  43. return signature;
  44. }
  45. }
  46. return null;
  47. }
  48. public static Collection<String> getReferenceSignatures(@NotNull FunctionReference functionReference) {
  49. Collection<String> signatures = new ArrayList<>();
  50. for (PsiElement parameter : functionReference.getParameters()) {
  51. String signature = null;
  52. // we already have a string value
  53. if ((parameter instanceof StringLiteralExpression)) {
  54. String param = ((StringLiteralExpression)parameter).getContents();
  55. if (StringUtil.isNotEmpty(param)) {
  56. signature = param;
  57. }
  58. } else if ((parameter instanceof ClassConstantReference || parameter instanceof FieldReference)) {
  59. // whitelist here; we can also provide some more but think of performance
  60. // Service::NAME, $this->name and Entity::CLASS;
  61. String param = ((PhpReference) parameter).getSignature();
  62. if (StringUtil.isNotEmpty(param)) {
  63. signature = param;
  64. }
  65. }
  66. signatures.add(signature);
  67. }
  68. return signatures;
  69. }
  70. /**
  71. * Creates a signature for PhpType implementation which must be resolved inside 'getBySignature'
  72. *
  73. * eg. foo(MyClass::class) => "#F\\foo|#K#C\\Foo.class"
  74. *
  75. * foo($this->foo), foo('foobar')
  76. */
  77. @Nullable
  78. public static String getReferenceSignatureByFirstParameter(@NotNull FunctionReference functionReference, char trimKey) {
  79. String refSignature = functionReference.getSignature();
  80. if(StringUtil.isEmpty(refSignature)) {
  81. return null;
  82. }
  83. PsiElement[] parameters = functionReference.getParameters();
  84. if(parameters.length == 0) {
  85. return null;
  86. }
  87. PsiElement parameter = parameters[0];
  88. // we already have a string value
  89. if ((parameter instanceof StringLiteralExpression)) {
  90. String param = ((StringLiteralExpression)parameter).getContents();
  91. if (StringUtil.isNotEmpty(param)) {
  92. return refSignature + trimKey + param;
  93. }
  94. return null;
  95. }
  96. // whitelist here; we can also provide some more but think of performance
  97. // Service::NAME, $this->name and Entity::CLASS;
  98. if ((parameter instanceof ClassConstantReference || parameter instanceof FieldReference)) {
  99. String signature = ((PhpReference) parameter).getSignature();
  100. if (StringUtil.isNotEmpty(signature)) {
  101. return refSignature + trimKey + signature;
  102. }
  103. }
  104. return null;
  105. }
  106. /**
  107. * we can also pipe php references signatures and resolve them here
  108. * overwrite parameter to get string value
  109. */
  110. @Nullable
  111. public static String getResolvedParameter(@NotNull PhpIndex phpIndex, @NotNull String parameter) {
  112. return getResolvedParameter(phpIndex, parameter, null, 0);
  113. }
  114. /**
  115. * we can also pipe php references signatures and resolve them here
  116. * overwrite parameter to get string value
  117. */
  118. @Nullable
  119. public static String getResolvedParameter(@NotNull PhpIndex phpIndex, @NotNull String parameter, @Nullable Set<String> visited, int depth) {
  120. // PHP 5.5 class constant: "Class\Foo::class"
  121. if(parameter.startsWith("#K#C")) {
  122. // PhpStorm9: #K#C\Class\Foo.class
  123. if(parameter.endsWith(".class")) {
  124. return StringUtils.stripStart(parameter.substring(4, parameter.length() - 6), "\\");
  125. }
  126. }
  127. // #K#C\Class\Foo.property
  128. // #K#C\Class\Foo.CONST
  129. if(parameter.startsWith("#")) {
  130. // get psi element from signature
  131. Collection<? extends PhpNamedElement> signTypes = phpIndex.getBySignature(parameter, visited, depth);
  132. if(signTypes.size() == 0) {
  133. return null;
  134. }
  135. // get string value
  136. parameter = GenericsUtil.getStringValue(signTypes.iterator().next());
  137. if(parameter == null) {
  138. return null;
  139. }
  140. }
  141. return parameter;
  142. }
  143. /**
  144. * We can have multiple types inside a TypeProvider; split them on "|" so that we dont get empty types
  145. *
  146. * #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.getRepository|
  147. * #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.getRepository
  148. */
  149. @NotNull
  150. public static Collection<? extends PhpNamedElement> getTypeSignature(@NotNull PhpIndex phpIndex, @NotNull String signature) {
  151. if (!signature.contains("|")) {
  152. return phpIndex.getBySignature(signature, null, 0);
  153. }
  154. Collection<PhpNamedElement> elements = new ArrayList<>();
  155. for (String s : signature.split("\\|")) {
  156. elements.addAll(phpIndex.getBySignature(s, null, 0));
  157. }
  158. return elements;
  159. }
  160. }