IntelliJ Platform SDK DevGuide

Edit page

PHP Open API

##使用php-openapi

<depends>com.jetbrains.php</depends>

PHP PSI

com.jetbrains.php.lang.psi.elements *;

Utility Classes

PHP扩展点

PhpTypeProvider

这是一个代码片段,使通用工厂方法支持工作

<php.typeProvider2 implementation="com.jetbrains.php.lang.psi.resolve.types.PhpStaticFactoryTypeProvider2"/>

接口:

/** * Extension point to implement to provide Type information on various PhpPsiElements */ public interface PhpTypeProvider2 { ExtensionPointName<PhpTypeProvider2> EP_NAME = ExtensionPointName.create("com.intellij.php.typeProvider2"); /** * @return Your custom signature key, i.e. "?". Do not use any of PhpTypeSignatureKey.XXX constants though! */ char getKey(); /** * @param element to deduce type for - using only LOCAL info. <b>THIS IS MOST CRUCIAL ASPECT TO FOLLOW</b> * @return type for element, null if no insight. You can return a custom signature here to be later decoded by method below. */ @Nullable String getType(PsiElement element); /** * @param expression Signature expression to decode. You can use PhpIndex.getBySignature() to look up expression internals. * @param project well so you can reach the PhpIndex * @return null if no match */ Collection<? extends PhpNamedElement> getBySignature(String expression, Project project); }

我们的实现:包括参数值的完成贡献者.

/** */ public class PhpStaticFactoryTypeProvider extends CompletionContributor implements PhpTypeProvider2 { private static final Key<CachedValue<Map<String, Map<String, String>>>> STATIC_FACTORY_TYPE_MAP = new Key<CachedValue<Map<String, Map<String, String>>>>("STATIC_FACTORY_TYPE_MAP"); @Override public char getKey() { return 'S'; } @Nullable @Override public String getType(PsiElement e) { if (e instanceof MethodReference && ((MethodReference)e).isStatic()) { Map<String, Map<String, String>> methods = getStaticMethodTypesMap(e.getProject()); String refSignature = ((MethodReference)e).getSignature(); if (methods.containsKey(refSignature)) { PsiElement[] parameters = ((MethodReference)e).getParameters(); if (parameters.length > 0) { PsiElement parameter = parameters[0]; if (parameter instanceof StringLiteralExpression) { String param = ((StringLiteralExpression)parameter).getContents(); if (StringUtil.isNotEmpty(param)) return refSignature + "." + param; } } } } return null; } @Override public Collection<? extends PhpNamedElement> getBySignature(String expression, Project project) { Map<String, Map<String, String>> methods = getStaticMethodTypesMap(project); int dot = expression.lastIndexOf('.'); String refSignature = expression.substring(0, dot); Map<String, String> types = methods.get(refSignature); if (types != null) { String type = types.get(expression.substring(dot + 1)); if (type != null) return PhpIndex.getInstance(project).getAnyByFQN(type); } return Collections.emptySet(); } synchronized Map<String, Map<String, String>> getStaticMethodTypesMap(final Project project) { CachedValue<Map<String, Map<String, String>>> myStaticMethodTypesMap = project.getUserData(STATIC_FACTORY_TYPE_MAP); if (myStaticMethodTypesMap == null) { myStaticMethodTypesMap = CachedValuesManager.getManager(project).createCachedValue( new CachedValueProvider<Map<String, Map<String, String>>>() { @Nullable @Override public Result<Map<String, Map<String, String>>> compute() { Map<String, Map<String, String>> map = new THashMap<String, Map<String, String>>(); Collection<Variable> variables = getVariables(project, "STATIC_METHOD_TYPES"); for (Variable variable : variables) { if (!"\\PHPSTORM_META\\".equals(variable.getNamespaceName())) continue; PsiElement parent = variable.getParent(); if (parent instanceof AssignmentExpression) { PhpPsiElement value = ((AssignmentExpression)parent).getValue(); if (value instanceof ArrayCreationExpression) { for (ArrayHashElement element : ((ArrayCreationExpression)value).getHashElements()) { PhpPsiElement match = element.getKey(); if (match instanceof MethodReference) { String matchSignature = ((MethodReference)match).getSignature(); Map<String, String> types = map.get(matchSignature); if (types == null) { types = new THashMap<String, String>(); map.put(matchSignature, types); } PhpPsiElement val = element.getValue(); if (val instanceof ArrayCreationExpression) { PhpPsiElement child = val.getFirstPsiChild(); while (child != null) { if (child.getFirstPsiChild() instanceof BinaryExpression) { BinaryExpression binary = ((BinaryExpression)child.getFirstPsiChild()); if (binary.getOperation().getNode().getElementType() == PhpTokenTypes.kwINSTANCEOF) { PsiElement leftOperand = binary.getLeftOperand(); PsiElement rightOperand = binary.getRightOperand(); if (leftOperand instanceof StringLiteralExpression && rightOperand != null) { types.put(((StringLiteralExpression)leftOperand).getContents(), rightOperand.getText()); } } } child = child.getNextPsiSibling(); } } } } } } } return CachedValueProvider.Result.create(map, getMetaFile(project)); } }, false); project.putUserData(STATIC_FACTORY_TYPE_MAP, myStaticMethodTypesMap); } return myStaticMethodTypesMap.getValue(); } private static Collection<Variable> getVariables(Project project, final String key) { PsiFile file = getMetaFile(project); final Collection<Variable> result = new SmartList<Variable>(); if (file instanceof PhpFile) { //AG not the most elegant way - but still an allowed usage. //noinspection deprecation file.accept(new PhpRecursiveElementVisitor() { @Override public void visitPhpAssignmentExpression(AssignmentExpression assignmentExpression) { PhpPsiElement variable = assignmentExpression.getVariable(); if (variable instanceof Variable) { if (((Variable)variable).getNameCS().equals(key)) { result.add((Variable)variable); } } } }); } return result; } public static PsiFile getMetaFile(Project project) { VirtualFile metaFile = LocalFileSystem.getInstance().findFileByPath(project.getBasePath() + File.separatorChar + ".phpstorm.meta.php"); return metaFile != null ? PsiManager.getInstance(project).findFile(metaFile) : null; } @Override public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { final ProcessingContext context = new ProcessingContext(); PsiElement position = parameters.getPosition(); if (parameters.getCompletionType() == CompletionType.BASIC && psiElement().withParent(StringLiteralExpression.class).withSuperParent(2, ParameterList.class) .accepts(position, context)) { ParameterListOwner parameterListOwner = PsiTreeUtil.getStubOrPsiParentOfType(position, ParameterListOwner.class); if (parameterListOwner instanceof MethodReference && ((MethodReference)parameterListOwner).isStatic()) { Map<String, String> map = getStaticMethodTypesMap(position.getProject()).get(((MethodReference)parameterListOwner).getSignature()); for (String s : map.keySet()) { result.addElement(LookupElementBuilder.create(s).appendTailText(map.get(s), true)); } } } super.fillCompletionVariants(parameters, result); } }

要完成工作注册是必需的:

<completion.contributor language="PHP" implementationClass="com.jetbrains.php.lang.psi.resolve.types.PhpStaticFactoryTypeProvider"/>
Last modified: 9 May 2019