Skip to content

Commit e5b4001

Browse files
committed
Rebased and fixed conflicts
1 parent daca2db commit e5b4001

File tree

2 files changed

+53
-98
lines changed

2 files changed

+53
-98
lines changed

build.gradle.kts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ plugins {
1313
id("org.jetbrains.changelog") version "1.3.1"
1414
// Gradle Qodana Plugin
1515
id("org.jetbrains.qodana") version "0.1.13"
16+
// Gradle Grammar-Kit Plugin
17+
id("org.jetbrains.grammarkit") version "2021.2.2"
1618
}
1719

1820
group = properties("pluginGroup")
@@ -112,4 +114,29 @@ tasks {
112114
includeEngines("junit-vintage")
113115
}
114116
}
117+
118+
generateLexer {
119+
source.set("src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.flex")
120+
targetDir.set("src/main/gen/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/")
121+
targetClass.set("ExpressionLanguageLexer")
122+
purgeOldFiles.set(true)
123+
}
124+
125+
generateParser {
126+
source.set("src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.bnf")
127+
targetRoot.set("src/main/gen")
128+
pathToParser.set("fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageParser.java")
129+
pathToPsiRoot.set("fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi")
130+
purgeOldFiles.set(true)
131+
}
132+
133+
compileJava {
134+
dependsOn("generateLexer")
135+
dependsOn("generateParser")
136+
}
115137
}
138+
139+
java.sourceSets["main"].java {
140+
// Include the generated files in the source set
141+
srcDir("src/main/gen")
142+
}

src/main/java/fr/adrienbrault/idea/symfony2plugin/security/AnnotationExpressionGotoCompletionRegistrar.java

Lines changed: 26 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
import com.intellij.patterns.PatternCondition;
55
import com.intellij.patterns.PlatformPatterns;
66
import com.intellij.patterns.PsiElementPattern;
7+
import com.intellij.patterns.StandardPatterns;
78
import com.intellij.psi.PsiElement;
89
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;
1110
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
1211
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
1312
import com.jetbrains.php.lang.psi.elements.ParameterList;
@@ -18,16 +17,17 @@
1817
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProviderLookupArguments;
1918
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
2019
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
20+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageCallExpr;
21+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageLiteralExpr;
22+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageRefExpr;
23+
import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageStringLiteral;
2124
import fr.adrienbrault.idea.symfony2plugin.security.utils.VoterUtil;
2225
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
23-
import org.apache.commons.lang.StringUtils;
2426
import org.jetbrains.annotations.NotNull;
2527

2628
import java.util.Collection;
2729
import java.util.Collections;
2830
import java.util.HashSet;
29-
import java.util.regex.Matcher;
30-
import java.util.regex.Pattern;
3131

