Copyright (c) 2000, 2016 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - Contribution for Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda Bug 466308 - [hovering] Javadoc header for parameter is wrong with annotation-based null analysis
/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda * Bug 466308 - [hovering] Javadoc header for parameter is wrong with annotation-based null analysis *******************************************************************************/
package org.eclipse.jdt.core.dom; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.util.IModifierConstants; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.core.JavaElement; import org.eclipse.jdt.internal.core.LocalVariable; import org.eclipse.jdt.internal.core.util.Util;
Internal implementation of variable bindings.
/** * Internal implementation of variable bindings. */
class VariableBinding implements IVariableBinding { private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE; private org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding; private ITypeBinding declaringClass; private String key; private String name; private BindingResolver resolver; private ITypeBinding type; private IAnnotationBinding[] annotations; VariableBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding) { this.resolver = resolver; this.binding = binding; } @Override public IAnnotationBinding[] getAnnotations() { if (this.annotations != null) { return this.annotations; } org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = this.binding.getAnnotations(); int length = internalAnnotations == null ? 0 : internalAnnotations.length; if (length != 0) { IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; int convertedAnnotationCount = 0; for (int i = 0; i < length; i++) { org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); if (annotationInstance == null) { continue; } tempAnnotations[convertedAnnotationCount++] = annotationInstance; } if (convertedAnnotationCount != length) { if (convertedAnnotationCount == 0) { return this.annotations = AnnotationBinding.NoAnnotations; } System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); } return this.annotations = tempAnnotations; } return this.annotations = AnnotationBinding.NoAnnotations; } @Override public Object getConstantValue() { Constant c = this.binding.constant(); if (c == null || c == Constant.NotAConstant) return null; switch (c.typeID()) { case TypeIds.T_boolean: return Boolean.valueOf(c.booleanValue()); case TypeIds.T_byte: return Byte.valueOf(c.byteValue()); case TypeIds.T_char: return Character.valueOf(c.charValue()); case TypeIds.T_double: return new Double(c.doubleValue()); case TypeIds.T_float: return new Float(c.floatValue()); case TypeIds.T_int: return Integer.valueOf(c.intValue()); case TypeIds.T_long: return Long.valueOf(c.longValue()); case TypeIds.T_short: return Short.valueOf(c.shortValue()); case TypeIds.T_JavaLangString: return c.stringValue(); } return null; } @Override public ITypeBinding getDeclaringClass() { if (isField()) { if (this.declaringClass == null) { FieldBinding fieldBinding = (FieldBinding) this.binding; this.declaringClass = this.resolver.getTypeBinding(fieldBinding.declaringClass); } return this.declaringClass; } else { return null; } } @Override public IMethodBinding getDeclaringMethod() { if (!isField()) { ASTNode node = this.resolver.findDeclaringNode(this); while (true) { if (node == null) { if (this.binding instanceof LocalVariableBinding) { LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; org.eclipse.jdt.internal.compiler.lookup.MethodBinding enclosingMethod = localVariableBinding.getEnclosingMethod(); if (enclosingMethod != null) return this.resolver.getMethodBinding(enclosingMethod); } return null; } switch(node.getNodeType()) { case ASTNode.INITIALIZER : return null; case ASTNode.METHOD_DECLARATION : MethodDeclaration methodDeclaration = (MethodDeclaration) node; return methodDeclaration.resolveBinding(); case ASTNode.LAMBDA_EXPRESSION : LambdaExpression lambdaExpression = (LambdaExpression) node; return lambdaExpression.resolveMethodBinding(); default: node = node.getParent(); } } } return null; } @Override public IJavaElement getJavaElement() { JavaElement element = getUnresolvedJavaElement(); if (element == null) return null; return element.resolved(this.binding); } @Override public String getKey() { if (this.key == null) { this.key = new String(this.binding.computeUniqueKey()); } return this.key; } @Override public int getKind() { return IBinding.VARIABLE; } @Override public int getModifiers() { if (isField()) { return ((FieldBinding) this.binding).getAccessFlags() & VALID_MODIFIERS; } if (this.binding.isFinal()) { return IModifierConstants.ACC_FINAL; } return Modifier.NONE; } @Override public String getName() { if (this.name == null) { this.name = new String(this.binding.name); } return this.name; } @Override public ITypeBinding getType() { if (this.type == null) { this.type = this.resolver.getTypeBinding(this.binding.type); } return this.type; } private JavaElement getUnresolvedJavaElement() { if (JavaCore.getPlugin() == null) { return null; } if (isField()) { if (this.resolver instanceof DefaultBindingResolver) { DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; if (!defaultBindingResolver.fromJavaProject) return null; return Util.getUnresolvedJavaElement( (FieldBinding) this.binding, defaultBindingResolver.workingCopyOwner, defaultBindingResolver.getBindingsToNodesMap()); } return null; } // local variable if (!(this.resolver instanceof DefaultBindingResolver)) return null; DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; if (!defaultBindingResolver.fromJavaProject) return null; VariableDeclaration localVar = (VariableDeclaration) defaultBindingResolver.bindingsToAstNodes.get(this); if (localVar == null) return null; SimpleName localName = localVar.getName(); int nameStart = localName.getStartPosition(); int nameLength = localName.getLength(); int sourceStart; int sourceLength; int modifiers = 0; if (localVar instanceof SingleVariableDeclaration) { sourceStart = localVar.getStartPosition(); sourceLength = localVar.getLength(); final SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) localVar; modifiers = singleVariableDeclaration.getModifiers(); } else { ASTNode node = localVar.getParent(); sourceStart = node.getStartPosition(); sourceLength = node.getLength(); VariableDeclarationFragment fragment = (VariableDeclarationFragment) localVar; final ASTNode parent = fragment.getParent(); switch (parent.getNodeType()) { case ASTNode.VARIABLE_DECLARATION_EXPRESSION : VariableDeclarationExpression expression = (VariableDeclarationExpression) parent; modifiers = expression.getModifiers(); break; case ASTNode.VARIABLE_DECLARATION_STATEMENT : VariableDeclarationStatement statement = (VariableDeclarationStatement) parent; modifiers = statement.getModifiers(); break; case ASTNode.FIELD_DECLARATION : FieldDeclaration fieldDeclaration = (FieldDeclaration) parent; modifiers = fieldDeclaration.getModifiers(); break; } } int sourceEnd = sourceStart+sourceLength-1; char[] typeSig = this.binding.type.genericTypeSignature(); JavaElement parent = null; IMethodBinding declaringMethod = getDeclaringMethod(); final LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; if (declaringMethod == null) { ReferenceContext referenceContext = localVariableBinding.declaringScope.referenceContext(); if (referenceContext instanceof TypeDeclaration){ // Local variable is declared inside an initializer TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext; JavaElement typeHandle = null; typeHandle = Util.getUnresolvedJavaElement( typeDeclaration.binding, defaultBindingResolver.workingCopyOwner, defaultBindingResolver.getBindingsToNodesMap()); parent = Util.getUnresolvedJavaElement(sourceStart, sourceEnd, typeHandle); } else { return null; } } else { parent = (JavaElement) declaringMethod.getJavaElement(); } if (parent == null) return null; return new LocalVariable( parent, localName.getIdentifier(), sourceStart, sourceEnd, nameStart, nameStart+nameLength-1, new String(typeSig), localVariableBinding.declaration.annotations, modifiers, (localVariableBinding.tagBits & TagBits.IsArgument) != 0); } @Override public IVariableBinding getVariableDeclaration() { if (isField()) { FieldBinding fieldBinding = (FieldBinding) this.binding; return this.resolver.getVariableBinding(fieldBinding.original()); } return this; } @Override public int getVariableId() { return this.binding.id; } @Override public boolean isParameter() { return (this.binding.tagBits & TagBits.IsArgument) != 0; } @Override public boolean isDeprecated() { if (isField()) { return ((FieldBinding) this.binding).isDeprecated(); } return false; } @Override public boolean isEnumConstant() { return (this.binding.modifiers & ClassFileConstants.AccEnum) != 0; } @Override public boolean isEqualTo(IBinding other) { if (other == this) { // identical binding - equal (key or no key) return true; } if (other == null) { // other binding missing return false; } if (!(other instanceof VariableBinding)) { return false; } org.eclipse.jdt.internal.compiler.lookup.VariableBinding otherBinding = ((VariableBinding) other).binding; if (this.binding instanceof FieldBinding) { if (otherBinding instanceof FieldBinding) { return BindingComparator.isEqual((FieldBinding) this.binding, (FieldBinding) otherBinding); } else { return false; } } else { if (BindingComparator.isEqual(this.binding, otherBinding)) { IMethodBinding declaringMethod = getDeclaringMethod(); IMethodBinding otherDeclaringMethod = ((VariableBinding) other).getDeclaringMethod(); if (declaringMethod == null) { if (otherDeclaringMethod != null) { return false; } return true; } return declaringMethod.isEqualTo(otherDeclaringMethod); } return false; } } @Override public boolean isField() { return this.binding instanceof FieldBinding; } @Override public boolean isSynthetic() { if (isField()) { return ((FieldBinding) this.binding).isSynthetic(); } return false; } @Override public boolean isRecovered() { return false; } @Override public boolean isEffectivelyFinal() { return (!this.binding.isFinal() && this.binding.isEffectivelyFinal()); } /* * For debugging purpose only. * @see java.lang.Object#toString() */ @Override public String toString() { return this.binding.toString(); } }