Skip to content
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

#2015 [Translation] Add inspection, autocompletion and navigation for named arguments #2021

Merged
merged 1 commit into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.formatter.FormatterUtil;
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
import com.jetbrains.php.lang.psi.elements.*;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
Expand Down Expand Up @@ -40,23 +43,41 @@ public void visitElement(PsiElement element) {
}

private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiElement) {
if (!(psiElement instanceof StringLiteralExpression) || !(psiElement.getContext() instanceof ParameterList)) {
if (!(psiElement instanceof StringLiteralExpression)) {
return;
}

ParameterList parameterList = (ParameterList) psiElement.getContext();
PsiElement parameterList = psiElement.getContext();
if (!(parameterList instanceof ParameterList)) {
return;
}

int domainParameter = -1;
PsiElement methodReference = parameterList.getContext();
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
domainParameter = 2;
if("transChoice".equals(((MethodReference) methodReference).getName())) {
domainParameter = 3;
PsiElement methodReferenceOrNewExpression = parameterList.getContext();
if (!(methodReferenceOrNewExpression instanceof MethodReference) && !(methodReferenceOrNewExpression instanceof NewExpression)) {
return;
}

ASTNode previousNonWhitespaceSibling = FormatterUtil.getPreviousNonWhitespaceSibling(psiElement.getNode());

if (previousNonWhitespaceSibling != null && previousNonWhitespaceSibling.getElementType() == PhpTokenTypes.opCOLON) {
ASTNode previousNonWhitespaceSibling1 = FormatterUtil.getPreviousNonWhitespaceSibling(previousNonWhitespaceSibling);
if (previousNonWhitespaceSibling1 != null && previousNonWhitespaceSibling1.getElementType() == PhpTokenTypes.IDENTIFIER) {
String text = previousNonWhitespaceSibling1.getText();
boolean isSupportedAttributeInsideContext = "domain".equals(text) && (
(methodReferenceOrNewExpression instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_SIGNATURES))
|| (methodReferenceOrNewExpression instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE))
);

if (isSupportedAttributeInsideContext) {
annotateTranslationDomain((StringLiteralExpression) psiElement, holder);
}
}
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
domainParameter = 2;

return;
}

int domainParameter = getDomainParameter(methodReferenceOrNewExpression);

if (domainParameter >= 0) {
ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
if(currentIndex != null && currentIndex.getIndex() == domainParameter) {
Expand All @@ -65,6 +86,22 @@ private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiEleme
}
}

public static int getDomainParameter(@NotNull PsiElement methodReferenceOrNewExpression) {
if (methodReferenceOrNewExpression instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
int domainParameter = 2;

if("transChoice".equals(((MethodReference) methodReferenceOrNewExpression).getName())) {
domainParameter = 3;
}

return domainParameter;
} else if(methodReferenceOrNewExpression instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
return 2;
}

return -1;
}

private void annotateTranslationDomain(StringLiteralExpression psiElement, @NotNull ProblemsHolder holder) {
String contents = psiElement.getContents();
if(StringUtils.isBlank(contents) || TranslationUtil.hasDomain(psiElement.getProject(), contents)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,45 +42,40 @@ public void visitElement(@NotNull PsiElement element) {
}

private void invoke(@NotNull ProblemsHolder holder, @NotNull PsiElement psiElement) {
if (!(psiElement instanceof StringLiteralExpression) || !(psiElement.getContext() instanceof ParameterList)) {
if (!(psiElement instanceof StringLiteralExpression)) {
return;
}

ParameterList parameterList = (ParameterList) psiElement.getContext();

int domainParameter = -1;
PsiElement methodReference = parameterList.getContext();
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
domainParameter = 2;
if("transChoice".equals(((MethodReference) methodReference).getName())) {
domainParameter = 3;
}
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
domainParameter = 2;
PsiElement parameterList = psiElement.getContext();
if (!(parameterList instanceof ParameterList)) {
return;
}

if (domainParameter < 0) {
PsiElement methodReferenceOrNewExpression = parameterList.getContext();
if (!(methodReferenceOrNewExpression instanceof MethodReference) && !(methodReferenceOrNewExpression instanceof NewExpression)) {
return;
}

ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
if(currentIndex == null || currentIndex.getIndex() != 0) {
if (!PsiElementUtils.isCurrentParameter(psiElement, "id", 0)) {
return;
}

PsiElement domainElement = PsiElementUtils.getMethodParameterPsiElementAt(parameterList, domainParameter);
if (!(
(methodReferenceOrNewExpression instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) ||
(methodReferenceOrNewExpression instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)))
) {
return;
}

PsiElement domainElement = ((ParameterList) parameterList).getParameter("domain", PhpTranslationDomainInspection.getDomainParameter(parameterList.getContext()));
if(domainElement == null) {
// no domain found; fallback to default domain
annotateTranslationKey((StringLiteralExpression) psiElement, "messages", holder);
} else {
// resolve string in parameter
PsiElement[] parameters = parameterList.getParameters();
if(parameters.length >= domainParameter) {
String domain = PhpElementsUtil.getStringValue(parameters[domainParameter]);
if(domain != null) {
annotateTranslationKey((StringLiteralExpression) psiElement, domain, holder);
}
String domain = PhpElementsUtil.getStringValue(domainElement);
if(domain != null) {
annotateTranslationKey((StringLiteralExpression) psiElement, domain, holder);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
import fr.adrienbrault.idea.symfony2plugin.util.ParameterBag;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import org.jetbrains.annotations.NotNull;
Expand All @@ -33,48 +32,38 @@ public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistr
}

ParameterList parameterList = (ParameterList) psiElement.getContext();
PsiElement methodReference = parameterList.getContext();
PsiElement methodReferenceOrNewExpression = parameterList.getContext();

int domainParameter = -1;
if (methodReference instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) {
domainParameter = 2;
if("transChoice".equals(((MethodReference) methodReference).getName())) {
domainParameter = 3;
}
} else if(methodReference instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReference, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)) {
domainParameter = 2;
}

if (domainParameter < 0) {
if (!(
(methodReferenceOrNewExpression instanceof MethodReference && PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_SIGNATURES)) ||
(methodReferenceOrNewExpression instanceof NewExpression && PhpElementsUtil.isNewExpressionPhpClassWithInstance((NewExpression) methodReferenceOrNewExpression, TranslationUtil.PHP_TRANSLATION_TRANSLATABLE_MESSAGE)))
) {
return new PsiReference[0];
}

ParameterBag currentIndex = PsiElementUtils.getCurrentParameterIndex(psiElement);
if(currentIndex == null) {
return new PsiReference[0];
}
int domainParameter = PhpTranslationDomainInspection.getDomainParameter(methodReferenceOrNewExpression);

if(currentIndex.getIndex() == domainParameter) {
if (PsiElementUtils.isCurrentParameter(psiElement, "domain", domainParameter)) {
return new PsiReference[]{ new TranslationDomainReference((StringLiteralExpression) psiElement) };
}

if(currentIndex.getIndex() == 0) {
String domain = PsiElementUtils.getMethodParameterAt(parameterList, domainParameter);
if (PsiElementUtils.isCurrentParameter(psiElement, "id", 0)) {
PsiElement domainPsi = parameterList.getParameter("domain", domainParameter);

if(domain == null) {
domain = "messages";
String domain = "messages";
if (domainPsi != null) {
String stringValue = PhpElementsUtil.getStringValue(domainPsi);
if (stringValue != null) {
domain = stringValue;
}
}

return new PsiReference[]{ new TranslationReference((StringLiteralExpression) psiElement, domain) };
}

return new PsiReference[0];
}

}

);

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.adrienbrault.idea.symfony2plugin.util;

import com.intellij.lang.ASTNode;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.patterns.ElementPattern;
Expand All @@ -8,12 +9,14 @@
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Processor;
import com.jetbrains.php.lang.PhpLanguage;
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
import com.jetbrains.php.lang.psi.elements.*;
import fr.adrienbrault.idea.symfony2plugin.translation.dict.TranslationUtil;
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -117,17 +120,30 @@ public static ParameterBag getCurrentParameterIndex(PsiElement[] parameters, Psi

@Nullable
public static ParameterBag getCurrentParameterIndex(PsiElement psiElement) {

if (!(psiElement.getContext() instanceof ParameterList)) {
PsiElement parameterList = psiElement.getContext();
if (!(parameterList instanceof ParameterList)) {
return null;
}

ParameterList parameterList = (ParameterList) psiElement.getContext();
if (!(parameterList.getContext() instanceof ParameterListOwner)) {
return null;
return getCurrentParameterIndex(((ParameterList) parameterList).getParameters(), psiElement);
}

public static boolean isCurrentParameter(@NotNull PsiElement psiElement, @NotNull String namedParameter, int index) {
PsiElement parameterList = psiElement.getContext();
if (!(parameterList instanceof ParameterList)) {
return false;
}

ASTNode previousNonWhitespaceSibling = FormatterUtil.getPreviousNonWhitespaceSibling(psiElement.getNode());
if (previousNonWhitespaceSibling != null && previousNonWhitespaceSibling.getElementType() == PhpTokenTypes.opCOLON) {
ASTNode previousNonWhitespaceSibling1 = FormatterUtil.getPreviousNonWhitespaceSibling(previousNonWhitespaceSibling);
if (previousNonWhitespaceSibling1 != null && previousNonWhitespaceSibling1.getElementType() == PhpTokenTypes.IDENTIFIER && namedParameter.equals(previousNonWhitespaceSibling1.getText())) {
return true;
}
}

return getCurrentParameterIndex(parameterList.getParameters(), psiElement);
ParameterBag currentParameterIndex = getCurrentParameterIndex(((ParameterList) parameterList).getParameters(), psiElement);
return currentParameterIndex != null && currentParameterIndex.getIndex() == index;
}

public static int getParameterIndexValue(@Nullable PsiElement parameterListChild) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public void testThatPhpTranslationDomainInspectionsAreProvided() {
"$x->trans('foo<caret>bar')",
PhpTranslationDomainInspection.MESSAGE
);

assertLocalInspectionContains("test.php", "<?php\n" +
"/** @var $x Symfony\\Component\\Translation\\TranslatorInterface */" +
"$x->trans('id', domain: 'dom<caret>ain')",
PhpTranslationDomainInspection.MESSAGE
);
}

public void testThatPhpTranslationDomainInspectionsForTranslatableMessageAreProvided() {
Expand All @@ -65,5 +71,10 @@ public void testThatPhpTranslationDomainInspectionsForTranslatableMessageAreProv
"new \\Symfony\\Component\\Translation\\TranslatableMessage('foobar', [], 'sym<caret>fony');",
PhpTranslationDomainInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"new \\Symfony\\Component\\Translation\\TranslatableMessage(domain: 'sym<caret>fony');",
PhpTranslationDomainInspection.MESSAGE
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,24 @@ public void testThatPhpTransInspectionsAreNotProvidedForKnownTranslations() {
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionContains("test.php", "<?php\n" +
"/** @var $x Symfony\\Component\\Translation\\TranslatorInterface */" +
"$x->trans(id: 'symfon<caret>y.great')",
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"/** @var $x Symfony\\Component\\Translation\\TranslatorInterface */" +
"$x->trans('symfon<caret>y.great', [], 'symfony')",
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"/** @var $x Symfony\\Component\\Translation\\TranslatorInterface */" +
"$x->trans('symfon<caret>y.great', domain: 'symfony')",
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"/** @var $x Symfony\\Component\\Translation\\TranslatorInterface */" +
"$x->transChoice('symfon<caret>y.great', 1, [], 'symfony')",
Expand Down Expand Up @@ -104,6 +116,11 @@ public void testThatPhpTranslationKeyInspectionsForTranslatableMessageAreProvide
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfon<caret>y.great', domain: 'symfony');",
PhpTranslationKeyInspection.MESSAGE
);

assertLocalInspectionNotContains("test.php", "<?php\n" +
"new \\Symfony\\Component\\Translation\\TranslatableMessage('symfon<caret>y.great', [], 'symfony');",
PhpTranslationKeyInspection.MESSAGE
Expand Down
Loading