1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2005, 2017 BEA Systems, Inc, IBM Corporation and others. |
3 | * |
4 | * This program and the accompanying materials |
5 | * are made available under the terms of the Eclipse Public License 2.0 |
6 | * which accompanies this distribution, and is available at |
7 | * https://www.eclipse.org/legal/epl-2.0/ |
8 | * |
9 | * SPDX-License-Identifier: EPL-2.0 |
10 | * |
11 | * Contributors: |
12 | * tyeung@bea.com - initial API and implementation |
13 | * IBM Corporation - implemented methods from IBinding |
14 | * IBM Corporation - renamed from ResolvedAnnotation to AnnotationBinding |
15 | * IBM Corporation - Fix for 328969 |
16 | *******************************************************************************/ |
17 | package org.eclipse.jdt.core.dom; |
18 | |
19 | import org.eclipse.jdt.core.IAnnotatable; |
20 | import org.eclipse.jdt.core.ICompilationUnit; |
21 | import org.eclipse.jdt.core.IJavaElement; |
22 | import org.eclipse.jdt.core.IMember; |
23 | import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; |
24 | import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; |
25 | import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
26 | import org.eclipse.jdt.internal.compiler.lookup.TagBits; |
27 | import org.eclipse.jdt.internal.compiler.util.*; |
28 | |
29 | /** |
30 | * Internal class |
31 | */ |
32 | class AnnotationBinding implements IAnnotationBinding { |
33 | static final AnnotationBinding[] NoAnnotations = new AnnotationBinding[0]; |
34 | private org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding binding; |
35 | private BindingResolver bindingResolver; |
36 | private String key; |
37 | |
38 | AnnotationBinding(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding annotation, BindingResolver resolver) { |
39 | if (annotation == null) |
40 | throw new IllegalStateException(); |
41 | this.binding = annotation; |
42 | this.bindingResolver = resolver; |
43 | } |
44 | |
45 | @Override |
46 | public IAnnotationBinding[] getAnnotations() { |
47 | return NoAnnotations; |
48 | } |
49 | |
50 | @Override |
51 | public ITypeBinding getAnnotationType() { |
52 | ITypeBinding typeBinding = this.bindingResolver.getTypeBinding(this.binding.getAnnotationType()); |
53 | if (typeBinding == null) |
54 | return null; |
55 | return typeBinding; |
56 | } |
57 | |
58 | @Override |
59 | public IMemberValuePairBinding[] getDeclaredMemberValuePairs() { |
60 | ReferenceBinding typeBinding = this.binding.getAnnotationType(); |
61 | if (typeBinding == null || ((typeBinding.tagBits & TagBits.HasMissingType) != 0)) { |
62 | return MemberValuePairBinding.NoPair; |
63 | } |
64 | ElementValuePair[] internalPairs = this.binding.getElementValuePairs(); |
65 | int length = internalPairs.length; |
66 | IMemberValuePairBinding[] pairs = length == 0 ? MemberValuePairBinding.NoPair : new MemberValuePairBinding[length]; |
67 | int counter = 0; |
68 | for (int i = 0; i < length; i++) { |
69 | ElementValuePair valuePair = internalPairs[i]; |
70 | if (valuePair.binding == null) continue; |
71 | pairs[counter++] = this.bindingResolver.getMemberValuePairBinding(valuePair); |
72 | } |
73 | if (counter == 0) return MemberValuePairBinding.NoPair; |
74 | if (counter != length) { |
75 | // resize |
76 | System.arraycopy(pairs, 0, (pairs = new MemberValuePairBinding[counter]), 0, counter); |
77 | } |
78 | return pairs; |
79 | } |
80 | |
81 | @Override |
82 | public IMemberValuePairBinding[] getAllMemberValuePairs() { |
83 | IMemberValuePairBinding[] pairs = getDeclaredMemberValuePairs(); |
84 | ReferenceBinding typeBinding = this.binding.getAnnotationType(); |
85 | if (typeBinding == null || ((typeBinding.tagBits & TagBits.HasMissingType) != 0)) return pairs; |
86 | MethodBinding[] methods = typeBinding.availableMethods(); // resilience |
87 | int methodLength = methods == null ? 0 : methods.length; |
88 | if (methodLength == 0) return pairs; |
89 | |
90 | int declaredLength = pairs.length; |
91 | if (declaredLength == methodLength) |
92 | return pairs; |
93 | |
94 | HashtableOfObject table = new HashtableOfObject(declaredLength); |
95 | for (int i = 0; i < declaredLength; i++) { |
96 | char[] internalName = ((MemberValuePairBinding) pairs[i]).internalName(); |
97 | if (internalName == null) continue; |
98 | table.put(internalName, pairs[i]); |
99 | } |
100 | |
101 | // handle case of more methods than declared members |
102 | IMemberValuePairBinding[] allPairs = new IMemberValuePairBinding[methodLength]; |
103 | for (int i = 0; i < methodLength; i++) { |
104 | Object pair = table.get(methods[i].selector); |
105 | allPairs[i] = pair == null ? new DefaultValuePairBinding(methods[i], this.bindingResolver) : (IMemberValuePairBinding) pair; |
106 | } |
107 | return allPairs; |
108 | } |
109 | |
110 | @Override |
111 | public IJavaElement getJavaElement() { |
112 | if (!(this.bindingResolver instanceof DefaultBindingResolver)) return null; |
113 | ASTNode node = (ASTNode) ((DefaultBindingResolver) this.bindingResolver).bindingsToAstNodes.get(this); |
114 | if (!(node instanceof Annotation)) return null; |
115 | ASTNode parent = node.getParent(); |
116 | IJavaElement parentElement = null; |
117 | switch (parent.getNodeType()) { |
118 | case ASTNode.PACKAGE_DECLARATION: |
119 | IJavaElement cu = ((CompilationUnit) parent.getParent()).getJavaElement(); |
120 | if (cu instanceof ICompilationUnit) { |
121 | String pkgName = ((PackageDeclaration) parent).getName().getFullyQualifiedName(); |
122 | parentElement = ((ICompilationUnit) cu).getPackageDeclaration(pkgName); |
123 | } |
124 | break; |
125 | case ASTNode.ENUM_DECLARATION: |
126 | case ASTNode.TYPE_DECLARATION: |
127 | case ASTNode.ANNOTATION_TYPE_DECLARATION: |
128 | parentElement = ((AbstractTypeDeclaration) parent).resolveBinding().getJavaElement(); |
129 | break; |
130 | case ASTNode.FIELD_DECLARATION: |
131 | VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) parent).fragments().get(0); |
132 | IVariableBinding variableBinding = fragment.resolveBinding(); |
133 | if (variableBinding == null) { |
134 | return null; |
135 | } |
136 | parentElement = variableBinding.getJavaElement(); |
137 | break; |
138 | case ASTNode.METHOD_DECLARATION: |
139 | IMethodBinding methodBinding = ((MethodDeclaration) parent).resolveBinding(); |
140 | if (methodBinding == null) return null; |
141 | parentElement = methodBinding.getJavaElement(); |
142 | break; |
143 | case ASTNode.MODULE_DECLARATION: |
144 | IModuleBinding moduleBinding = ((ModuleDeclaration) parent).resolveBinding(); |
145 | if (moduleBinding == null) return null; |
146 | parentElement = moduleBinding.getJavaElement(); |
147 | break; |
148 | case ASTNode.VARIABLE_DECLARATION_STATEMENT: |
149 | fragment = (VariableDeclarationFragment) ((VariableDeclarationStatement) parent).fragments().get(0); |
150 | variableBinding = fragment.resolveBinding(); |
151 | if (variableBinding == null) { |
152 | return null; |
153 | } |
154 | parentElement = variableBinding.getJavaElement(); |
155 | break; |
156 | default: |
157 | return null; |
158 | } |
159 | if (! (parentElement instanceof IAnnotatable)) return null; |
160 | if ((parentElement instanceof IMember) && ((IMember) parentElement).isBinary()) { |
161 | return ((IAnnotatable) parentElement).getAnnotation(getAnnotationType().getQualifiedName()); |
162 | } |
163 | return ((IAnnotatable) parentElement).getAnnotation(getName()); |
164 | } |
165 | |
166 | @Override |
167 | public String getKey() { |
168 | if (this.key == null) { |
169 | String recipientKey = getRecipientKey(); |
170 | this.key = new String(this.binding.computeUniqueKey(recipientKey.toCharArray())); |
171 | } |
172 | return this.key; |
173 | } |
174 | |
175 | private String getRecipientKey() { |
176 | if (!(this.bindingResolver instanceof DefaultBindingResolver)) return ""; //$NON-NLS-1$ |
177 | DefaultBindingResolver resolver = (DefaultBindingResolver) this.bindingResolver; |
178 | ASTNode node = (ASTNode) resolver.bindingsToAstNodes.get(this); |
179 | if (node == null) { |
180 | // Can happen if annotation bindings have been resolved before having parsed the declaration |
181 | return ""; //$NON-NLS-1$ |
182 | } |
183 | ASTNode recipient = node.getParent(); |
184 | switch (recipient.getNodeType()) { |
185 | case ASTNode.PACKAGE_DECLARATION: |
186 | String pkgName = ((PackageDeclaration) recipient).getName().getFullyQualifiedName(); |
187 | return pkgName.replace('.', '/'); |
188 | case ASTNode.TYPE_DECLARATION: |
189 | return ((TypeDeclaration) recipient).resolveBinding().getKey(); |
190 | case ASTNode.FIELD_DECLARATION: |
191 | VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) recipient).fragments().get(0); |
192 | return fragment.resolveBinding().getKey(); |
193 | case ASTNode.METHOD_DECLARATION: |
194 | return ((MethodDeclaration) recipient).resolveBinding().getKey(); |
195 | case ASTNode.MODULE_DECLARATION: |
196 | return ((ModuleDeclaration) recipient).resolveBinding().getKey(); |
197 | case ASTNode.VARIABLE_DECLARATION_STATEMENT: |
198 | fragment = (VariableDeclarationFragment) ((VariableDeclarationStatement) recipient).fragments().get(0); |
199 | return fragment.resolveBinding().getKey(); |
200 | default: |
201 | return ""; //$NON-NLS-1$ |
202 | } |
203 | } |
204 | |
205 | @Override |
206 | public int getKind() { |
207 | return IBinding.ANNOTATION; |
208 | } |
209 | |
210 | @Override |
211 | public int getModifiers() { |
212 | return Modifier.NONE; |
213 | } |
214 | |
215 | @Override |
216 | public String getName() { |
217 | ITypeBinding annotationType = getAnnotationType(); |
218 | if (annotationType == null) { |
219 | return new String(this.binding.getAnnotationType().sourceName()); |
220 | } else { |
221 | return annotationType.getName(); |
222 | } |
223 | } |
224 | |
225 | @Override |
226 | public boolean isDeprecated() { |
227 | ReferenceBinding typeBinding = this.binding.getAnnotationType(); |
228 | if (typeBinding == null) return false; |
229 | return typeBinding.isDeprecated(); |
230 | } |
231 | |
232 | @Override |
233 | public boolean isEqualTo(IBinding otherBinding) { |
234 | if (this == otherBinding) |
235 | return true; |
236 | if (otherBinding.getKind() != IBinding.ANNOTATION) |
237 | return false; |
238 | IAnnotationBinding other = (IAnnotationBinding) otherBinding; |
239 | if (!getAnnotationType().isEqualTo(other.getAnnotationType())) |
240 | return false; |
241 | IMemberValuePairBinding[] memberValuePairs = getDeclaredMemberValuePairs(); |
242 | IMemberValuePairBinding[] otherMemberValuePairs = other.getDeclaredMemberValuePairs(); |
243 | if (memberValuePairs.length != otherMemberValuePairs.length) |
244 | return false; |
245 | for (int i = 0, length = memberValuePairs.length; i < length; i++) { |
246 | if (!memberValuePairs[i].isEqualTo(otherMemberValuePairs[i])) |
247 | return false; |
248 | } |
249 | return true; |
250 | } |
251 | |
252 | @Override |
253 | public boolean isRecovered() { |
254 | ReferenceBinding annotationType = this.binding.getAnnotationType(); |
255 | return annotationType == null || (annotationType.tagBits & TagBits.HasMissingType) != 0; } |
256 | |
257 | @Override |
258 | public boolean isSynthetic() { |
259 | return false; |
260 | } |
261 | |
262 | @Override |
263 | public String toString() { |
264 | ITypeBinding type = getAnnotationType(); |
265 | final StringBuilder buffer = new StringBuilder(); |
266 | buffer.append('@'); |
267 | if (type != null) |
268 | buffer.append(type.getName()); |
269 | buffer.append('('); |
270 | IMemberValuePairBinding[] pairs = getDeclaredMemberValuePairs(); |
271 | for (int i = 0, len = pairs.length; i < len; i++) { |
272 | if (i != 0) |
273 | buffer.append(", "); //$NON-NLS-1$ |
274 | buffer.append(pairs[i].toString()); |
275 | } |
276 | buffer.append(')'); |
277 | return buffer.toString(); |
278 | } |
279 | |
280 | } |
281 |
Members