blob: c96f153a8ac67f343a926b2c6647d8572c55bb0d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.internal.compiler.lookup;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
public final class LocalTypeBinding extends NestedTypeBinding {
final static char[] LocalTypePrefix = { '$', 'L', 'o', 'c', 'a', 'l', '$' };
private InnerEmulationDependency[] dependents;
public ArrayBinding[] localArrayBindings; // used to cache array bindings of various dimensions for this local type
public CaseStatement enclosingCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221)
int sourceStart; // used by computeUniqueKey to uniquely identify this binding
public MethodBinding enclosingMethod;
public LocalTypeBinding(ClassScope scope, SourceTypeBinding enclosingType, CaseStatement switchCase) {
super(
new char[][] {CharOperation.concat(LocalTypePrefix, scope.referenceContext.name)},
scope,
enclosingType);
if (this.sourceName == TypeDeclaration.ANONYMOUS_EMPTY_NAME)
this.tagBits |= AnonymousTypeMask;
else
this.tagBits |= LocalTypeMask;
this.enclosingCase = switchCase;
this.sourceStart = scope.referenceContext.sourceStart;
MethodScope methodScope = scope.enclosingMethodScope();
AbstractMethodDeclaration declaration = methodScope.referenceMethod();
if (declaration != null) {
this.enclosingMethod = declaration.binding;
}
}
/* Record a dependency onto a source target type which may be altered
* by the end of the innerclass emulation. Later on, we will revisit
* all its dependents so as to update them (see updateInnerEmulationDependents()).
*/
public void addInnerEmulationDependent(BlockScope dependentScope, boolean wasEnclosingInstanceSupplied) {
int index;
if (dependents == null) {
index = 0;
dependents = new InnerEmulationDependency[1];
} else {
index = dependents.length;
for (int i = 0; i < index; i++)
if (dependents[i].scope == dependentScope)
return; // already stored
System.arraycopy(dependents, 0, (dependents = new InnerEmulationDependency[index + 1]), 0, index);
}
dependents[index] = new InnerEmulationDependency(dependentScope, wasEnclosingInstanceSupplied);
// System.out.println("Adding dependency: "+ new String(scope.enclosingType().readableName()) + " --> " + new String(this.readableName()));
}
public char[] computeUniqueKey(boolean withAccessFlags) {
ReferenceBinding enclosing = enclosingType();
ReferenceBinding temp;
while ((temp = enclosing.enclosingType()) != null)
enclosing = temp;
StringBuffer buffer = new StringBuffer();
buffer.append(enclosing.computeUniqueKey(withAccessFlags));
int semicolon = buffer.lastIndexOf(";"); //$NON-NLS-1$
buffer.insert(semicolon, '$');
semicolon = buffer.lastIndexOf(";"); //$NON-NLS-1$
buffer.insert(semicolon, this.sourceStart);
int length = buffer.length();
char[] uniqueKey = new char[length];
buffer.getChars(0, length, uniqueKey, 0);
return uniqueKey;
}
public char[] constantPoolName() /* java/lang/Object */ {
return constantPoolName;
}
ArrayBinding createArrayType(int dimensionCount) {
if (localArrayBindings == null) {
localArrayBindings = new ArrayBinding[] {new ArrayBinding(this, dimensionCount, scope.environment())};
return localArrayBindings[0];
}
// find the cached array binding for this dimensionCount (if any)
int length = localArrayBindings.length;
for (int i = 0; i < length; i++)
if (localArrayBindings[i].dimensions == dimensionCount)
return localArrayBindings[i];
// no matching array
System.arraycopy(localArrayBindings, 0, localArrayBindings = new ArrayBinding[length + 1], 0, length);
return localArrayBindings[length] = new ArrayBinding(this, dimensionCount, scope.environment());
}
public char[] readableName() /*java.lang.Object, p.X<T> */ {
char[] readableName;
if (isAnonymousType()) {
if (superInterfaces == NoSuperInterfaces)
readableName = CharOperation.concat(TypeConstants.ANONYM_PREFIX, superclass.readableName(), TypeConstants.ANONYM_SUFFIX);
else
readableName = CharOperation.concat(TypeConstants.ANONYM_PREFIX, superInterfaces[0].readableName(), TypeConstants.ANONYM_SUFFIX);
} else if (isMemberType()) {
readableName = CharOperation.concat(enclosingType().readableName(), this.sourceName, '.');
} else {
readableName = this.sourceName;
}
TypeVariableBinding[] typeVars;
if ((typeVars = this.typeVariables()) != NoTypeVariables) {
StringBuffer nameBuffer = new StringBuffer(10);
nameBuffer.append(readableName).append('<');
for (int i = 0, length = typeVars.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(typeVars[i].readableName());
}
nameBuffer.append('>');
int nameLength = nameBuffer.length();
readableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, readableName, 0);
}
return readableName;
}
public char[] shortReadableName() /*Object*/ {
char[] shortReadableName;
if (isAnonymousType()) {
if (superInterfaces == NoSuperInterfaces)
shortReadableName = CharOperation.concat(TypeConstants.ANONYM_PREFIX, superclass.shortReadableName(), TypeConstants.ANONYM_SUFFIX);
else
shortReadableName = CharOperation.concat(TypeConstants.ANONYM_PREFIX, superInterfaces[0].shortReadableName(), TypeConstants.ANONYM_SUFFIX);
} else if (isMemberType()) {
shortReadableName = CharOperation.concat(enclosingType().shortReadableName(), sourceName, '.');
} else {
shortReadableName = sourceName;
}
TypeVariableBinding[] typeVars;
if ((typeVars = this.typeVariables()) != NoTypeVariables) {
StringBuffer nameBuffer = new StringBuffer(10);
nameBuffer.append(shortReadableName).append('<');
for (int i = 0, length = typeVars.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
nameBuffer.append(typeVars[i].shortReadableName());
}
nameBuffer.append('>');
int nameLength = nameBuffer.length();
shortReadableName = new char[nameLength];
nameBuffer.getChars(0, nameLength, shortReadableName, 0);
}
return shortReadableName;
}
// Record that the type is a local member type
public void setAsMemberType() {
tagBits |= MemberTypeMask;
}
public void setConstantPoolName(char[] computedConstantPoolName) /* java/lang/Object */ {
this.constantPoolName = computedConstantPoolName;
}
public char[] sourceName() {
if (isAnonymousType()) {
if (superInterfaces == NoSuperInterfaces)
return CharOperation.concat(TypeConstants.ANONYM_PREFIX, superclass.sourceName(), TypeConstants.ANONYM_SUFFIX);
else
return CharOperation.concat(TypeConstants.ANONYM_PREFIX, superInterfaces[0].sourceName(), TypeConstants.ANONYM_SUFFIX);
} else
return sourceName;
}
public String toString() {
if (isAnonymousType())
return "Anonymous type : " + super.toString(); //$NON-NLS-1$
if (isMemberType())
return "Local member type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$
return "Local type : " + new String(sourceName()) + " " + super.toString(); //$NON-NLS-2$ //$NON-NLS-1$
}
/* Trigger the dependency mechanism forcing the innerclass emulation
* to be propagated to all dependent source types.
*/
public void updateInnerEmulationDependents() {
if (dependents != null) {
for (int i = 0; i < dependents.length; i++) {
InnerEmulationDependency dependency = dependents[i];
// System.out.println("Updating " + new String(this.readableName()) + " --> " + new String(dependency.scope.enclosingType().readableName()));
dependency.scope.propagateInnerEmulation(this, dependency.wasEnclosingInstanceSupplied);
}
}
}
}