|
10 | 10 | import org.eclipse.jdt.internal.core.SourceMethod; |
11 | 11 | import org.eclipse.jdt.internal.core.SourceRefElement; |
12 | 12 |
|
| 13 | +import java.util.ArrayList; |
13 | 14 | import java.util.Arrays; |
14 | 15 | import java.util.List; |
15 | 16 | import java.util.Map; |
@@ -47,28 +48,33 @@ default boolean matchesAnnotationQuery(SearchMatch match, List<Class<? extends S |
47 | 48 |
|
48 | 49 | // Iterate over the annotation this symbol is annotated with |
49 | 50 | for (IAnnotation annotation : annotations) { |
50 | | - // See if the annotation's name matches the pattern given in the query for the annotation |
51 | | - String fqn = getFQN(annotation); |
52 | | - if (getAnnotationQuery().matchesAnnotation(fqn)) { |
53 | | - return doElementsMatch((Annotation) annotation); |
54 | | - } else { |
55 | | - // The LS doesn't seem to be able to match on annotations within annotations, but |
56 | | - // if the main annotation doesn't match, there might be some annotations inside: |
57 | | - for (IMemberValuePair member : annotation.getMemberValuePairs()) { |
58 | | - if (member.getValueKind() == IMemberValuePair.K_ANNOTATION) { |
59 | | - if (member.getValue() instanceof Object[]) { |
60 | | - Object[] objs = (Object[]) member.getValue(); |
61 | | - for (int i = 0; i < objs.length; i++) { |
62 | | - Annotation innerAnnotation = (Annotation) objs[i]; |
63 | | - fqn = getFQN(innerAnnotation); |
| 51 | + for (String fqn : getFQNCandidates(annotation)) { |
| 52 | + if (getAnnotationQuery().matchesAnnotation(fqn)) { |
| 53 | + return doElementsMatch((Annotation) annotation); |
| 54 | + } |
| 55 | + } |
| 56 | + // Nested annotations (e.g. in member value pairs) |
| 57 | + for (IMemberValuePair member : annotation.getMemberValuePairs()) { |
| 58 | + if (member.getValueKind() == IMemberValuePair.K_ANNOTATION) { |
| 59 | + if (member.getValue() instanceof Object[]) { |
| 60 | + Object[] objs = (Object[]) member.getValue(); |
| 61 | + for (int i = 0; i < objs.length; i++) { |
| 62 | + Annotation innerAnnotation = (Annotation) objs[i]; |
| 63 | + for (String fqn : getFQNCandidates(innerAnnotation)) { |
64 | 64 | if (getAnnotationQuery().matchesAnnotation(fqn)) { |
65 | 65 | return doElementsMatch(innerAnnotation); |
66 | 66 | } |
67 | 67 | } |
68 | 68 | } |
| 69 | + } else if (member.getValue() instanceof IAnnotation) { |
| 70 | + Annotation innerAnnotation = (Annotation) member.getValue(); |
| 71 | + for (String fqn : getFQNCandidates(innerAnnotation)) { |
| 72 | + if (getAnnotationQuery().matchesAnnotation(fqn)) { |
| 73 | + return doElementsMatch(innerAnnotation); |
| 74 | + } |
| 75 | + } |
69 | 76 | } |
70 | 77 | } |
71 | | - |
72 | 78 | } |
73 | 79 | } |
74 | 80 | return false; |
@@ -178,21 +184,37 @@ private IAnnotation[] tryToGetAnnotations(SourceRefElement t) { |
178 | 184 | } |
179 | 185 |
|
180 | 186 | /** |
181 | | - * Tries to extract the fqn of the annotation from the list of imports of the compilation unit. |
| 187 | + * Returns all possible FQNs for this annotation from the CU's imports: single-type match (if any) |
| 188 | + * first, then one candidate per on-demand import. Caller tries each until the rule matches. |
182 | 189 | */ |
183 | | - private String getFQN(IAnnotation annotation) { |
| 190 | + private List<String> getFQNCandidates(IAnnotation annotation) { |
184 | 191 | String name = annotation.getElementName(); |
185 | | - if (Pattern.matches(".*\\.", name)) { |
186 | | - // If the name of the annotation has a dot on it, it's a fqn |
187 | | - return name; |
188 | | - } else { |
189 | | - // If not, the annotation must have been imported. Look in the imports: |
190 | | - return tryToGetImports(annotation).stream() |
191 | | - .filter(i -> i.getElementName().endsWith(name)) |
192 | | - .findFirst() |
193 | | - .map(IImportDeclaration::getElementName) |
194 | | - .orElse(""); |
| 192 | + if (name == null || name.isEmpty()) { |
| 193 | + return List.of(); |
| 194 | + } |
| 195 | + // Already fully qualified in source (e.g. @com.example.MyAnnotation) |
| 196 | + if (name.contains(".")) { |
| 197 | + return List.of(name); |
| 198 | + } |
| 199 | + List<IImportDeclaration> imports = tryToGetImports(annotation); |
| 200 | + List<String> candidates = new ArrayList<>(); |
| 201 | + // Single-type: at most one |
| 202 | + imports.stream() |
| 203 | + .filter(i -> i.getElementName().endsWith(name)) |
| 204 | + .findFirst() |
| 205 | + .map(IImportDeclaration::getElementName) |
| 206 | + .ifPresent(candidates::add); |
| 207 | + // On-demand: one candidate per pkg.* |
| 208 | + for (IImportDeclaration imp : imports) { |
| 209 | + String elementName = imp.getElementName(); |
| 210 | + if (elementName != null && elementName.endsWith(".*")) { |
| 211 | + String prefix = elementName.substring(0, elementName.length() - 2); |
| 212 | + if (!prefix.isEmpty()) { |
| 213 | + candidates.add(prefix + "." + name); |
| 214 | + } |
| 215 | + } |
195 | 216 | } |
| 217 | + return candidates; |
196 | 218 | } |
197 | 219 |
|
198 | 220 | private List<IImportDeclaration> tryToGetImports(IAnnotation annotation) { |
|
0 commit comments