| 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