4
4
import com .intellij .patterns .PatternCondition ;
5
5
import com .intellij .patterns .PlatformPatterns ;
6
6
import com .intellij .patterns .PsiElementPattern ;
7
+ import com .intellij .patterns .StandardPatterns ;
7
8
import com .intellij .psi .PsiElement ;
8
9
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
10
import com .jetbrains .php .lang .documentation .phpdoc .psi .tags .PhpDocTag ;
12
11
import com .jetbrains .php .lang .lexer .PhpTokenTypes ;
13
12
import com .jetbrains .php .lang .psi .elements .ParameterList ;
18
17
import fr .adrienbrault .idea .symfony2plugin .codeInsight .GotoCompletionProviderLookupArguments ;
19
18
import fr .adrienbrault .idea .symfony2plugin .codeInsight .GotoCompletionRegistrar ;
20
19
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 ;
21
24
import fr .adrienbrault .idea .symfony2plugin .security .utils .VoterUtil ;
22
25
import fr .adrienbrault .idea .symfony2plugin .util .PhpElementsUtil ;
23
- import org .apache .commons .lang .StringUtils ;
24
26
import org .jetbrains .annotations .NotNull ;
25
27
26
28
import java .util .Collection ;
27
29
import java .util .Collections ;
28
30
import java .util .HashSet ;
29
- import java .util .regex .Matcher ;
30
- import java .util .regex .Pattern ;
31
31
32
32
/**
33
33
* @author Daniel Espendiller <[email protected] >
@@ -40,39 +40,24 @@ public class AnnotationExpressionGotoCompletionRegistrar implements GotoCompleti
40
40
public void register (@ NotNull GotoCompletionRegistrarParameter registrar ) {
41
41
// "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
42
42
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
+ ),
44
57
MyGotoCompletionProvider ::new
45
58
);
46
59
}
47
60
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
-
76
61
/**
77
62
* "@Security("has_role('ROLE_FOOBAR')")"
78
63
* "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
@@ -87,16 +72,7 @@ public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arg
87
72
final CompletionResultSet resultSet = arguments .getResultSet ();
88
73
String blockNamePrefix = resultSet .getPrefixMatcher ().getPrefix ();
89
74
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 );
100
76
101
77
VoterUtil .LookupElementPairConsumer consumer = new VoterUtil .LookupElementPairConsumer ();
102
78
VoterUtil .visitAttribute (getProject (), consumer );
@@ -106,70 +82,22 @@ public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arg
106
82
@ NotNull
107
83
@ Override
108
84
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 ) {
127
87
return Collections .emptyList ();
128
88
}
129
89
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 );
143
92
93
+ var targets = new HashSet <PsiElement >();
144
94
VoterUtil .visitAttribute (getProject (), pair -> {
145
- if (roles . contains ( pair .getFirst ())) {
95
+ if (pair .getFirst (). equals ( role )) {
146
96
targets .add (pair .getSecond ());
147
97
}
148
98
});
149
99
150
100
return targets ;
151
101
}
152
102
}
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
- }
175
103
}
0 commit comments