3232
/**
3333
* @author Daniel Espendiller <[email protected]>
@@ -40,39 +40,24 @@ public class AnnotationExpressionGotoCompletionRegistrar implements GotoCompleti
4040
public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
4141
// "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
4242
registrar.register(
43-
PlatformPatterns.or(getDocTagStringPattern(), getAttributeStringPattern()),
43+
PlatformPatterns.psiElement()
44+
.withParent(PlatformPatterns
45+
.psiElement(ExpressionLanguageStringLiteral.class)
46+
.withParent(PlatformPatterns
47+
.psiElement(ExpressionLanguageLiteralExpr.class)
48+
.withParent(PlatformPatterns
49+
.psiElement(ExpressionLanguageCallExpr.class)
50+
.withFirstChild(PlatformPatterns
51+
.psiElement(ExpressionLanguageRefExpr.class)
52+
.withText(StandardPatterns.string().oneOf("has_role", "is_granted"))
53+
)
54+
)
55+
)
56+
),
4457
MyGotoCompletionProvider::new
4558
);
4659
}
4760

48-
@NotNull
49-
private PsiElementPattern.Capture<PsiElement> getAttributeStringPattern() {
50-
// #[Security("is_granted('POST_SHOW')")]
51-
return PlatformPatterns.psiElement().withElementType(PlatformPatterns.elementType().or(
52-
PhpTokenTypes.STRING_LITERAL_SINGLE_QUOTE,
53-
PhpTokenTypes.STRING_LITERAL
54-
))
55-
.withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
56-
.withParent(PlatformPatterns.psiElement(ParameterList.class)
57-
.withParent(PlatformPatterns.psiElement(PhpAttribute.class)
58-
.with(PhpDocInstancePatternCondition.INSTANCE)
59-
)
60-
)
61-
);
62-
}
63-
64-
@NotNull
65-
private PsiElementPattern.Capture<PsiElement> getDocTagStringPattern() {
66-
return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STRING)
67-
.withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
68-
.withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)
69-
.withParent(PlatformPatterns.psiElement(PhpDocTag.class)
70-
.with(PhpDocInstancePatternCondition.INSTANCE)
71-
)
72-
)
73-
);
74-
}
75-
7661
/**
7762
* "@Security("has_role('ROLE_FOOBAR')")"
7863
* "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
@@ -87,16 +72,7 @@ public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arg
8772
final CompletionResultSet resultSet = arguments.getResultSet();
8873
String blockNamePrefix = resultSet.getPrefixMatcher().getPrefix();
8974

90-
// find caret position:
91-
// - "has_role('"
92-
// - "has_role('YAML_ROLE_"
93-
if(!blockNamePrefix.matches("^.*(has_role|is_granted)\\s*\\(\\s*['|\"][\\w-]*$")) {
94-
return;
95-
}
96-
97-
// clear prefix caret string; for a clean completion independent from inside content
98-
String substring = blockNamePrefix.replaceAll("^(.*(has_role|is_granted)\\s*\\(\\s*['|\"])", "");
99-
CompletionResultSet myResultSet = resultSet.withPrefixMatcher(substring);
75+
CompletionResultSet myResultSet = resultSet.withPrefixMatcher(blockNamePrefix);
10076

10177
VoterUtil.LookupElementPairConsumer consumer = new VoterUtil.LookupElementPairConsumer();
10278
VoterUtil.visitAttribute(getProject(), consumer);
@@ -106,70 +82,22 @@ public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arg
10682
@NotNull
10783
@Override
10884
public Collection<PsiElement> getPsiTargets(PsiElement element) {
109-
String contents = null;
110-
if(getElement().getNode().getElementType() == PhpDocTokenTypes.DOC_STRING) {
111-
// @Security
112-
PsiElement parent = getElement().getParent();
113-
if(!(parent instanceof StringLiteralExpression)) {
114-
return Collections.emptyList();
115-
}
116-
117-
contents = ((StringLiteralExpression) parent).getContents();
118-
} else {
119-
// @Security
120-
PsiElement parent = getElement().getParent();
121-
if (parent instanceof StringLiteralExpression) {
122-
contents = ((StringLiteralExpression) parent).getContents();
123-
}
124-
}
125-
126-
if (StringUtils.isBlank(contents)) {
85+
var text = getElement().getText();
86+
if (text.length() < 2) {
12787
return Collections.emptyList();
12888
}
12989

130-
Collection<String> roles = new HashSet<>();
131-
for (String regex : new String[]{"is_granted\\s*\\(\\s*['|\"]([^'\"]+)['|\"]\\s*[\\)|,]", "has_role\\s*\\(\\s*['|\"]([^'\"]+)['|\"]\\s*\\)"}) {
132-
Matcher matcher = Pattern.compile(regex).matcher(contents);
133-
while(matcher.find()){
134-
roles.add(matcher.group(1));
135-
}
136-
}
137-
138-
if(roles.size() == 0) {
139-
return Collections.emptyList();
140-
}
141-
142-
Collection<PsiElement> targets = new HashSet<>();
90+
// Strip quotes
91+
var role = text.substring(1, text.length() - 1);
14392

93+
var targets = new HashSet<PsiElement>();
14494
VoterUtil.visitAttribute(getProject(), pair -> {
145-
if(roles.contains(pair.getFirst())) {
95+
if(pair.getFirst().equals(role)) {
14696
targets.add(pair.getSecond());
14797
}
14898
});
14999

150100
return targets;
151101
}
152102
}
153-
154-
/**
155-
* Check if given PhpDocTag is instance of given Annotation class
156-
*/
157-
private static class PhpDocInstancePatternCondition extends PatternCondition<PsiElement> {
158-
private static final PhpDocInstancePatternCondition INSTANCE = new PhpDocInstancePatternCondition();
159-
160-
PhpDocInstancePatternCondition() {
161-
super("PhpDoc/Attribute Instance");
162-
}
163-
164-
@Override
165-
public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext processingContext) {
166-
if (psiElement instanceof PhpDocTag) {
167-
return PhpElementsUtil.isEqualClassName(AnnotationUtil.getAnnotationReference((PhpDocTag) psiElement), SECURITY_ANNOTATION);
168-
} else if (psiElement instanceof PhpAttribute) {
169-
return SECURITY_ANNOTATION.equals(((PhpAttribute) psiElement).getFQN());
170-
}
171-
172-
return false;
173-
}
174-
}
175103
}

0 commit comments

Comments
 (0)