Skip to content

add PhpStorm 2020.1 build gradle support #1453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 21, 2020
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ before_install:
- "export ORG_GRADLE_PROJECT_annotationPluginVersion=${ANNOTATION_PLUGIN_VERSION}"

env:
- PHPSTORM_ENV="skip incomplete" IDEA_VERSION="IU-2019.2" PHP_PLUGIN_VERSION="192.5728.108" TWIG_PLUGIN_VERSION="192.5728.26" TOOLBOX_PLUGIN_VERSION="0.4.6" ANNOTATION_PLUGIN_VERSION="5.3" DQL_PLUGIN_VERSION="192.5728.12"
- PHPSTORM_ENV="skip incomplete" IDEA_VERSION="IU-2020.1" PHP_PLUGIN_VERSION="201.6668.153" TWIG_PLUGIN_VERSION="201.6668.153" TOOLBOX_PLUGIN_VERSION="0.4.6" ANNOTATION_PLUGIN_VERSION="5.3" DQL_PLUGIN_VERSION="201.6668.60"

script:
- "./gradlew check verifyPlugin buildPlugin"
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ intellij {
}

patchPluginXml {
sinceBuild '192'
sinceBuild '201'
changeNotes = htmlFixer('src/main/resources/META-INF/change-notes.html')
}

Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ideaVersion = IU-2019.2
phpPluginVersion = 192.5728.108
twigPluginVersion = 192.5728.26
dqlPluginVersion = 192.5728.12
ideaVersion = IU-2020.1
phpPluginVersion = 201.6668.153
twigPluginVersion = 201.6668.153
dqlPluginVersion = 201.6668.60
toolboxPluginVersion = 0.4.6
annotationPluginVersion = 5.3
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private Map<String, LookupElement> getModelLookupElements() {
}

