/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ 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.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Initializer; 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.BlockScope; 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. */ 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; } 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; } /* (non-Javadoc) * @see IVariableBinding#getConstantValue() * @since 3.0 */ 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 new Byte(c.byteValue()); case TypeIds.T_char: return new Character(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 new Integer(c.intValue()); case TypeIds.T_long: return new Long(c.longValue()); case TypeIds.T_short: return new Short(c.shortValue()); case TypeIds.T_JavaLangString: return c.stringValue(); } return null; } /* * @see IVariableBinding#getDeclaringClass() */ 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; } } /* * @see IVariableBinding#getDeclaringMethod() */ 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; BlockScope blockScope = localVariableBinding.declaringScope; if (blockScope != null) { ReferenceContext referenceContext = blockScope.referenceContext(); if (referenceContext instanceof Initializer) { return null; } if (referenceContext instanceof AbstractMethodDeclaration) { return this.resolver.getMethodBinding(((AbstractMethodDeclaration) referenceContext).binding); } } } return null; } switch(node.getNodeType()) { case ASTNode.INITIALIZER : return null; case ASTNode.METHOD_DECLARATION : MethodDeclaration methodDeclaration = (MethodDeclaration) node; return methodDeclaration.resolveBinding(); default: node = node.getParent(); } } } return null; } /* * @see IBinding#getJavaElement() */ public IJavaElement getJavaElement() { JavaElement element = getUnresolvedJavaElement(); if (element == null) return null; return element.resolved(this.binding); } /* * @see IBinding#getKey() */ public String getKey() { if (this.key == null) { this.key = new String(this.binding.computeUniqueKey()); } return this.key; } /* * @see IBinding#getKind() */ public int getKind() { return IBinding.VARIABLE; } /* * @see IBinding#getModifiers() */ public int getModifiers() { if (isField()) { return ((FieldBinding) this.binding).getAccessFlags() & VALID_MODIFIERS; } if (this.binding.isFinal()) { return IModifierConstants.ACC_FINAL; } return Modifier.NONE; } /* * @see IBinding#getName() */ public String getName() { if (this.name == null) { this.name = new String(this.binding.name); } return this.name; } /* * @see IVariableBinding#getType() */ 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; int nameStart; int nameLength; int sourceStart; int sourceLength; int modifiers = 0; if (localVar instanceof SingleVariableDeclaration) { sourceStart = localVar.getStartPosition(); sourceLength = localVar.getLength(); final SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) localVar; SimpleName simpleName = singleVariableDeclaration.getName(); nameStart = simpleName.getStartPosition(); nameLength = simpleName.getLength(); modifiers = singleVariableDeclaration.getModifiers(); } else { nameStart = localVar.getStartPosition(); nameLength = localVar.getLength(); 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, localVar.getName().getIdentifier(), sourceStart, sourceEnd, nameStart, nameStart+nameLength-1, new String(typeSig), localVariableBinding.declaration.annotations, modifiers, (localVariableBinding.tagBits & TagBits.IsArgument) != 0); } /* * @see IVariableBinding#getVariableDeclaration() * @since 3.1 */ public IVariableBinding getVariableDeclaration() { if (isField()) { FieldBinding fieldBinding = (FieldBinding) this.binding; return this.resolver.getVariableBinding(fieldBinding.original()); } return this; } /* * @see IVariableBinding#getVariableId() */ public int getVariableId() { return this.binding.id; } /* * @see IVariableBinding#isParameter() */ public boolean isParameter() { return (this.binding.tagBits & TagBits.IsArgument) != 0; } /* * @see IBinding#isDeprecated() */ public boolean isDeprecated() { if (isField()) { return ((FieldBinding) this.binding).isDeprecated(); } return false; } /* * @see IVariableBinding#isEnumConstant() * @since 3.1 */ public boolean isEnumConstant() { return (this.binding.modifiers & ClassFileConstants.AccEnum) != 0; } /* * @see IBinding#isEqualTo(Binding) * @since 3.1 */ 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; } } /* * @see IVariableBinding#isField() */ public boolean isField() { return this.binding instanceof FieldBinding; } /* * @see IBinding#isSynthetic() */ public boolean isSynthetic() { if (isField()) { return ((FieldBinding) this.binding).isSynthetic(); } return false; } /* * (non-Javadoc) * @see org.eclipse.jdt.core.dom.IBinding#isRecovered() */ public boolean isRecovered() { return false; } /* * For debugging purpose only. * @see java.lang.Object#toString() */ public String toString() { return this.binding.toString(); } }