| 1 | /******************************************************************************* |
|---|---|
| 2 | * Copyright (c) 2000, 2021 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 | * IBM Corporation - initial API and implementation |
| 13 | * Stephan Herrmann - Contribution for |
| 14 | * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda |
| 15 | * Bug 466308 - [hovering] Javadoc header for parameter is wrong with annotation-based null analysis |
| 16 | *******************************************************************************/ |
| 17 | |
| 18 | package org.eclipse.jdt.core.dom; |
| 19 | |
| 20 | import org.eclipse.jdt.core.IJavaElement; |
| 21 | import org.eclipse.jdt.core.JavaCore; |
| 22 | import org.eclipse.jdt.core.util.IModifierConstants; |
| 23 | import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| 24 | import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| 25 | import org.eclipse.jdt.internal.compiler.impl.Constant; |
| 26 | import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; |
| 27 | import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
| 28 | import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; |
| 29 | import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; |
| 30 | import org.eclipse.jdt.internal.compiler.lookup.TagBits; |
| 31 | import org.eclipse.jdt.internal.compiler.lookup.TypeIds; |
| 32 | import org.eclipse.jdt.internal.core.JavaElement; |
| 33 | import org.eclipse.jdt.internal.core.LocalVariable; |
| 34 | import org.eclipse.jdt.internal.core.util.Util; |
| 35 | |
| 36 | /** |
| 37 | * Internal implementation of variable bindings. |
| 38 | */ |
| 39 | class VariableBinding implements IVariableBinding { |
| 40 | |
| 41 | private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | |
| 42 | Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE; |
| 43 | |
| 44 | private org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding; |
| 45 | private ITypeBinding declaringClass; |
| 46 | private String key; |
| 47 | private String name; |
| 48 | private BindingResolver resolver; |
| 49 | private ITypeBinding type; |
| 50 | private IAnnotationBinding[] annotations; |
| 51 | |
| 52 | VariableBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding) { |
| 53 | this.resolver = resolver; |
| 54 | this.binding = binding; |
| 55 | } |
| 56 | |
| 57 | @Override |
| 58 | public IAnnotationBinding[] getAnnotations() { |
| 59 | if (this.annotations != null) { |
| 60 | return this.annotations; |
| 61 | } |
| 62 | org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = this.binding.getAnnotations(); |
| 63 | int length = internalAnnotations == null ? 0 : internalAnnotations.length; |
| 64 | if (length != 0) { |
| 65 | IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; |
| 66 | int convertedAnnotationCount = 0; |
| 67 | for (int i = 0; i < length; i++) { |
| 68 | org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; |
| 69 | final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); |
| 70 | if (annotationInstance == null) { |
| 71 | continue; |
| 72 | } |
| 73 | tempAnnotations[convertedAnnotationCount++] = annotationInstance; |
| 74 | } |
| 75 | if (convertedAnnotationCount != length) { |
| 76 | if (convertedAnnotationCount == 0) { |
| 77 | return this.annotations = AnnotationBinding.NoAnnotations; |
| 78 | } |
| 79 | System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); |
| 80 | } |
| 81 | return this.annotations = tempAnnotations; |
| 82 | } |
| 83 | return this.annotations = AnnotationBinding.NoAnnotations; |
| 84 | } |
| 85 | |
| 86 | @Override |
| 87 | public Object getConstantValue() { |
| 88 | Constant c = this.binding.constant(); |
| 89 | if (c == null || c == Constant.NotAConstant) return null; |
| 90 | switch (c.typeID()) { |
| 91 | case TypeIds.T_boolean: |
| 92 | return Boolean.valueOf(c.booleanValue()); |
| 93 | case TypeIds.T_byte: |
| 94 | return Byte.valueOf(c.byteValue()); |
| 95 | case TypeIds.T_char: |
| 96 | return Character.valueOf(c.charValue()); |
| 97 | case TypeIds.T_double: |
| 98 | return Double.valueOf(c.doubleValue()); |
| 99 | case TypeIds.T_float: |
| 100 | return Float.valueOf(c.floatValue()); |
| 101 | case TypeIds.T_int: |
| 102 | return Integer.valueOf(c.intValue()); |
| 103 | case TypeIds.T_long: |
| 104 | return Long.valueOf(c.longValue()); |
| 105 | case TypeIds.T_short: |
| 106 | return Short.valueOf(c.shortValue()); |
| 107 | case TypeIds.T_JavaLangString: |
| 108 | return c.stringValue(); |
| 109 | } |
| 110 | return null; |
| 111 | } |
| 112 | |
| 113 | @Override |
| 114 | public ITypeBinding getDeclaringClass() { |
| 115 | if (isField()) { |
| 116 | if (this.declaringClass == null) { |
| 117 | FieldBinding fieldBinding = (FieldBinding) this.binding; |
| 118 | this.declaringClass = this.resolver.getTypeBinding(fieldBinding.declaringClass); |
| 119 | } |
| 120 | return this.declaringClass; |
| 121 | } else { |
| 122 | return null; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | @Override |
| 127 | public IMethodBinding getDeclaringMethod() { |
| 128 | if (!isField()) { |
| 129 | ASTNode node = this.resolver.findDeclaringNode(this); |
| 130 | while (true) { |
| 131 | if (node == null) { |
| 132 | if (this.binding instanceof LocalVariableBinding) { |
| 133 | LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; |
| 134 | org.eclipse.jdt.internal.compiler.lookup.MethodBinding enclosingMethod = localVariableBinding.getEnclosingMethod(); |
| 135 | if (enclosingMethod != null) |
| 136 | return this.resolver.getMethodBinding(enclosingMethod); |
| 137 | } |
| 138 | return null; |
| 139 | } |
| 140 | switch(node.getNodeType()) { |
| 141 | case ASTNode.INITIALIZER : |
| 142 | return null; |
| 143 | case ASTNode.METHOD_DECLARATION : |
| 144 | MethodDeclaration methodDeclaration = (MethodDeclaration) node; |
| 145 | return methodDeclaration.resolveBinding(); |
| 146 | case ASTNode.LAMBDA_EXPRESSION : |
| 147 | LambdaExpression lambdaExpression = (LambdaExpression) node; |
| 148 | return lambdaExpression.resolveMethodBinding(); |
| 149 | default: |
| 150 | node = node.getParent(); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | return null; |
| 155 | } |
| 156 | |
| 157 | @Override |
| 158 | public IJavaElement getJavaElement() { |
| 159 | JavaElement element = getUnresolvedJavaElement(); |
| 160 | if (element == null) |
| 161 | return null; |
| 162 | return element.resolved(this.binding); |
| 163 | } |
| 164 | |
| 165 | @Override |
| 166 | public String getKey() { |
| 167 | if (this.key == null) { |
| 168 | this.key = new String(this.binding.computeUniqueKey()); |
| 169 | } |
| 170 | return this.key; |
| 171 | } |
| 172 | |
| 173 | @Override |
| 174 | public int getKind() { |
| 175 | return IBinding.VARIABLE; |
| 176 | } |
| 177 | |
| 178 | @Override |
| 179 | public int getModifiers() { |
| 180 | if (isField()) { |
| 181 | return ((FieldBinding) this.binding).getAccessFlags() & VALID_MODIFIERS; |
| 182 | } |
| 183 | if (this.binding.isFinal()) { |
| 184 | return IModifierConstants.ACC_FINAL; |
| 185 | } |
| 186 | return Modifier.NONE; |
| 187 | } |
| 188 | |
| 189 | @Override |
| 190 | public String getName() { |
| 191 | if (this.name == null) { |
| 192 | this.name = new String(this.binding.name); |
| 193 | } |
| 194 | return this.name; |
| 195 | } |
| 196 | |
| 197 | @Override |
| 198 | public ITypeBinding getType() { |
| 199 | if (this.type == null) { |
| 200 | this.type = this.resolver.getTypeBinding(this.binding.type); |
| 201 | } |
| 202 | return this.type; |
| 203 | } |
| 204 | |
| 205 | private JavaElement getUnresolvedJavaElement() { |
| 206 | if (JavaCore.getPlugin() == null) { |
| 207 | return null; |
| 208 | } |
| 209 | if (isField()) { |
| 210 | if (this.resolver instanceof DefaultBindingResolver) { |
| 211 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
| 212 | if (!defaultBindingResolver.fromJavaProject) return null; |
| 213 | return Util.getUnresolvedJavaElement( |
| 214 | (FieldBinding) this.binding, |
| 215 | defaultBindingResolver.workingCopyOwner, |
| 216 | defaultBindingResolver.getBindingsToNodesMap()); |
| 217 | } |
| 218 | return null; |
| 219 | }else if (isRecordComponent()) { |
| 220 | if (this.resolver instanceof DefaultBindingResolver) { |
| 221 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
| 222 | if (!defaultBindingResolver.fromJavaProject) return null; |
| 223 | return Util.getUnresolvedJavaElement( |
| 224 | (RecordComponentBinding) this.binding, |
| 225 | defaultBindingResolver.workingCopyOwner, |
| 226 | defaultBindingResolver.getBindingsToNodesMap()); |
| 227 | } |
| 228 | return null; |
| 229 | } |
| 230 | // local variable |
| 231 | if (!(this.resolver instanceof DefaultBindingResolver)) return null; |
| 232 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
| 233 | if (!defaultBindingResolver.fromJavaProject) return null; |
| 234 | VariableDeclaration localVar = (VariableDeclaration) defaultBindingResolver.bindingsToAstNodes.get(this); |
| 235 | if (localVar == null) return null; |
| 236 | SimpleName localName = localVar.getName(); |
| 237 | int nameStart = localName.getStartPosition(); |
| 238 | int nameLength = localName.getLength(); |
| 239 | int sourceStart; |
| 240 | int sourceLength; |
| 241 | int modifiers = 0; |
| 242 | if (localVar instanceof SingleVariableDeclaration) { |
| 243 | sourceStart = localVar.getStartPosition(); |
| 244 | sourceLength = localVar.getLength(); |
| 245 | final SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) localVar; |
| 246 | modifiers = singleVariableDeclaration.getModifiers(); |
| 247 | } else { |
| 248 | ASTNode node = localVar.getParent(); |
| 249 | sourceStart = node.getStartPosition(); |
| 250 | sourceLength = node.getLength(); |
| 251 | VariableDeclarationFragment fragment = (VariableDeclarationFragment) localVar; |
| 252 | final ASTNode parent = fragment.getParent(); |
| 253 | switch (parent.getNodeType()) { |
| 254 | case ASTNode.VARIABLE_DECLARATION_EXPRESSION : |
| 255 | VariableDeclarationExpression expression = (VariableDeclarationExpression) parent; |
| 256 | modifiers = expression.getModifiers(); |
| 257 | break; |
| 258 | case ASTNode.VARIABLE_DECLARATION_STATEMENT : |
| 259 | VariableDeclarationStatement statement = (VariableDeclarationStatement) parent; |
| 260 | modifiers = statement.getModifiers(); |
| 261 | break; |
| 262 | case ASTNode.FIELD_DECLARATION : |
| 263 | FieldDeclaration fieldDeclaration = (FieldDeclaration) parent; |
| 264 | modifiers = fieldDeclaration.getModifiers(); |
| 265 | break; |
| 266 | } |
| 267 | } |
| 268 | int sourceEnd = sourceStart+sourceLength-1; |
| 269 | char[] typeSig = this.binding.type.genericTypeSignature(); |
| 270 | JavaElement parent = null; |
| 271 | IMethodBinding declaringMethod = getDeclaringMethod(); |
| 272 | if (this.binding instanceof RecordComponentBinding) { |
| 273 | return null; // TODO : SEE Bug 562736/ BUG 562637 |
| 274 | } |
| 275 | final LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; |
| 276 | if (declaringMethod == null) { |
| 277 | ReferenceContext referenceContext = localVariableBinding.declaringScope.referenceContext(); |
| 278 | if (referenceContext instanceof TypeDeclaration){ |
| 279 | // Local variable is declared inside an initializer |
| 280 | TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext; |
| 281 | JavaElement typeHandle = null; |
| 282 | typeHandle = Util.getUnresolvedJavaElement( |
| 283 | typeDeclaration.binding, |
| 284 | defaultBindingResolver.workingCopyOwner, |
| 285 | defaultBindingResolver.getBindingsToNodesMap()); |
| 286 | parent = Util.getUnresolvedJavaElement(sourceStart, sourceEnd, typeHandle); |
| 287 | } else { |
| 288 | return null; |
| 289 | } |
| 290 | } else { |
| 291 | parent = (JavaElement) declaringMethod.getJavaElement(); |
| 292 | } |
| 293 | if (parent == null) return null; |
| 294 | return new LocalVariable( |
| 295 | parent, |
| 296 | localName.getIdentifier(), |
| 297 | sourceStart, |
| 298 | sourceEnd, |
| 299 | nameStart, |
| 300 | nameStart+nameLength-1, |
| 301 | new String(typeSig), |
| 302 | localVariableBinding.declaration.annotations, |
| 303 | modifiers, |
| 304 | (localVariableBinding.tagBits & TagBits.IsArgument) != 0); |
| 305 | } |
| 306 | |
| 307 | @Override |
| 308 | public IVariableBinding getVariableDeclaration() { |
| 309 | if (isField()) { |
| 310 | FieldBinding fieldBinding = (FieldBinding) this.binding; |
| 311 | return this.resolver.getVariableBinding(fieldBinding.original()); |
| 312 | } |
| 313 | return this; |
| 314 | } |
| 315 | |
| 316 | @Override |
| 317 | public int getVariableId() { |
| 318 | return this.binding.id; |
| 319 | } |
| 320 | |
| 321 | @Override |
| 322 | public boolean isParameter() { |
| 323 | return (this.binding.tagBits & TagBits.IsArgument) != 0; |
| 324 | } |
| 325 | |
| 326 | @Override |
| 327 | public boolean isDeprecated() { |
| 328 | if (isField()) { |
| 329 | return ((FieldBinding) this.binding).isDeprecated(); |
| 330 | } |
| 331 | return false; |
| 332 | } |
| 333 | |
| 334 | @Override |
| 335 | public boolean isEnumConstant() { |
| 336 | return (this.binding.modifiers & ClassFileConstants.AccEnum) != 0; |
| 337 | } |
| 338 | |
| 339 | @Override |
| 340 | public boolean isEqualTo(IBinding other) { |
| 341 | if (other == this) { |
| 342 | // identical binding - equal (key or no key) |
| 343 | return true; |
| 344 | } |
| 345 | if (other == null) { |
| 346 | // other binding missing |
| 347 | return false; |
| 348 | } |
| 349 | if (!(other instanceof VariableBinding)) { |
| 350 | return false; |
| 351 | } |
| 352 | org.eclipse.jdt.internal.compiler.lookup.VariableBinding otherBinding = ((VariableBinding) other).binding; |
| 353 | if (this.binding instanceof FieldBinding) { |
| 354 | if (otherBinding instanceof FieldBinding) { |
| 355 | return BindingComparator.isEqual((FieldBinding) this.binding, (FieldBinding) otherBinding); |
| 356 | } else { |
| 357 | return false; |
| 358 | } |
| 359 | } else { |
| 360 | if (BindingComparator.isEqual(this.binding, otherBinding)) { |
| 361 | IMethodBinding declaringMethod = getDeclaringMethod(); |
| 362 | IMethodBinding otherDeclaringMethod = ((VariableBinding) other).getDeclaringMethod(); |
| 363 | if (declaringMethod == null) { |
| 364 | if (otherDeclaringMethod != null) { |
| 365 | return false; |
| 366 | } |
| 367 | return true; |
| 368 | } |
| 369 | return declaringMethod.isEqualTo(otherDeclaringMethod); |
| 370 | } |
| 371 | return false; |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | @Override |
| 376 | public boolean isField() { |
| 377 | return this.binding instanceof FieldBinding; |
| 378 | } |
| 379 | |
| 380 | @Override |
| 381 | public boolean isSynthetic() { |
| 382 | if (isField()) { |
| 383 | return ((FieldBinding) this.binding).isSynthetic(); |
| 384 | } |
| 385 | return false; |
| 386 | } |
| 387 | |
| 388 | @Override |
| 389 | public boolean isRecovered() { |
| 390 | return false; |
| 391 | } |
| 392 | |
| 393 | @Override |
| 394 | public boolean isEffectivelyFinal() { |
| 395 | return (!this.binding.isFinal() && this.binding.isEffectivelyFinal()); |
| 396 | } |
| 397 | |
| 398 | @Override |
| 399 | public boolean isRecordComponent() { |
| 400 | return this.binding instanceof RecordComponentBinding; |
| 401 | } |
| 402 | |
| 403 | /* |
| 404 | * For debugging purpose only. |
| 405 | * @see java.lang.Object#toString() |
| 406 | */ |
| 407 | @Override |
| 408 | public String toString() { |
| 409 | return this.binding.toString(); |
| 410 | } |
| 411 | |
| 412 | } |
| 413 |
Members