@Override
public void processNames(@NotNull Processor<String> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) {
public void processNames(@NotNull Processor<? super String> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) {
for(String name: getServiceCollector().getServices().keySet()) {
processor.process(name);
}
Expand Down Expand Up @@ -174,7 +174,7 @@ public void processNames(@NotNull Processor<String> processor, @NotNull GlobalSe
}

@Override
public void processElementsWithName(@NotNull String name, @NotNull Processor<NavigationItem> processor, @NotNull FindSymbolParameters parameters) {
public void processElementsWithName(@NotNull String name, @NotNull Processor<? super NavigationItem> processor, @NotNull FindSymbolParameters parameters) {

for(ContainerService containerService: getServiceCollector().collect()) {
if(containerService.getName().equals(name)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,35 @@

import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.parser.PhpElementTypes;
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.resolve.types.PhpType;
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3;
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider4;
import fr.adrienbrault.idea.symfony2plugin.Settings;
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PhpTypeProviderUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Resolve "find*" and attach the entity from the getRepository method
*
* "$om->getRepository('\Foo\Bar')->find('foobar')->get<caret>Id()"
*
* @author Daniel Espendiller <[email protected]>
*/
public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider3 {
private static MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] {
public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider4 {
private static final MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] {
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "find"),
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findOneBy"),
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findAll"),
Expand All @@ -48,18 +51,7 @@ public char getKey() {
@Nullable
@Override
public PhpType getType(PsiElement e) {
if (!Settings.getInstance(e.getProject()).pluginEnabled) {
return null;
}

// filter out method calls without parameter
// $this->get('service_name')
if(!PlatformPatterns
.psiElement(PhpElementTypes.METHOD_REFERENCE)
.withChild(PlatformPatterns
.psiElement(PhpElementTypes.PARAMETER_LIST)
).accepts(e)) {

if (!(e instanceof MethodReference) || !Settings.getInstance(e.getProject()).pluginEnabled) {
return null;
}

Expand All @@ -75,16 +67,6 @@ public PhpType getType(PsiElement e) {
return null;
}

// at least one parameter is necessary on some finds
PsiElement[] parameters = methodRef.getParameters();
if(!methodRefName.equals("findAll")) {
if(parameters.length == 0) {
return null;
}
} else if(parameters.length != 0) {
return null;
}

// we can get the repository name from the signature calls
// #M#?#M#?#M#C\Foo\Bar\Controller\BarController.get?doctrine.getRepository?EntityBundle:User.find
String repositorySignature = methodRef.getSignature();
Expand All @@ -105,57 +87,64 @@ public PhpType getType(PsiElement e) {
return new PhpType().add("#" + this.getKey() + refSignature + TRIM_KEY + repositorySignature);
}

@Nullable
@Override
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
// get back our original call
int endIndex = expression.lastIndexOf(TRIM_KEY);
public PhpType complete(String s, Project project) {
int endIndex = s.lastIndexOf(TRIM_KEY);
if(endIndex == -1) {
return Collections.emptySet();
}

String originalSignature = expression.substring(0, endIndex);
String parameter = expression.substring(endIndex + 1);

// search for called method
PhpIndex phpIndex = PhpIndex.getInstance(project);
Collection<? extends PhpNamedElement> phpNamedElementCollections = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);
if(phpNamedElementCollections.size() == 0) {
return Collections.emptySet();
}

Method method = getObjectRepositoryCall(phpNamedElementCollections);
if(method == null) {
return Collections.emptySet();
return null;
}

// we can also pipe php references signatures and resolve them here
// overwrite parameter to get string value
parameter = PhpTypeProviderUtil.getResolvedParameter(phpIndex, parameter);
String originalSignature = s.substring(0, endIndex);
String parameter = s.substring(endIndex + 1);
parameter = PhpTypeProviderUtil.getResolvedParameter(PhpIndex.getInstance(project), parameter);
if(parameter == null) {
return Collections.emptySet();
return null;
}

PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter);
if(phpClass == null) {
return Collections.emptySet();
return null;
}

String name = method.getName();
if(name.equals("findAll") || name.equals("findBy")) {
method.getType().add(phpClass.getFQN() + "[]");
return phpNamedElementCollections;
PhpIndex phpIndex = PhpIndex.getInstance(project);

Collection<? extends PhpNamedElement> typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);

// ->getRepository(SecondaryMarket::class)->findAll() => "findAll", but only if its a instance of this method;
// so non Doctrine method are already filtered
Set<String> resolveMethods = getObjectRepositoryCall(typeSignature).stream()
.map(PhpNamedElement::getName)
.collect(Collectors.toSet());

if (resolveMethods.isEmpty()) {
return null;
}

return PhpTypeProviderUtil.mergeSignatureResults(phpNamedElementCollections, phpClass);
PhpType phpType = new PhpType();

resolveMethods.stream()
.map(name -> name.equals("findAll") || name.equals("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN())
.collect(Collectors.toSet())
.forEach(phpType::add);

return phpType;
}

@Override
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
return null;
}

private Method getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
@NotNull
private Collection<Method> getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
Collection<Method> methods = new HashSet<>();
for (PhpNamedElement phpNamedElement: phpNamedElements) {
if(phpNamedElement instanceof Method && PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, FIND_SIGNATURES)) {
return (Method) phpNamedElement;
methods.add((Method) phpNamedElement);
}
}

return null;
return methods;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.jetbrains.php.lang.psi.elements.*;
Expand All @@ -12,6 +11,7 @@
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -41,10 +41,10 @@ public class ParameterLanguageInjector implements MultiHostInjector {
};

private final MethodLanguageInjection[] LANGUAGE_INJECTIONS = {
new MethodLanguageInjection(LANGUAGE_ID_CSS, "@media all { ", " }", CSS_SELECTOR_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_XPATH, null, null, XPATH_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_JSON, null, null, JSON_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_DQL, null, null, DQL_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_CSS, "@media all { ", " }", CSS_SELECTOR_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_XPATH, null, null, XPATH_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_JSON, null, null, JSON_SIGNATURES),
new MethodLanguageInjection(LANGUAGE_ID_DQL, null, null, DQL_SIGNATURES),
};

public static final String LANGUAGE_ID_CSS = "CSS";
Expand Down Expand Up @@ -88,26 +88,23 @@ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull
}

for (MethodLanguageInjection languageInjection : LANGUAGE_INJECTIONS) {
Language language = languageInjection.getLanguage();
if (language == null) {
continue;
}
// $crawler->filter('...')
// $em->createQuery('...')
// JsonResponse::fromJsonString('...')
if (parent instanceof MethodReference) {
if (PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) parent, languageInjection.getSignatures())) {
injectLanguage(registrar, expr, language, languageInjection);
injectLanguage(registrar, expr, languageInjection);
return;
}
}
// $dql = "...";
else if (parent instanceof AssignmentExpression) {
if (LANGUAGE_ID_DQL.equals(language.getID())) {
Language language = languageInjection.getLanguage();
if (language != null && LANGUAGE_ID_DQL.equals(language.getID())) {
PhpPsiElement variable = ((AssignmentExpression) parent).getVariable();
if (variable instanceof Variable) {
if (DQL_VARIABLE_NAME.equals(variable.getName())) {
injectLanguage(registrar, expr, language, languageInjection);
injectLanguage(registrar, expr, languageInjection);
return;
}
}
Expand All @@ -117,28 +114,33 @@ else if (parent instanceof AssignmentExpression) {

}

private void injectLanguage(@NotNull MultiHostRegistrar registrar, @NotNull StringLiteralExpressionImpl element, Language language, MethodLanguageInjection languageInjection) {
private void injectLanguage(@NotNull MultiHostRegistrar registrar, @NotNull StringLiteralExpressionImpl element, MethodLanguageInjection languageInjection) {
Language language = languageInjection.getLanguage();
if (language == null) {
return;
}

registrar.startInjecting(language)
.addPlace(languageInjection.getPrefix(), languageInjection.getSuffix(), element, element.getValueRange())
.doneInjecting();
.addPlace(languageInjection.getPrefix(), languageInjection.getSuffix(), element, element.getValueRange())
.doneInjecting();
}

private class MethodLanguageInjection {
private final Language language;
private static class MethodLanguageInjection {
private final String language;
private final String prefix;
private final String suffix;
private final MethodMatcher.CallToSignature[] signatures;

MethodLanguageInjection(@NotNull String languageId, String prefix, String suffix, MethodMatcher.CallToSignature[] signatures) {

this.language = Language.findLanguageByID(languageId);
MethodLanguageInjection(String languageId, String prefix, String suffix, MethodMatcher.CallToSignature[] signatures) {
this.language = languageId;
this.prefix = prefix;
this.suffix = suffix;
this.signatures = signatures;
}

@Nullable
public Language getLanguage() {
return language;
return Language.findLanguageByID(this.language);
}

public String getPrefix() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,17 +393,17 @@ public static Map<String, Route> getRoutesInsideUrlGeneratorFile(@NotNull PsiFil

// Symfony < 2.8
// static private $declaredRoutes = array(...)
for(Field field: phpClass.getFields()) {
if(!field.getName().equals("declaredRoutes")) {
continue;
}
// only "getOwnFields" is uncached and dont breaks; find* methods are cached resulting in exceptions
Field[] ownFields = phpClass.getOwnFields();
for (Field ownField : ownFields) {
if ("declaredRoutes".equals(ownField.getName())) {
PsiElement defaultValue = ownField.getDefaultValue();
if(!(defaultValue instanceof ArrayCreationExpression)) {
continue;
}

PsiElement defaultValue = field.getDefaultValue();
if(!(defaultValue instanceof ArrayCreationExpression)) {
continue;
collectRoutesOnArrayCreation(routes, (ArrayCreationExpression) defaultValue);
}

collectRoutesOnArrayCreation(routes, (ArrayCreationExpression) defaultValue);
}

// Symfony >= 2.8
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@
]]></description>

<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="182.0"/>
<idea-version since-build="201.0"/>

<extensions defaultExtensionNs="com.jetbrains.php">
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.dic.SymfonyContainerTypeProvider"/>
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.util.EventDispatcherTypeProvider"/>
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider"/>
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryResultTypeProvider"/>
<typeProvider4 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryResultTypeProvider"/>
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectManagerFindTypeProvider"/>
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.assistant.signature.MethodSignatureTypeProvider"/>
<libraryRoot id="symfony_meta" path="/symfony-meta/" runtime="false"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ public void assertLineMarker(@NotNull PsiElement psiElement, @NotNull LineMarker

final List<PsiElement> elements = collectPsiElementsRecursive(psiElement);

for (LineMarkerProvider lineMarkerProvider : LineMarkerProviders.INSTANCE.allForLanguage(psiElement.getLanguage())) {
for (LineMarkerProvider lineMarkerProvider : LineMarkerProviders.getInstance().allForLanguage(psiElement.getLanguage())) {
Collection<LineMarkerInfo> lineMarkerInfos = new ArrayList<LineMarkerInfo>();
lineMarkerProvider.collectSlowLineMarkers(elements, lineMarkerInfos);

Expand All @@ -600,7 +600,7 @@ public void assertLineMarkerIsEmpty(@NotNull PsiElement psiElement) {

final List<PsiElement> elements = collectPsiElementsRecursive(psiElement);

for (LineMarkerProvider lineMarkerProvider : LineMarkerProviders.INSTANCE.allForLanguage(psiElement.getLanguage())) {
for (LineMarkerProvider lineMarkerProvider : LineMarkerProviders.getInstance().allForLanguage(psiElement.getLanguage())) {
Collection<LineMarkerInfo> lineMarkerInfos = new ArrayList<LineMarkerInfo>();
lineMarkerProvider.collectSlowLineMarkers(elements, lineMarkerInfos);

Expand Down
Loading