1 /*******************************************************************************
2 * Copyright (c) 2007, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package net.sourceforge.phpdt.core.dom;
14 import java.util.List;
16 import net.sourceforge.phpdt.core.IJavaElement;
17 import net.sourceforge.phpdt.core.compiler.CharOperation;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.Binding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
22 import net.sourceforge.phpdt.internal.compiler.util.SuffixConstants;
23 import net.sourceforge.phpdt.internal.compiler.util.Util;
24 import net.sourceforge.phpdt.internal.core.PackageFragment;
27 * This class represents the recovered binding for a type
29 class RecoveredTypeBinding implements ITypeBinding {
31 private VariableDeclaration variableDeclaration;
32 private Type currentType;
33 private BindingResolver resolver;
34 private int dimensions;
35 private RecoveredTypeBinding innerTypeBinding;
36 private ITypeBinding[] typeArguments;
37 private net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding binding;
39 RecoveredTypeBinding(BindingResolver resolver, VariableDeclaration variableDeclaration) {
40 this.variableDeclaration = variableDeclaration;
41 this.resolver = resolver;
42 this.currentType = getType();
43 this.dimensions = variableDeclaration.getExtraDimensions();
44 if (this.currentType.isArrayType()) {
45 this.dimensions += ((ArrayType) this.currentType).getDimensions();
49 RecoveredTypeBinding(BindingResolver resolver, net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding typeBinding) {
50 this.resolver = resolver;
51 this.dimensions = typeBinding.dimensions();
52 this.binding = typeBinding;
55 RecoveredTypeBinding(BindingResolver resolver, Type type) {
56 this.currentType = type;
57 this.resolver = resolver;
59 if (type.isArrayType()) {
60 this.dimensions += ((ArrayType) type).getDimensions();
64 RecoveredTypeBinding(BindingResolver resolver, RecoveredTypeBinding typeBinding, int dimensions) {
65 this.innerTypeBinding = typeBinding;
66 this.dimensions = typeBinding.getDimensions() + dimensions;
67 this.resolver = resolver;
71 * @see org.eclipse.jdt.core.dom.ITypeBinding#createArrayType(int)
73 public ITypeBinding createArrayType(int dims) {
74 return this.resolver.getTypeBinding(this, dims);
78 * @see org.eclipse.jdt.core.dom.ITypeBinding#getBinaryName()
80 public String getBinaryName() {
85 * @see org.eclipse.jdt.core.dom.ITypeBinding#getBound()
87 public ITypeBinding getBound() {
92 * @see org.eclipse.jdt.core.dom.ITypeBinding#getComponentType()
94 public ITypeBinding getComponentType() {
95 if (this.dimensions == 0) return null;
96 return this.resolver.getTypeBinding(this, -1);
100 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredFields()
102 public IVariableBinding[] getDeclaredFields() {
103 return TypeBinding.NO_VARIABLE_BINDINGS;
107 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredMethods()
109 public IMethodBinding[] getDeclaredMethods() {
110 return TypeBinding.NO_METHOD_BINDINGS;
114 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredModifiers()
116 public int getDeclaredModifiers() {
121 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredTypes()
123 public ITypeBinding[] getDeclaredTypes() {
124 return TypeBinding.NO_TYPE_BINDINGS;
128 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaringClass()
130 public ITypeBinding getDeclaringClass() {
135 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaringMethod()
137 public IMethodBinding getDeclaringMethod() {
142 * @see org.eclipse.jdt.core.dom.ITypeBinding#getDimensions()
144 public int getDimensions() {
145 return this.dimensions;
149 * @see org.eclipse.jdt.core.dom.ITypeBinding#getElementType()
151 public ITypeBinding getElementType() {
152 if (this.binding != null) {
153 if (this.binding.isArrayType()) {
154 ArrayBinding arrayBinding = (ArrayBinding) this.binding;
155 return new RecoveredTypeBinding(this.resolver, arrayBinding.leafComponentType);
157 return new RecoveredTypeBinding(this.resolver, this.binding);
160 if (this.innerTypeBinding != null) {
161 return this.innerTypeBinding.getElementType();
163 if (this.currentType!= null && this.currentType.isArrayType()) {
164 return this.resolver.getTypeBinding(((ArrayType) this.currentType).getElementType());
166 if (this.variableDeclaration != null && this.variableDeclaration.getExtraDimensions() != 0) {
167 return this.resolver.getTypeBinding(getType());
173 * @see org.eclipse.jdt.core.dom.ITypeBinding#getErasure()
175 public ITypeBinding getErasure() {
180 * @see org.eclipse.jdt.core.dom.ITypeBinding#getInterfaces()
182 public ITypeBinding[] getInterfaces() {
183 return TypeBinding.NO_TYPE_BINDINGS;
187 * @see org.eclipse.jdt.core.dom.ITypeBinding#getModifiers()
189 public int getModifiers() {
190 return Modifier.NONE;
194 * @see org.eclipse.jdt.core.dom.ITypeBinding#getName()
196 public String getName() {
197 char[] brackets = new char[this.dimensions * 2];
198 for (int i = this.dimensions * 2 - 1; i >= 0; i -= 2) {
200 brackets[i - 1] = '[';
202 StringBuffer buffer = new StringBuffer(this.getInternalName());
203 buffer.append(brackets);
204 return String.valueOf(buffer);
207 private String getInternalName() {
208 if (this.innerTypeBinding != null) {
209 return this.innerTypeBinding.getInternalName();
211 ReferenceBinding referenceBinding = getReferenceBinding();
212 if (referenceBinding != null) {
213 return new String(referenceBinding.compoundName[referenceBinding.compoundName.length - 1]);
215 return this.getTypeNameFrom(getType());
219 * @see org.eclipse.jdt.core.dom.ITypeBinding#getPackage()
221 public IPackageBinding getPackage() {
222 if (this.binding != null) {
223 switch (this.binding.kind()) {
224 case Binding.BASE_TYPE :
225 case Binding.ARRAY_TYPE :
226 case Binding.TYPE_PARAMETER : // includes capture scenario
227 case Binding.WILDCARD_TYPE :
228 case Binding.INTERSECTION_TYPE:
231 IPackageBinding packageBinding = this.resolver.getPackageBinding(this.binding.getPackage());
232 if (packageBinding != null) return packageBinding;
234 if (this.innerTypeBinding != null && this.dimensions > 0) {
237 CompilationUnitScope scope = this.resolver.scope();
239 return this.resolver.getPackageBinding(scope.getCurrentPackage());
245 * @see org.eclipse.jdt.core.dom.ITypeBinding#getQualifiedName()
247 public String getQualifiedName() {
248 ReferenceBinding referenceBinding = getReferenceBinding();
249 if (referenceBinding != null) {
250 StringBuffer buffer = new StringBuffer();
251 char[] brackets = new char[this.dimensions * 2];
252 for (int i = this.dimensions * 2 - 1; i >= 0; i -= 2) {
254 brackets[i - 1] = '[';
256 buffer.append(CharOperation.toString(referenceBinding.compoundName));
257 buffer.append(brackets);
258 return String.valueOf(buffer);
264 private ReferenceBinding getReferenceBinding() {
265 if (this.binding != null) {
266 if (this.binding.isArrayType()) {
267 ArrayBinding arrayBinding = (ArrayBinding) this.binding;
268 if (arrayBinding.leafComponentType instanceof ReferenceBinding) {
269 return (ReferenceBinding) arrayBinding.leafComponentType;
271 } else if (this.binding instanceof ReferenceBinding) {
272 return (ReferenceBinding) this.binding;
274 } else if (this.innerTypeBinding != null) {
275 return this.innerTypeBinding.getReferenceBinding();
281 * @see org.eclipse.jdt.core.dom.ITypeBinding#getSuperclass()
283 public ITypeBinding getSuperclass() {
284 if (getQualifiedName().equals("java.lang.Object")) { //$NON-NLS-1$
287 return this.resolver.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
291 * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeArguments()
293 public ITypeBinding[] getTypeArguments() {
294 if (this.binding != null) {
295 return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS;
297 if (this.typeArguments != null) {
298 return typeArguments;
301 if (this.innerTypeBinding != null) {
302 return this.innerTypeBinding.getTypeArguments();
305 if (this.currentType.isParameterizedType()) {
306 ParameterizedType parameterizedType = (ParameterizedType) this.currentType;
307 List typeArgumentsList = parameterizedType.typeArguments();
308 int size = typeArgumentsList.size();
309 ITypeBinding[] temp = new ITypeBinding[size];
310 for (int i = 0; i < size; i++) {
311 ITypeBinding currentTypeBinding = ((Type) typeArgumentsList.get(i)).resolveBinding();
312 if (currentTypeBinding == null) {
313 return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS;
315 temp[i] = currentTypeBinding;
317 return this.typeArguments = temp;
319 return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS;
323 * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeBounds()
325 public ITypeBinding[] getTypeBounds() {
326 return TypeBinding.NO_TYPE_BINDINGS;
330 * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeDeclaration()
332 public ITypeBinding getTypeDeclaration() {
337 * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeParameters()
339 public ITypeBinding[] getTypeParameters() {
340 return TypeBinding.NO_TYPE_BINDINGS;
344 * @see org.eclipse.jdt.core.dom.ITypeBinding#getWildcard()
346 public ITypeBinding getWildcard() {
351 * @see org.eclipse.jdt.core.dom.ITypeBinding#isAnnotation()
353 public boolean isAnnotation() {
358 * @see org.eclipse.jdt.core.dom.ITypeBinding#isAnonymous()
360 public boolean isAnonymous() {
365 * @see org.eclipse.jdt.core.dom.ITypeBinding#isArray()
367 public boolean isArray() {
372 * @see org.eclipse.jdt.core.dom.ITypeBinding#isAssignmentCompatible(org.eclipse.jdt.core.dom.ITypeBinding)
374 public boolean isAssignmentCompatible(ITypeBinding typeBinding) {
375 if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$
378 // since recovered binding are not unique isEqualTo is required
379 return this.isEqualTo(typeBinding);
383 * @see org.eclipse.jdt.core.dom.ITypeBinding#isCapture()
385 public boolean isCapture() {
390 * @see org.eclipse.jdt.core.dom.ITypeBinding#isCastCompatible(org.eclipse.jdt.core.dom.ITypeBinding)
392 public boolean isCastCompatible(ITypeBinding typeBinding) {
393 if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$
396 // since recovered binding are not unique isEqualTo is required
397 return this.isEqualTo(typeBinding);
401 * @see org.eclipse.jdt.core.dom.ITypeBinding#isClass()
403 public boolean isClass() {
408 * @see org.eclipse.jdt.core.dom.ITypeBinding#isEnum()
410 public boolean isEnum() {
415 * @see org.eclipse.jdt.core.dom.ITypeBinding#isFromSource()
417 public boolean isFromSource() {
422 * @see org.eclipse.jdt.core.dom.ITypeBinding#isGenericType()
424 public boolean isGenericType() {
429 * @see org.eclipse.jdt.core.dom.ITypeBinding#isInterface()
431 public boolean isInterface() {
436 * @see org.eclipse.jdt.core.dom.ITypeBinding#isLocal()
438 public boolean isLocal() {
443 * @see org.eclipse.jdt.core.dom.ITypeBinding#isMember()
445 public boolean isMember() {
450 * @see org.eclipse.jdt.core.dom.ITypeBinding#isNested()
452 public boolean isNested() {
457 * @see org.eclipse.jdt.core.dom.ITypeBinding#isNullType()
459 public boolean isNullType() {
464 * @see org.eclipse.jdt.core.dom.ITypeBinding#isParameterizedType()
466 public boolean isParameterizedType() {
467 if (this.innerTypeBinding != null) {
468 return this.innerTypeBinding.isParameterizedType();
470 if (this.currentType != null) {
471 return this.currentType.isParameterizedType();
477 * @see org.eclipse.jdt.core.dom.ITypeBinding#isPrimitive()
479 public boolean isPrimitive() {
484 * @see org.eclipse.jdt.core.dom.ITypeBinding#isRawType()
486 public boolean isRawType() {
491 * @see org.eclipse.jdt.core.dom.ITypeBinding#isSubTypeCompatible(org.eclipse.jdt.core.dom.ITypeBinding)
493 public boolean isSubTypeCompatible(ITypeBinding typeBinding) {
494 if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$
497 // since recovered binding are not unique isEqualTo is required
498 return this.isEqualTo(typeBinding);
502 * @see org.eclipse.jdt.core.dom.ITypeBinding#isTopLevel()
504 public boolean isTopLevel() {
509 * @see org.eclipse.jdt.core.dom.ITypeBinding#isTypeVariable()
511 public boolean isTypeVariable() {
516 * @see org.eclipse.jdt.core.dom.ITypeBinding#isUpperbound()
518 public boolean isUpperbound() {
523 * @see org.eclipse.jdt.core.dom.ITypeBinding#isWildcardType()
525 public boolean isWildcardType() {
530 * @see org.eclipse.jdt.core.dom.IBinding#getAnnotations()
532 public IAnnotationBinding[] getAnnotations() {
533 return AnnotationBinding.NoAnnotations;
537 * @see org.eclipse.jdt.core.dom.IBinding#getJavaElement()
539 public IJavaElement getJavaElement() {
540 IPackageBinding packageBinding = getPackage();
541 if (packageBinding != null) {
542 final IJavaElement javaElement = packageBinding.getJavaElement();
543 if (javaElement != null && javaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
544 // best effort: we don't know if the recovered binding is a binary or source binding, so go with a compilation unit
545 return ((PackageFragment) javaElement).getCompilationUnit(getInternalName() + SuffixConstants.SUFFIX_STRING_java);
552 * @see org.eclipse.jdt.core.dom.IBinding#getKey()
554 public String getKey() {
555 StringBuffer buffer = new StringBuffer();
556 buffer.append("Recovered#"); //$NON-NLS-1$
557 if (this.innerTypeBinding != null) {
558 buffer.append("innerTypeBinding") //$NON-NLS-1$
559 .append(this.innerTypeBinding.getKey());
560 } else if (this.currentType != null) {
561 buffer.append("currentType") //$NON-NLS-1$
562 .append(this.currentType.toString());
563 } else if (this.binding != null) {
564 buffer.append("typeBinding") //$NON-NLS-1$
565 .append(this.binding.computeUniqueKey());
566 } else if (variableDeclaration != null) {
568 .append("variableDeclaration") //$NON-NLS-1$
569 .append(this.variableDeclaration.getClass())
570 .append(this.variableDeclaration.getName().getIdentifier())
571 .append(this.variableDeclaration.getExtraDimensions());
573 buffer.append(this.getDimensions());
574 if (this.typeArguments != null) {
576 for (int i = 0, max = this.typeArguments.length; i < max; i++) {
580 buffer.append(this.typeArguments[i].getKey());
584 return String.valueOf(buffer);
588 * @see org.eclipse.jdt.core.dom.IBinding#getKind()
590 public int getKind() {
591 return IBinding.TYPE;
595 * @see org.eclipse.jdt.core.dom.IBinding#isDeprecated()
597 public boolean isDeprecated() {
602 * @see org.eclipse.jdt.core.dom.IBinding#isEqualTo(org.eclipse.jdt.core.dom.IBinding)
604 public boolean isEqualTo(IBinding other) {
605 if (!other.isRecovered() || other.getKind() != IBinding.TYPE) return false;
606 return this.getKey().equals(other.getKey());
610 * @see org.eclipse.jdt.core.dom.IBinding#isRecovered()
612 public boolean isRecovered() {
617 * @see org.eclipse.jdt.core.dom.IBinding#isSynthetic()
619 public boolean isSynthetic() {
623 private String getTypeNameFrom(Type type) {
624 if (type == null) return Util.EMPTY_STRING;
625 switch(type.getNodeType0()) {
626 case ASTNode.ARRAY_TYPE :
627 ArrayType arrayType = (ArrayType) type;
628 type = arrayType.getElementType();
629 return getTypeNameFrom(type);
630 case ASTNode.PARAMETERIZED_TYPE :
631 ParameterizedType parameterizedType = (ParameterizedType) type;
632 StringBuffer buffer = new StringBuffer(getTypeNameFrom(parameterizedType.getType()));
633 ITypeBinding[] tArguments = getTypeArguments();
634 final int typeArgumentsLength = tArguments.length;
635 if (typeArgumentsLength != 0) {
637 for (int i = 0; i < typeArgumentsLength; i++) {
641 buffer.append(tArguments[i].getName());
645 return String.valueOf(buffer);
646 case ASTNode.PRIMITIVE_TYPE :
647 PrimitiveType primitiveType = (PrimitiveType) type;
648 return primitiveType.getPrimitiveTypeCode().toString();
649 case ASTNode.QUALIFIED_TYPE :
650 QualifiedType qualifiedType = (QualifiedType) type;
651 return qualifiedType.getName().getIdentifier();
652 case ASTNode.SIMPLE_TYPE :
653 SimpleType simpleType = (SimpleType) type;
654 Name name = simpleType.getName();
655 if (name.isQualifiedName()) {
656 QualifiedName qualifiedName = (QualifiedName) name;
657 return qualifiedName.getName().getIdentifier();
659 return ((SimpleName) name).getIdentifier();
661 return Util.EMPTY_STRING;
664 private Type getType() {
665 if (this.currentType != null) {
666 return this.currentType;
668 if (this.variableDeclaration == null) return null;
669 switch(this.variableDeclaration.getNodeType()) {
670 case ASTNode.SINGLE_VARIABLE_DECLARATION :
671 SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) this.variableDeclaration;
672 return singleVariableDeclaration.getType();
674 // this is a variable declaration fragment
675 ASTNode parent = this.variableDeclaration.getParent();
676 switch(parent.getNodeType()) {
677 case ASTNode.VARIABLE_DECLARATION_EXPRESSION :
678 VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) parent;
679 return variableDeclarationExpression.getType();
680 case ASTNode.VARIABLE_DECLARATION_STATEMENT :
681 VariableDeclarationStatement statement = (VariableDeclarationStatement) parent;
682 return statement.getType();
683 case ASTNode.FIELD_DECLARATION :
684 FieldDeclaration fieldDeclaration = (FieldDeclaration) parent;
685 return fieldDeclaration.getType();
688 return null; // should not happen