Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 20fd411

Browse files
committed
Refactored ParameterLanguageInjector
1 parent 9e62a68 commit 20fd411

File tree

7 files changed

+817
-730
lines changed

7 files changed

+817
-730
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package fr.adrienbrault.idea.symfony2plugin.lang;
2+
3+
import com.intellij.lang.Language;
4+
import com.intellij.patterns.ElementPattern;
5+
import com.intellij.patterns.StandardPatterns;
6+
import com.intellij.psi.PsiElement;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
13+
public final class LanguageInjection {
14+
@NotNull
15+
private final String languageId;
16+
@Nullable
17+
private final String prefix;
18+
@Nullable
19+
private final String suffix;
20+
@NotNull
21+
private final ElementPattern<? extends PsiElement> pattern;
22+
23+
protected LanguageInjection(@NotNull String languageId, @Nullable String prefix, @Nullable String suffix, @NotNull ElementPattern<? extends PsiElement> pattern) {
24+
this.languageId = languageId;
25+
this.prefix = prefix;
26+
this.suffix = suffix;
27+
this.pattern = pattern;
28+
}
29+
30+
@Nullable
31+
public Language getLanguage() {
32+
return Language.findLanguageByID(languageId);
33+
}
34+
35+
@Nullable
36+
public String getPrefix() {
37+
return prefix;
38+
}
39+
40+
@Nullable
41+
public String getSuffix() {
42+
return suffix;
43+
}
44+
45+
@NotNull
46+
public ElementPattern<? extends PsiElement> getPattern() {
47+
return pattern;
48+
}
49+
50+
public static class Builder {
51+
@NotNull
52+
private final String languageId;
53+
@NotNull
54+
private final List<ElementPattern<? extends PsiElement>> patterns;
55+
@Nullable
56+
private String prefix;
57+
@Nullable
58+
private String suffix;
59+
60+
public Builder(@NotNull String languageId) {
61+
this.languageId = languageId;
62+
this.patterns = new ArrayList<>();
63+
}
64+
65+
public Builder withPrefix(@Nullable String prefix) {
66+
this.prefix = prefix;
67+
68+
return this;
69+
}
70+
71+
public Builder withSuffix(@Nullable String suffix) {
72+
this.suffix = suffix;
73+
74+
return this;
75+
}
76+
77+
public final Builder matchingPattern(@NotNull ElementPattern<? extends PsiElement> pattern) {
78+
patterns.add(pattern);
79+
return this;
80+
}
81+
82+
public Builder matchingAttributeArgument(@NotNull String classFQN, @NotNull String argumentName, int argumentIndex) {
83+
return matchingPattern(LanguageInjectionPatterns.getAttributeArgumentPattern(classFQN, argumentName, argumentIndex));
84+
}
85+
86+
public Builder matchingAnnotationProperty(@NotNull String classFQN, @NotNull String propertyName, boolean isDefaultProperty) {
87+
return matchingPattern(LanguageInjectionPatterns.getAnnotationPropertyPattern(classFQN, propertyName, isDefaultProperty));
88+
}
89+
90+
public Builder matchingConstructorCallArgument(@NotNull String classFQN, @NotNull String argumentName, int argumentIndex) {
91+
return matchingPattern(LanguageInjectionPatterns.getConstructorCallArgumentPattern(classFQN, argumentName, argumentIndex));
92+
}
93+
94+
public Builder matchingFunctionCallArgument(@NotNull String functionFQN, @NotNull String argumentName, int argumentIndex) {
95+
return matchingPattern(LanguageInjectionPatterns.getFunctionCallArgumentPattern(functionFQN, argumentName, argumentIndex));
96+
}
97+
98+
public Builder matchingMethodCallArgument(@NotNull String classFQN, @NotNull String methodName, @NotNull String argumentName, int argumentIndex) {
99+
return matchingPattern(LanguageInjectionPatterns.getMethodCallArgumentPattern(classFQN, methodName, argumentName, argumentIndex));
100+
}
101+
102+
public LanguageInjection build() {
103+
return new LanguageInjection(languageId, prefix, suffix, StandardPatterns.or(patterns.toArray(new ElementPattern[0])));
104+
}
105+
}
106+
}
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
package fr.adrienbrault.idea.symfony2plugin.lang;
2+
3+
import com.intellij.patterns.ElementPattern;
4+
import com.intellij.patterns.PatternCondition;
5+
import com.intellij.patterns.PlatformPatterns;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.psi.PsiWhiteSpace;
8+
import com.intellij.util.ProcessingContext;
9+
import com.jetbrains.php.lang.documentation.phpdoc.lexer.PhpDocTokenTypes;
10+
import com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes;
11+
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
12+
import com.jetbrains.php.lang.psi.elements.*;
13+
import com.jetbrains.php.lang.psi.elements.impl.ParameterListImpl;
14+
import de.espend.idea.php.annotation.util.AnnotationUtil;
15+
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
16+
import org.jetbrains.annotations.NotNull;
17+
import org.jetbrains.annotations.Nullable;
18+
19+
public final class LanguageInjectionPatterns {
20+
21+
public static ElementPattern<? extends PsiElement> getAnnotationPropertyPattern(
22+
@NotNull String classFQN,
23+
@NotNull String propertyName,
24+
boolean isDefaultProperty) {
25+
return PlatformPatterns
26+
.psiElement(StringLiteralExpression.class)
27+
.with(new IsAnnotationProperty(classFQN, propertyName, isDefaultProperty));
28+
}
29+
30+
public static ElementPattern<? extends PsiElement> getAttributeArgumentPattern(
31+
@NotNull String classFQN,
32+
@NotNull String argumentName,
33+
int argumentIndex
34+
) {
35+
return PlatformPatterns.psiElement()
36+
.with(new IsArgument(argumentName, argumentIndex))
37+
.withParent(PlatformPatterns
38+
.psiElement(ParameterList.class)
39+
.withParent(
40+
PlatformPatterns.psiElement(PhpAttribute.class)
41+
.with(new IsAttribute(classFQN))
42+
)
43+
);
44+
}
45+
46+
public static ElementPattern<? extends PsiElement> getMethodCallArgumentPattern(
47+
@NotNull String classFQN,
48+
@NotNull String methodName,
49+
@NotNull String argumentName,
50+
int argumentIndex
51+
) {
52+
return PlatformPatterns.psiElement()
53+
.with(new IsArgument(argumentName, argumentIndex))
54+
.withParent(PlatformPatterns
55+
.psiElement(ParameterList.class)
56+
.withParent(
57+
PlatformPatterns.psiElement(MethodReference.class)
58+
.with(new IsMethodReference(classFQN, methodName))
59+
)
60+
);
61+
}
62+
63+
public static ElementPattern<? extends PsiElement> getConstructorCallArgumentPattern(
64+
@NotNull String classFQN,
65+
@NotNull String argumentName,
66+
int argumentIndex
67+
) {
68+
return PlatformPatterns.psiElement()
69+
.with(new IsArgument(argumentName, argumentIndex))
70+
.withParent(PlatformPatterns
71+
.psiElement(ParameterList.class)
72+
.withParent(
73+
PlatformPatterns.psiElement(NewExpression.class)
74+
.with(new IsConstructorReference(classFQN))
75+
)
76+
);
77+
}
78+
79+
public static ElementPattern<? extends PsiElement> getFunctionCallArgumentPattern(
80+
@NotNull String functionFQN,
81+
@NotNull String argumentName,
82+
int argumentIndex
83+
) {
84+
return PlatformPatterns.psiElement()
85+
.with(new IsArgument(argumentName, argumentIndex))
86+
.withParent(PlatformPatterns
87+
.psiElement(ParameterList.class)
88+
.withParent(
89+
PlatformPatterns.psiElement(FunctionReference.class)
90+
.with(new IsFunctionReference(functionFQN))
91+
)
92+
);
93+
}
94+
95+
private static class IsAnnotationProperty extends PatternCondition<StringLiteralExpression> {
96+
@NotNull
97+
private final String classFQN;
98+
@NotNull
99+
private final String propertyName;
100+
private final boolean isDefaultProperty;
101+
102+
public IsAnnotationProperty(@NotNull String classFQN, @NotNull String propertyName, boolean isDefaultProperty) {
103+
super(String.format("IsAnnotationProperty(%s, %s)", classFQN, propertyName));
104+
this.classFQN = classFQN;
105+
this.propertyName = propertyName;
106+
this.isDefaultProperty = isDefaultProperty;
107+
}
108+
109+
@Override
110+
public boolean accepts(@NotNull StringLiteralExpression element, ProcessingContext context) {
111+
if (element.getParent() == null || !(element.getParent().getParent() instanceof PhpDocTag)) {
112+
return false;
113+
}
114+
115+
var phpDocTag = (PhpDocTag) element.getParent().getParent();
116+
117+
var annotationClass = AnnotationUtil.getAnnotationReference(phpDocTag);
118+
if (annotationClass != null && annotationClass.getFQN().equals(classFQN)) {
119+
return element.equals(getPropertyValuePsiElement(phpDocTag));
120+
}
121+
122+
return false;
123+
}
124+
125+
@Nullable
126+
private PsiElement getPropertyValuePsiElement(@NotNull PhpDocTag phpDocTag) {
127+
PsiElement property = AnnotationUtil.getPropertyValueAsPsiElement(phpDocTag, propertyName);
128+
129+
if (property == null && isDefaultProperty) {
130+
var phpDocAttrList = phpDocTag.getFirstPsiChild();
131+
if (phpDocAttrList != null && phpDocAttrList.getNode().getElementType() == PhpDocElementTypes.phpDocAttributeList) {
132+
PhpPsiElement firstPhpPsiElement = phpDocAttrList.getFirstPsiChild();
133+
if (firstPhpPsiElement instanceof StringLiteralExpression && !hasIdentifier(firstPhpPsiElement)) {
134+
property = firstPhpPsiElement;
135+
}
136+
}
137+
}
138+
139+
return property;
140+
}
141+
142+
private boolean hasIdentifier(@NotNull PsiElement property) {
143+
return PlatformPatterns.psiElement()
144+
.afterLeafSkipping(
145+
PlatformPatterns.or(
146+
PlatformPatterns.psiElement(PsiWhiteSpace.class),
147+
PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=")
148+
),
149+
PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER)
150+
)
151+
.accepts(property);
152+
}
153+
}
154+
155+
private static class IsAttribute extends PatternCondition<PhpAttribute> {
156+
@NotNull
157+
private final String classFQN;
158+
159+
public IsAttribute(@NotNull String classFQN) {
160+
super(String.format("IsAttribute(%s)", classFQN));
161+
this.classFQN = classFQN;
162+
}
163+
164+
@Override
165+
public boolean accepts(@NotNull PhpAttribute phpAttribute, ProcessingContext context) {
166+
return classFQN.equals(phpAttribute.getFQN());
167+
}
168+
}
169+
170+
private static class IsArgument extends PatternCondition<PsiElement> {
171+
@NotNull
172+
private final String name;
173+
private final int index;
174+
175+
public IsArgument(@NotNull String name, int index) {
176+
super(String.format("isArgument(%s, %d)", name, index));
177+
this.name = name;
178+
this.index = index;
179+
}
180+
181+
@Override
182+
public boolean accepts(@NotNull PsiElement parameter, ProcessingContext context) {
183+
if (parameter.getParent() instanceof ParameterListImpl) {
184+
var parameterList = (ParameterListImpl) parameter.getParent();
185+
if (parameterList.getParameter(name) == parameter) {
186+
return true;
187+
}
188+
189+
return parameterList.getParameter(index) == parameter && ParameterListImpl.getNameIdentifier(parameter) == null;
190+
}
191+
192+
return false;
193+
}
194+
}
195+
196+
private static class IsFunctionReference extends PatternCondition<FunctionReference> {
197+
@NotNull
198+
private final String name;
199+
200+
public IsFunctionReference(@NotNull String name) {
201+
super(String.format("IsFunctionReference(%s)", name));
202+
this.name = name;
203+
}
204+
205+
@Override
206+
public boolean accepts(@NotNull FunctionReference element, ProcessingContext context) {
207+
return name.equals(element.getFQN());
208+
}
209+
}
210+
211+
private static class IsMethodReference extends PatternCondition<MethodReference> {
212+
@NotNull
213+
private final String classFQN;
214+
@NotNull
215+
private final String methodName;
216+
217+
public IsMethodReference(@NotNull String classFQN, @NotNull String methodName) {
218+
super(String.format("IsMethodReference(%s::%s)", classFQN, methodName));
219+
this.classFQN = classFQN;
220+
this.methodName = methodName;
221+
}
222+
223+
@Override
224+
public boolean accepts(@NotNull MethodReference element, ProcessingContext context) {
225+
return PhpElementsUtil.isMethodReferenceInstanceOf(element, classFQN, methodName);
226+
}
227+
}
228+
229+
private static class IsConstructorReference extends PatternCondition<NewExpression> {
230+
@NotNull
231+
private final String classFQN;
232+
233+
public IsConstructorReference(@NotNull String classFQN) {
234+
super(String.format("IsConstructorReference(%s)", classFQN));
235+
this.classFQN = classFQN;
236+
}
237+
238+
@Override
239+
public boolean accepts(@NotNull NewExpression newExpression, ProcessingContext context) {
240+
return PhpElementsUtil.isNewExpressionPhpClassWithInstance(newExpression, classFQN);
241+
}
242+
}
243+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /