blob: 32b6ccd5dbf618ab75fe50e3de8e540ad9303f59 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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
* Erling Ellingsen - patch for bug 125570
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.compiler.lookup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.eclipse.wst.jsdt.core.LibrarySuperType;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.compiler.libraries.SystemLibraryLocation;
import org.eclipse.wst.jsdt.core.infer.InferEngine;
import org.eclipse.wst.jsdt.core.infer.InferredType;
import org.eclipse.wst.jsdt.core.infer.InferrenceManager;
import org.eclipse.wst.jsdt.core.infer.InferrenceProvider;
import org.eclipse.wst.jsdt.internal.codeassist.ISearchRequestor;
import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor;
import org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode;
import org.eclipse.wst.jsdt.internal.compiler.ast.Assignment;
import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.FunctionExpression;
import org.eclipse.wst.jsdt.internal.compiler.ast.ImportReference;
import org.eclipse.wst.jsdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction;
import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.wst.jsdt.internal.compiler.util.CompoundNameVector;
import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfType;
import org.eclipse.wst.jsdt.internal.compiler.util.ObjectVector;
import org.eclipse.wst.jsdt.internal.compiler.util.SimpleNameVector;
import org.eclipse.wst.jsdt.internal.compiler.util.SimpleSetOfCharArray;
import org.eclipse.wst.jsdt.internal.core.SearchableEnvironment;
import org.eclipse.wst.jsdt.internal.core.search.indexing.IIndexConstants;
import org.eclipse.wst.jsdt.internal.core.util.QualificationHelpers;
import org.eclipse.wst.jsdt.internal.core.util.Util;
public class CompilationUnitScope extends BlockScope {
public LookupEnvironment environment;
public CompilationUnitDeclaration referenceContext;
public char[][] currentPackageName;
public PackageBinding fPackage;
public ImportBinding[] imports;
public HashtableOfObject typeOrPackageCache; // used in Scope.getTypeOrPackage()
public SourceTypeBinding[] topLevelTypes;
public SourceTypeBinding[] existingTopLevelTypes;
private CompoundNameVector qualifiedReferences;
private SimpleNameVector simpleNameReferences;
private ObjectVector referencedTypes;
private ObjectVector referencedSuperTypes;
HashtableOfType constantPoolNameUsage;
public int analysisIndex;
private int captureID = 1;
/* Allows a compilation unit to inherit fields from a superType */
public ReferenceBinding superBinding;
/**
* <p>
* <code>true</code> if the {@link #superBinding} is currently being
* built, <code>false</code> otherwise.
* </p>
*
* @see #buildSuperType()
* @see #fBuidingSuperBindingLock
*/
private volatile boolean fBuildingSuperBinding;
/**
* <p>
* Lock that should be used when using the {@link #fBuildingSuperBinding}
* property.
* </p>
*/
private final Object fBuidingSuperBindingLock = new Object();
/**
* boolean flag to determine if we need to build the
* Global Super Type for this scope.
*/
private boolean shouldBuildGlobalSuperType = false;
private ClassScope classScope;
public int temporaryAnalysisIndex;
public HashSet externalCompilationUnits = new HashSet();
public static final char FILENAME_DOT_SUBSTITUTION = '#';
class DeclarationVisitor extends ASTVisitor {
ArrayList methods = new ArrayList();
public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
if(localDeclaration.initialization instanceof FunctionExpression) {
this.visit(((FunctionExpression) localDeclaration.initialization).getMethodDeclaration(), scope);
} else {
TypeBinding type = localDeclaration.resolveVarType(scope);
LocalVariableBinding binding = new LocalVariableBinding(localDeclaration, type, 0, false);
localDeclaration.binding = binding;
addLocalVariable(binding);
}
return false;
}
/**
* @see org.eclipse.wst.jsdt.internal.compiler.ASTVisitor#visit(org.eclipse.wst.jsdt.internal.compiler.ast.Assignment, org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope)
*/
public boolean visit(Assignment assignment, BlockScope scope) {
/* If assigning to single name reference and there is no existing local
* variable binding for that reference, create one. This is for the case
* where their is no variable declaration in the compilation unit but the
* variable is assigned to.
*/
if(assignment.lhs instanceof SingleNameReference) {
SingleNameReference ref = (SingleNameReference)assignment.lhs;
//only create new binding if one does not already exist
LocalVariableBinding existingBinding = scope.compilationUnitScope().findVariable(ref.getToken());
if(existingBinding == null) {
LocalDeclaration localDeclaration = new LocalDeclaration(ref.getToken(),ref.sourceStart,ref.sourceEnd);
localDeclaration.inferredType = assignment.getInferredType();
TypeBinding binding = null;
if(localDeclaration.inferredType != null) {
binding = localDeclaration.inferredType.resolveType(scope.compilationUnitScope(), assignment);
}
LocalVariableBinding localBinding = new LocalVariableBinding(localDeclaration, binding, 0, false);
scope.compilationUnitScope().addLocalVariable(localBinding);
}
}
return super.visit(assignment, scope);
}
public boolean visit(MethodDeclaration methodDeclaration, Scope parentScope) {
// do not visit functions that are defined in another type, they will be visisted in
// that type
if(methodDeclaration.inferredMethod == null || methodDeclaration.inferredMethod.inType == null || methodDeclaration.inferredMethod.isConstructor) {
char[] selector = methodDeclaration.getName();
boolean isConstructor = false;
if(methodDeclaration.inferredMethod != null && methodDeclaration.inferredMethod.isConstructor) {
isConstructor = true;
}
MethodScope scope = new MethodScope(parentScope, methodDeclaration, false);
if(selector != null && !methodDeclaration.hasBinding()) {
MethodBinding methodBinding =
scope.createMethod(methodDeclaration, selector, referenceContext.compilationUnitBinding,
isConstructor, false);
// is null if binding could not be created
if(methodBinding != null && methodBinding.selector != null) {
methods.add(methodBinding);
}
if(methodBinding.selector != null) {
environment.defaultPackage.addBinding(methodBinding, methodBinding.selector, Binding.METHOD);
fPackage.addBinding(methodBinding, methodBinding.selector, Binding.METHOD);
}
methodDeclaration.setBinding(methodBinding);
} else {
methodDeclaration.setScope(scope);
}
if(fPackage != environment.defaultPackage) {
fPackage.addBinding(referenceContext.compilationUnitBinding, referenceContext.getMainTypeName(),
Binding.COMPILATION_UNIT);
}
methodDeclaration.bindArguments();
}
return false;
}
}
public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
super(COMPILATION_UNIT_SCOPE, null);
this.environment = environment;
this.referenceContext = unit;
unit.scope = this;
char[][] pkgName =
unit.currentPackage == null ? (unit.compilationResult != null ? unit.compilationResult.getPackageName()
: null) : unit.currentPackage.tokens;
this.currentPackageName = pkgName == null ? CharOperation.NO_CHAR_CHAR : pkgName;
this.referencedTypes = new ObjectVector();
if(compilerOptions().produceReferenceInfo) {
this.qualifiedReferences = new CompoundNameVector();
this.simpleNameReferences = new SimpleNameVector();
this.referencedSuperTypes = new ObjectVector();
} else {
this.qualifiedReferences = null; // used to test if dependencies should be recorded
this.simpleNameReferences = null;
this.referencedSuperTypes = null;
}
this.fBuildingSuperBinding = false;
}
protected CompilationUnitScope(LookupEnvironment environment) {
super(COMPILATION_UNIT_SCOPE, null);
this.environment = environment;
this.referencedTypes = new ObjectVector();
if(compilerOptions().produceReferenceInfo) {
this.qualifiedReferences = new CompoundNameVector();
this.simpleNameReferences = new SimpleNameVector();
this.referencedSuperTypes = new ObjectVector();
} else {
this.qualifiedReferences = null; // used to test if dependencies should be recorded
this.simpleNameReferences = null;
this.referencedSuperTypes = null;
}
this.fBuildingSuperBinding = false;
}
public ClassScope classScope() {
if(this.classScope != null)
return this.classScope;
return super.classScope();
}
void buildFieldsAndMethods() {
for(int i = 0, length = topLevelTypes.length; i < length; i++) {
if(topLevelTypes[i] != null) {
topLevelTypes[i].buildFieldsAndMethods();
}
}
}
void buildTypeBindings(AccessRestriction accessRestriction) {
buildTypeBindings(CharOperation.NO_CHAR_CHAR, accessRestriction);
}
void buildTypeBindings(char[][] restrictToNames, AccessRestriction accessRestriction) {
existingTopLevelTypes = topLevelTypes;
topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be
// resolved
if(referenceContext.compilationResult.compilationUnit != null) {
char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName();
if(expectedPackageName != null && !CharOperation.equals(currentPackageName, expectedPackageName)) {
currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName;
}
}
if(currentPackageName == CharOperation.NO_CHAR_CHAR) {
fPackage = environment.defaultPackage;
} else {
fPackage = environment.createPackage(currentPackageName);
}
this.faultInImports();
// Skip typeDeclarations which know of previously reported errors
int typeLength = referenceContext.numberInferredTypes;
List newlyBuiltTypes = new ArrayList();
SimpleSetOfCharArray addTypes = new SimpleSetOfCharArray(10);
boolean shouldTraverse = true;
String fileName = new String(this.referenceContext.getFileName());
// do an initial pass through the types to be built and add their super types to the list, so they get
// built in the event they are anonymous.
for(int i = 0; i < typeLength; i++) {
InferredType typeDecl = referenceContext.inferredTypes[i];
if(typeDecl.isDefinition()) {
if (restrictToNames != null && restrictToNames.length > 0) {
boolean continueBuilding = false;
for(int j = 0; !continueBuilding && j < restrictToNames.length; j++) {
if(CharOperation.equals(typeDecl.getName(), restrictToNames[j]))
continueBuilding = true;
}
if(continueBuilding && typeDecl.getSuperType() != null && !typeDecl.getSuperType().isIndexed()) {
System.arraycopy(restrictToNames, 0, restrictToNames = new char[restrictToNames.length + 1][], 0, restrictToNames.length - 1);
restrictToNames[restrictToNames.length - 1] = typeDecl.getSuperClassName();
}
}
}
}
nextType: for(int i = 0; i < typeLength; i++) {
InferredType typeDecl = referenceContext.inferredTypes[i];
if(typeDecl.isDefinition()) {
if (restrictToNames != null && restrictToNames.length > 0) {
boolean continueBuilding = false;
for(int j = 0; !continueBuilding && j < restrictToNames.length; j++) {
if(CharOperation.equals(typeDecl.getName(), restrictToNames[j]))
continueBuilding = true;
}
if(!continueBuilding)
continue nextType;
}
ReferenceBinding typeBinding = null;
// check that the type is not already built
if(existingTopLevelTypes != null && restrictToNames != null && restrictToNames.length > 0) {
for(int j = 0; j < existingTopLevelTypes.length; j++) {
/* use #sourceName here because it does not check through all the linked types
* for SourceTypeBindings, which in this case we do not want to do because it is
* not needed and is a performance drag */
if(existingTopLevelTypes[j] != null && CharOperation.equals(typeDecl.getName(), existingTopLevelTypes[j].sourceName())) {
typeBinding = environment.defaultPackage.getType0(typeDecl.getName());
if(typeBinding == null) {
environment.defaultPackage.addType(existingTopLevelTypes[j]);
fPackage.addType(existingTopLevelTypes[j]);
}
shouldTraverse = false;
continue nextType;
}
}
}
shouldTraverse = false;
// build the type and its synonyms
SourceTypeBinding originalSourceType = null;
int numberOfTypesToBuild = 1 + (referenceContext.inferredTypes[i].getSynonyms() == null ? 0 : referenceContext.inferredTypes[i].getSynonyms().length);
for (int j = 0; j < numberOfTypesToBuild; j++) {
if (j > 0) {
// main type has been built, now build associated synonyms
typeDecl = referenceContext.inferredTypes[i].getSynonyms()[j - 1];
if(typeDecl.binding != null)
break;
}
typeBinding = environment.defaultPackage.getType0(typeDecl.getName());
recordSimpleReference(typeDecl.getName()); // needed to detect collision cases
SourceTypeBinding existingBinding = null;
if(typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) {
/* if a type exists, it must be a valid type - cannot
* be a NotFound problem type unless it's an unresolved
* type which is now being defined
*/
if(typeBinding instanceof SourceTypeBinding) {
existingBinding = (SourceTypeBinding) typeBinding;
}
}
ClassScope child = new ClassScope(this, typeDecl);
SourceTypeBinding type = child.buildInferredType(null, environment.defaultPackage, accessRestriction);
if(type != null) {
if (j == 0) {
originalSourceType = type;
}
if (existingBinding != null && typeDecl.isIndexed()) {
existingBinding.addLinkedBinding(type);
environment.defaultPackage.addType(existingBinding);
fPackage.addType(existingBinding);
}
else if(typeDecl.isIndexed()) {
addTypes.add(typeDecl.getName());
}
// set the original type as a nextType on this synonym
if (j > 0 && originalSourceType != null) {
type.addLinkedBinding(originalSourceType);
}
newlyBuiltTypes.add(type);
}
}
}
}
/* shrink topLevelTypes...
* happens if error reported or if only building restricted type names */
int count = newlyBuiltTypes.size();
topLevelTypes = (SourceTypeBinding[]) newlyBuiltTypes.toArray(new SourceTypeBinding[count]);
if(existingTopLevelTypes != null && restrictToNames != null && restrictToNames.length > 0) {
System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count + existingTopLevelTypes.length], 0, count);
System.arraycopy(existingTopLevelTypes, 0, topLevelTypes, count, existingTopLevelTypes.length);
existingTopLevelTypes = null;
}
/* set up context, needs to be done before super type can be built
* since building super type may refer back to this contexts binding */
char[] path = CharOperation.concatWith(this.currentPackageName, '/');
if(referenceContext.compilationUnitBinding == null) {
referenceContext.compilationUnitBinding =
new CompilationUnitBinding(this, environment.defaultPackage, path);
if(fPackage != environment.defaultPackage)
fPackage.addBinding(referenceContext.compilationUnitBinding, referenceContext.getMainTypeName(),
Binding.COMPILATION_UNIT);
}
// build the super type
if(shouldBuildGlobalSuperType())
buildSuperType();
//set the super type on the binding
this.referenceContext.compilationUnitBinding.setSuperBinding(this.superBinding);
//add new type bindings
char[][] typeNames = new char[addTypes.elementSize][];
addTypes.asArray(typeNames);
environment.addUnitsContainingBindings(typeNames, Binding.TYPE, fileName);
// connect synonymous types, now that their synonyms should have bindings
for (int i = 0; i < typeLength; i++) {
char[] inferredTypeName = referenceContext.inferredTypes[i].getName();
//determine if the inferredTypeName is in the restrict to list
boolean isResctrictToName = true;
if (restrictToNames != null && restrictToNames.length > 0) {
isResctrictToName = false;
for(int j = 0; !isResctrictToName && j < restrictToNames.length; j++) {
isResctrictToName = CharOperation.equals(inferredTypeName, restrictToNames[j]);
}
}
//if inferred type is on restricted list and any linked synonyms
if (isResctrictToName && referenceContext.inferredTypes[i].getSynonyms() != null) {
ReferenceBinding binding = environment.defaultPackage.getType0(inferredTypeName);
if (binding != null && binding instanceof SourceTypeBinding) {
for (int j = 0; j < referenceContext.inferredTypes[i].getSynonyms().length; j++) {
ReferenceBinding synonymBinding = environment.defaultPackage.getType0(referenceContext.inferredTypes[i].getSynonyms()[j].getName());
if (synonymBinding != null && synonymBinding instanceof SourceTypeBinding) {
((SourceTypeBinding) binding).addLinkedBinding((SourceTypeBinding) synonymBinding);
}
}
}
}
}
if((restrictToNames == null || restrictToNames.length == 0) || shouldTraverse) {
if(referenceContext.compilationUnitBinding.methods == Binding.NO_METHODS) {
DeclarationVisitor visitor = new DeclarationVisitor();
this.referenceContext.traverse(visitor, this);
MethodBinding[] methods =
(MethodBinding[]) visitor.methods.toArray(new MethodBinding[visitor.methods.size()]);
referenceContext.compilationUnitBinding.setMethods(methods);
}
}
}
/**
* <p>
* Builds the super type for this scope. This also includes adding the
* "global" type to the global type type hierarchy.
* </p>
* <p>
* If the super type has already been built then this is a no-op.
* </p>
*/
public void buildSuperType() {
//be sure to only build the super once and not allow an infinite loop of building to occur
synchronized (this.fBuidingSuperBindingLock) {
if(this.fBuildingSuperBinding || this.superBinding != null) {
return;
} else {
this.fBuildingSuperBinding = true;
}
}
try {
char[] superTypeName = null;
LibrarySuperType libSuperType = null;
if(this.referenceContext.compilationResult!=null && this.referenceContext.compilationResult.compilationUnit!=null) {
libSuperType = this.referenceContext.compilationResult.compilationUnit.getCommonSuperType();
if(libSuperType==null) {
return;
} else {
superTypeName = libSuperType.getSuperTypeName().toCharArray();
}
}
if (superTypeName==null) {
return;
}
this.superBinding = findType(superTypeName, environment.defaultPackage, environment.defaultPackage);
if(this.superBinding==null || !this.superBinding.isValidBinding()) {
superTypeName = null;
return ;
}
/* If super type is combined source type, search through SourceTypes for the specific instance */
if( (this.superBinding instanceof SourceTypeBinding)) {
this.classScope = ((SourceTypeBinding)this.superBinding).classScope;
} else if(this.superBinding!=null) {
InferredType te = this.superBinding.getInferredType();
this.classScope = new ClassScope(this, te);
}
if(this.superBinding != null && this.classScope != null) {
SourceTypeBinding sourceType = null;
if(this.superBinding instanceof SourceTypeBinding) {
sourceType = (SourceTypeBinding)this.superBinding;
}
this.classScope.buildInferredType(sourceType, this.environment.defaultPackage, null);
//if there is a searchable environment then merge global fields with fields on super binding
if(this.environment().nameEnvironment instanceof SearchableEnvironment) {
//find all of the global fields from the index
SearchableEnvironment env = (SearchableEnvironment)this.environment().nameEnvironment;
final HashtableOfObject globalFields = new HashtableOfObject();
env.findVariables(null, new char[][]{IIndexConstants.GLOBAL_SYMBOL}, false, new ISearchRequestor() {
public void acceptVariable(char[] signature, char[] typeQualification, char[] typeSimpleName, char[] declaringQualification, char[] declaringSimpleName, int modifiers, String path) {
//store global field and its type name
globalFields.put(signature, QualificationHelpers.createFullyQualifiedName(typeQualification, typeSimpleName));
}
public void acceptType(char[] packageName, char[] fileName, char[] typeName, char[][] enclosingTypeNames, int modifiers, AccessRestriction accessRestriction) {
//ignore
}
public void acceptPackage(char[] packageName) {
//ignore
}
public void acceptFunction(char[] signature, char[][] parameterFullyQualifedTypeNames, char[][] parameterNames, char[] returnQualification, char[] returnSimpleName, char[] declaringQualification, char[] declaringSimpleName, int modifiers, String path) {
//ignore
}
public void acceptConstructor(int modifiers, char[] typeName, char[][] parameterTypes, char[][] parameterNames, String path, AccessRestriction access) {
//ignore
}
public void acceptBinding(char[] packageName, char[] fileName, char[] bindingName, int bindingType, int modifiers, AccessRestriction accessRestriction) {
//ignore
}
});
//merge the global fields with the super binding fields
mergeWithSuperBinding(globalFields);
}
recordTypeReference(this.superBinding);
recordSuperTypeReference(this.superBinding);
environment().setAccessRestriction(this.superBinding, null);
}
//check to see if the special "global" type was created in this scope, if so make it the super binding
if(this.topLevelTypes != null) {
TypeBinding globalType = null;
for(int i = 0; i < this.topLevelTypes.length && globalType == null; ++i) {
if(this.topLevelTypes[i] != null && CharOperation.equals(this.topLevelTypes[i].sourceName,IIndexConstants.GLOBAL_SYMBOL)) {
globalType = this.topLevelTypes[i];
}
}
if(globalType instanceof ReferenceBinding) {
if(this.superBinding == null) {
this.superBinding = (ReferenceBinding)globalType;
} else if (this.superBinding instanceof SourceTypeBinding) {
ReferenceBinding currentSuper = this.superBinding;
ReferenceBinding previousSuper = this.superBinding;
/* need to find the type with no super type or with Object as its super type,
* so that the "fake" Global object can be injected in there */
while(currentSuper != null && !CharOperation.equals(currentSuper.sourceName, IIndexConstants.OBJECT)) {
previousSuper = currentSuper;
if(currentSuper instanceof SourceTypeBinding) {
currentSuper = ((SourceTypeBinding)currentSuper).getSuperBinding0();
}
else {
break;
}
}
// if we found the null class just add the global object
if(currentSuper == null) {
if(!CharOperation.equals(previousSuper.sourceName, globalType.sourceName())) {
((SourceTypeBinding)previousSuper).setSuperBinding((ReferenceBinding)globalType);
}
}
else if(CharOperation.equals(currentSuper.sourceName, IIndexConstants.OBJECT)){
// if we found the object case, set object as the parent of global first
((SourceTypeBinding)globalType).setSuperBinding(currentSuper);
if(!CharOperation.equals(previousSuper.sourceName, globalType.sourceName())) {
((SourceTypeBinding)previousSuper).setSuperBinding((ReferenceBinding)globalType);
}
}
}
}
}
} finally {
//finished building super
synchronized (this.fBuidingSuperBindingLock) {
this.fBuildingSuperBinding = false;
}
}
}
/**
* <p>
* Merges the table of global field names to their types with the fields of the super binding.
* </p>
*
* @param globalFields table of global field names to their types to merge with the fields of
* the super binding
*/
private void mergeWithSuperBinding(HashtableOfObject globalFields) {
//list of the super fields to iterate through
List superBindingFields = new ArrayList();
superBindingFields.addAll(Arrays.asList(this.superBinding.fields()));
//set of the super field names so that duplicates do not get added to the list
SimpleSetOfCharArray superBindingFieldsNames = new SimpleSetOfCharArray(superBindingFields.size());
for(int i = 0; i < superBindingFields.size(); ++i) {
superBindingFieldsNames.add(((FieldBinding)superBindingFields.get(i)).name);
}
/* for each super binding field check if there is an existing global
* field with the same name to merge it with */
for(int superBindingFieldIndex = 0;
superBindingFieldIndex < superBindingFields.size();
++superBindingFieldIndex) {
FieldBinding superBindingField = (FieldBinding)superBindingFields.get(superBindingFieldIndex);
//check if there is an existing global field with the same name as the super type field
char[] globalFieldType = (char[])globalFields.get(superBindingField.name);
/* if no global field then guess that their might be an anonymous
* global type for the super binding.
*
* IE:
* navigator.foo = 42
*
* This creates a global anonymous type for navigator but does not
* add it to the global type for performance reasons. */
if(globalFieldType == null || globalFieldType.length == 0) {
globalFieldType = InferEngine.createAnonymousGlobalTypeName(superBindingField.name);
}
/* if the type for the global field can be found and is valid then
* merge it with the super binding field */
ReferenceBinding globalFieldBinding = this.findType(globalFieldType,
this.getCurrentPackage(), this.getCurrentPackage());
if(globalFieldBinding != null &&
globalFieldBinding instanceof SourceTypeBinding &&
globalFieldBinding.isValidBinding() &&
!globalFieldBinding.isAnyType()) {
/* if the type of the super binding field is the same as the super binding
* then the fields of the super binding field should also be considered
* super binding fields
*
* IE: there is a field on the Window type named window that has a
* type of Window. Thus any fields of the window field also need to be
* merged with the super binding (this example is assuming window is the super
* type) */
if(superBindingField.type != null && superBindingField.type.isEquivalentTo(this.superBinding)) {
FieldBinding[] fieldsOnGlobalField = globalFieldBinding.fields();
for(int fieldsOnGlobalFieldIndex = 0;
fieldsOnGlobalFieldIndex < fieldsOnGlobalField.length;
++fieldsOnGlobalFieldIndex) {
//only add if field with name that is not already added
if(!superBindingFieldsNames.includes(fieldsOnGlobalField[fieldsOnGlobalFieldIndex].name)) {
superBindingFields.add(fieldsOnGlobalField[fieldsOnGlobalFieldIndex]);
superBindingFieldsNames.add(fieldsOnGlobalField[fieldsOnGlobalFieldIndex].name);
}
}
}
/* if the super field type is a SourceTypeBinding then link it with that of the global field
* else if the super field does not have a type or is the any type set it to be the type
* of the global field */
if(superBindingField.type != null && superBindingField.type instanceof SourceTypeBinding) {
((SourceTypeBinding)superBindingField.type).addLinkedBinding((SourceTypeBinding)globalFieldBinding);
} else if(superBindingField.type == null || superBindingField.type.isAnyType() ){
superBindingField.type = globalFieldBinding;
}
}
}
}
SourceTypeBinding buildType(InferredType inferredType, SourceTypeBinding enclosingType,
PackageBinding packageBinding, AccessRestriction accessRestriction) {
// provide the typeDeclaration with needed scopes
if(enclosingType == null) {
char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, inferredType.getName());
inferredType.binding = new SourceTypeBinding(className, packageBinding, this);
// @GINO: Anonymous set bits
if(!inferredType.isNamed())
inferredType.binding.tagBits |= TagBits.AnonymousTypeMask;
}
SourceTypeBinding sourceType = inferredType.binding;
environment().setAccessRestriction(sourceType, accessRestriction);
environment().defaultPackage.addType(sourceType);
sourceType.fPackage.addType(sourceType);
return sourceType;
}
public PackageBinding getDefaultPackage() {
return environment.defaultPackage;
}
public void addLocalVariable(LocalVariableBinding binding) {
super.addLocalVariable(binding);
environment.defaultPackage.addBinding(binding, binding.name, Binding.VARIABLE);
fPackage.addBinding(binding, binding.name, Binding.VARIABLE);
}
void checkAndSetImports() {
if(referenceContext.imports == null) {
imports = getDefaultImports();
return;
}
// allocate the import array, add java.lang.* by default
int numberOfStatements = referenceContext.imports.length;
int numberOfImports = numberOfStatements + 1;
for(int i = 0; i < numberOfStatements; i++) {
ImportReference importReference = referenceContext.imports[i];
if(((importReference.bits & ASTNode.OnDemand) != 0)
&& CharOperation.equals(JAVA_LANG, importReference.tokens)) {
numberOfImports--;
break;
}
}
ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
resolvedImports[0] = getDefaultImports()[0];
int index = 1;
nextImport: for(int i = 0; i < numberOfStatements; i++) {
ImportReference importReference = referenceContext.imports[i];
char[][] compoundName = importReference.tokens;
// skip duplicates or imports of the current package
for(int j = 0; j < index; j++) {
ImportBinding resolved = resolvedImports[j];
if(resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0))
if(CharOperation.equals(compoundName, resolvedImports[j].compoundName))
continue nextImport;
}
if((importReference.bits & ASTNode.OnDemand) != 0) {
if(CharOperation.equals(compoundName, currentPackageName))
continue nextImport;
Binding importBinding = findImport(compoundName, compoundName.length);
if(!importBinding.isValidBinding())
continue nextImport; // we report all problems in faultInImports()
resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference);
} else {
// resolve single imports only when the last name matches
resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference);
}
}
// shrink resolvedImports... only happens if an error was reported
if(resolvedImports.length > index)
System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
imports = resolvedImports;
}
/* INTERNAL USE-ONLY
* Innerclasses get their name computed as they are generated, since some may not
* be actually outputed if sitting inside unreachable code. */
public char[] computeConstantPoolName(LocalTypeBinding localType) {
if(localType.constantPoolName() != null) {
return localType.constantPoolName();
}
// delegates to the outermost enclosing classfile, since it is the only one with a global
// vision of its innertypes.
if(constantPoolNameUsage == null)
constantPoolNameUsage = new HashtableOfType();
ReferenceBinding outerMostEnclosingType = localType.scope.outerMostClassScope().enclosingSourceType();
// ensure there is not already such a local type name defined by the user
int index = 0;
char[] candidateName;
boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5;
while(true) {
if(localType.isMemberType()) {
if(index == 0) {
candidateName =
CharOperation.concat(localType.enclosingType().constantPoolName(), localType.sourceName,
'.');
} else {
// in case of collision, then member name gets extra $1 inserted
// e.g. class X { { class L{} new X(){ class L{} } } }
candidateName =
CharOperation.concat(localType.enclosingType().constantPoolName(), '.', String.valueOf(
index).toCharArray(), '.', localType.sourceName);
}
} else if(localType.isAnonymousType()) {
if(isCompliant15) {
// from 1.5 on, use immediately enclosing type name
candidateName =
CharOperation.concat(localType.enclosingType.constantPoolName(),
String.valueOf(index + 1).toCharArray(), '.');
} else {
candidateName =
CharOperation.concat(outerMostEnclosingType.constantPoolName(),
String.valueOf(index + 1).toCharArray(), '.');
}
} else {
// local type
if(isCompliant15) {
candidateName =
CharOperation.concat(CharOperation.concat(localType.enclosingType().constantPoolName(),
String.valueOf(index + 1).toCharArray(), '.'), localType.sourceName);
} else {
candidateName =
CharOperation.concat(outerMostEnclosingType.constantPoolName(), '.', String.valueOf(
index + 1).toCharArray(), '.', localType.sourceName);
}
}
if(constantPoolNameUsage.get(candidateName) != null) {
index++;
} else {
constantPoolNameUsage.put(candidateName, localType);
break;
}
}
return candidateName;
}
void connectTypeHierarchy(char[][] typeNames) {
if(classScope != null) {
classScope.connectTypeHierarchy();
}
nextType: for(int i = 0; i < referenceContext.numberInferredTypes; i++) {
InferredType inferredType = referenceContext.inferredTypes[i];
if(typeNames.length > 0) {
boolean continueBuilding = false;
for(int j = 0; !continueBuilding && j < typeNames.length; j++) {
if(CharOperation.equals(inferredType.getName(), typeNames[j]))
continueBuilding = true;
}
if(!continueBuilding)
continue nextType;
}
if(inferredType.binding != null && inferredType.binding.classScope != null) {
inferredType.binding.classScope.connectTypeHierarchy();
}
}
}
void connectTypeHierarchy() {
connectTypeHierarchy(CharOperation.NO_CHAR_CHAR);
}
void faultInImports() {
if(this.typeOrPackageCache != null)
return; // can be called when a field constant is resolved before static imports
if(referenceContext.imports == null) {
this.typeOrPackageCache = new HashtableOfObject(1);
return;
}
// collect the top level type names if a single type import exists
int numberOfStatements = referenceContext.imports.length;
HashtableOfType typesBySimpleNames = null;
for(int i = 0; i < numberOfStatements; i++) {
if((referenceContext.imports[i].bits & ASTNode.OnDemand) == 0) {
typesBySimpleNames = new HashtableOfType(topLevelTypes.length + numberOfStatements);
for(int j = 0, length = topLevelTypes.length; j < length; j++)
typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]);
break;
}
}
// allocate the import array, add java.lang.* by default
ImportBinding[] defaultImports = getDefaultImports();
int numberOfImports = numberOfStatements + defaultImports.length;
for(int i = 0; i < numberOfStatements; i++) {
ImportReference importReference = referenceContext.imports[i];
if(((importReference.bits & ASTNode.OnDemand) != 0)
&& CharOperation.equals(JAVA_LANG, importReference.tokens)) {
numberOfImports--;
break;
}
}
ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
System.arraycopy(defaultImports, 0, resolvedImports, 0, defaultImports.length);
int index = defaultImports.length;
// keep static imports with normal imports until there is a reason to split them up
// on demand imports continue to be packages & types. need to check on demand type imports
// for fields/methods
// single imports change from being just types to types or fields
nextImport: for(int i = 0; i < numberOfStatements; i++) {
ImportReference importReference = referenceContext.imports[i];
char[][] compoundName = importReference.tokens;
// skip duplicates or imports of the current package
for(int j = 0; j < index; j++) {
ImportBinding resolved = resolvedImports[j];
if(resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)) {
if(CharOperation.equals(compoundName, resolved.compoundName)) {
continue nextImport;
}
}
}
if((importReference.bits & ASTNode.OnDemand) != 0) {
if(CharOperation.equals(compoundName, currentPackageName)) {
continue nextImport;
}
Binding importBinding = findImport(compoundName, compoundName.length);
if(!importBinding.isValidBinding()) {
continue nextImport;
}
resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference);
} else {
Binding importBinding = findSingleImport(compoundName);
if(!importBinding.isValidBinding()) {
continue nextImport;
}
ReferenceBinding conflictingType = null;
if(importBinding instanceof MethodBinding) {
conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length);
if(!conflictingType.isValidBinding())
conflictingType = null;
}
// collisions between an imported static field & a type should be checked according
// to spec... but currently not by javac
if(importBinding instanceof ReferenceBinding || conflictingType != null) {
ReferenceBinding referenceBinding =
conflictingType == null ? (ReferenceBinding) importBinding : conflictingType;
if(importReference.isTypeUseDeprecated(referenceBinding, this))
problemReporter().deprecatedType(referenceBinding, importReference);
ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]);
if(existingType != null) {
continue nextImport;
}
typesBySimpleNames.put(compoundName[compoundName.length - 1], referenceBinding);
}
resolvedImports[index++] =
conflictingType == null ? new ImportBinding(compoundName, false, importBinding, importReference)
: new ImportConflictBinding(compoundName, importBinding, conflictingType,
importReference);
}
}
// shrink resolvedImports... only happens if an error was reported
if(resolvedImports.length > index)
System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
imports = resolvedImports;
int length = imports.length;
this.typeOrPackageCache = new HashtableOfObject(length);
for(int i = 0; i < length; i++) {
ImportBinding binding = imports[i];
if(!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding
|| binding instanceof ImportConflictBinding)
this.typeOrPackageCache.put(binding.compoundName[binding.compoundName.length - 1], binding);
}
}
public void faultInTypes() {
faultInImports();
this.referenceContext.compilationUnitBinding.faultInTypesForFieldsAndMethods();
for(int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].faultInTypesForFieldsAndMethods();
}
/**
* this API is for code assist purpose
*
* @param compoundName
* @param onDemand
* @return
*/
public Binding findImport(char[][] compoundName, boolean onDemand) {
if(onDemand) {
return findImport(compoundName, compoundName.length);
} else {
return findSingleImport(compoundName);
}
}
private Binding findImport(char[][] compoundName, int length) {
recordQualifiedReference(compoundName);
Binding binding = environment.getTopLevelPackage(compoundName[0]);
int i = 1;
foundNothingOrType: if(binding != null) {
PackageBinding packageBinding = (PackageBinding) binding;
while(i < length) {
int type = (i + 1 == length) ? Binding.COMPILATION_UNIT : Binding.PACKAGE;
binding = packageBinding.getTypeOrPackage(compoundName[i++], type);
if(binding == null || !binding.isValidBinding()) {
binding = null;
break foundNothingOrType;
}
if(i == length && (binding instanceof CompilationUnitBinding))
return binding;
if(!(binding instanceof PackageBinding))
break foundNothingOrType;
packageBinding = (PackageBinding) binding;
}
return packageBinding;
}
ReferenceBinding type;
if(binding == null) {
if(environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null,
ProblemReasons.NotFound);
type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage);
if(type == null || !type.isValidBinding())
return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null,
ProblemReasons.NotFound);
i = 1; // reset to look for member types inside the default package type
} else {
type = (ReferenceBinding) binding;
}
while(i < length) {
if(!type.canBeSeenBy(environment.defaultPackage))
return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type,
ProblemReasons.NotVisible);
char[] name = compoundName[i++];
// does not look for inherited member types on purpose, only immediate members
type = type.getMemberType(name);
if(type == null)
return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null,
ProblemReasons.NotFound);
}
if(!type.canBeSeenBy(environment.defaultPackage))
return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible);
return type;
}
private Binding findSingleImport(char[][] compoundName) {
if(compoundName.length == 1) {
// findType records the reference
// the name cannot be a package
if(environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
return new ProblemReferenceBinding(compoundName, null, ProblemReasons.NotFound);
ReferenceBinding typeBinding =
findType(compoundName[0], environment.defaultPackage, environment.defaultPackage);
if(typeBinding == null)
return new ProblemReferenceBinding(compoundName, null, ProblemReasons.NotFound);
return typeBinding;
}
return findImport(compoundName, compoundName.length);
}
MethodBinding findStaticMethod(ReferenceBinding currentType, char[] selector) {
if(!currentType.canBeSeenBy(this))
return null;
do {
MethodBinding[] methods = currentType.getMethods(selector);
if(methods != Binding.NO_METHODS) {
for(int i = methods.length; --i >= 0;) {
MethodBinding method = methods[i];
if(method.isStatic() && method.canBeSeenBy(environment.defaultPackage))
return method;
}
}
((SourceTypeBinding) currentType).classScope.connectTypeHierarchy();
} while((currentType = currentType.getSuperBinding()) != null);
return null;
}
ImportBinding[] getDefaultImports() {
// initialize the default imports if necessary... share the default java.lang.* import
Binding importBinding = environment.defaultPackage;
// abort if java.lang cannot be found...
if(importBinding == null || !importBinding.isValidBinding()) {
// create a proxy for the missing BinaryType
MissingBinaryTypeBinding missingObject =
environment.cacheMissingBinaryType(JAVA_LANG_OBJECT, this.referenceContext);
importBinding = missingObject.fPackage;
}
ImportBinding systemJSBinding = null;
if(environment.defaultImports != null) {
systemJSBinding = environment.defaultImports[0];
} else {
systemJSBinding =
new ImportBinding(new char[][] { SystemLibraryLocation.SYSTEM_LIBARAY_NAME }, true, importBinding,
(ImportReference) null);
environment.defaultImports = new ImportBinding[] { systemJSBinding };
}
ImportBinding[] defaultImports = null;
String[] contextIncludes = null;
InferrenceProvider[] inferenceProviders =
InferrenceManager.getInstance().getInferenceProviders(this.referenceContext);
if(inferenceProviders != null && inferenceProviders.length > 0) {
for(int i = 0; i < inferenceProviders.length; i++) {
if(contextIncludes == null) {
contextIncludes = inferenceProviders[i].getResolutionConfiguration().getContextIncludes();
} else {
String[] contextIncludesTemp =
inferenceProviders[0].getResolutionConfiguration().getContextIncludes();
if(contextIncludesTemp != null) {
String[] contextIncludesOld = contextIncludes;
contextIncludes = new String[contextIncludesTemp.length + contextIncludesOld.length];
System.arraycopy(contextIncludesOld, 0, contextIncludes, 0, contextIncludesOld.length);
System.arraycopy(contextIncludesTemp, 0, contextIncludes, contextIncludesOld.length - 1,
contextIncludesTemp.length);
}
}
}
}
if(contextIncludes != null && contextIncludes.length > 0) {
ArrayList list = new ArrayList();
list.add(systemJSBinding);
for(int i = 0; i < contextIncludes.length; i++) {
String include = contextIncludes[i];
if(include != null) {
int index = Util.indexOfJavaLikeExtension(include);
if(index >= 0)
include = include.substring(0, index);
include = include.replace('.', FILENAME_DOT_SUBSTITUTION);
char[][] qualifiedName = CharOperation.splitOn('/', include.toCharArray());
Binding binding = findImport(qualifiedName, qualifiedName.length);
if(binding.isValidBinding()) {
list.add(new ImportBinding(qualifiedName, true, binding, null));
}
}
}
defaultImports = (ImportBinding[]) list.toArray(new ImportBinding[list.size()]);
} else
defaultImports = new ImportBinding[] { systemJSBinding };
return defaultImports;
}
/**
* <p><b>NOTE:</b> NOT Public API</p>
*
* @param compoundName
* @param onDemand
* @return
*/
public final Binding getImport(char[][] compoundName, boolean onDemand) {
if(onDemand)
return findImport(compoundName, compoundName.length);
return findSingleImport(compoundName);
}
public int nextCaptureID() {
return this.captureID++;
}
/**
* Answer the problem reporter to use for raising new problems.
*
* Note that as a side-effect, this updates the current reference context
* (unit, type or method) in case the problem handler decides it is necessary
* to abort.
*/
public ProblemReporter problemReporter() {
ProblemReporter problemReporter = referenceContext.problemReporter;
problemReporter.referenceContext = referenceContext;
return problemReporter;
}
/**
* What do we hold onto:
*
* 1. when we resolve 'a.b.c', say we keep only 'a.b.c'
* & when we fail to resolve 'c' in 'a.b', lets keep 'a.b.c'
* THEN when we come across a new/changed/removed item named 'a.b.c',
* we would find all references to 'a.b.c'
* -> This approach fails because every type is resolved in every onDemand import to
* detect collision cases... so the references could be 10 times bigger than necessary.
*
* 2. when we resolve 'a.b.c', lets keep 'a.b' & 'c'
* & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'c'
* THEN when we come across a new/changed/removed item named 'a.b.c',
* we would find all references to 'a.b' & 'c'
* -> This approach does not have a space problem but fails to handle collision cases.
* What happens if a type is added named 'a.b'? We would search for 'a' & 'b' but
* would not find a match.
*
* 3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c'
* & when we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c'
* THEN when we come across a new/changed/removed item named 'a.b.c',
* we would find all references to 'a.b' & 'c'
* OR 'a.b' -> 'a' & 'b'
* OR 'a' -> '' & 'a'
* -> As long as each single char[] is interned, we should not have a space problem
* and can handle collision cases.
*
* 4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c'
* & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c'
* THEN when we come across a new/changed/removed item named 'a.b.c',
* we would find all references to 'a.b' & 'c'
* OR 'a.b' -> 'a' & 'b' in the simple name collection
* OR 'a' -> 'a' in the simple name collection
* -> As long as each single char[] is interned, we should not have a space problem
* and can handle collision cases.
*/
void recordQualifiedReference(char[][] qualifiedName) {
if(qualifiedReferences == null)
return; // not recording dependencies
int length = qualifiedName.length;
if(length > 1) {
while(!qualifiedReferences.contains(qualifiedName)) {
qualifiedReferences.add(qualifiedName);
if(length == 2) {
recordSimpleReference(qualifiedName[0]);
recordSimpleReference(qualifiedName[1]);
return;
}
length--;
recordSimpleReference(qualifiedName[length]);
System.arraycopy(qualifiedName, 0, qualifiedName = new char[length][], 0, length);
}
} else if(length == 1) {
recordSimpleReference(qualifiedName[0]);
}
}
void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) {
recordQualifiedReference(qualifiedEnclosingName);
recordSimpleReference(simpleName);
}
void recordReference(ReferenceBinding type, char[] simpleName) {
ReferenceBinding actualType = typeToRecord(type);
if(actualType != null)
recordReference(actualType.compoundName, simpleName);
}
void recordSimpleReference(char[] simpleName) {
if(simpleNameReferences == null)
return; // not recording dependencies
if(!simpleNameReferences.contains(simpleName))
simpleNameReferences.add(simpleName);
}
void recordSuperTypeReference(TypeBinding type) {
if(referencedSuperTypes == null)
return; // not recording dependencies
ReferenceBinding actualType = typeToRecord(type);
if(actualType != null && !referencedSuperTypes.containsIdentical(actualType))
referencedSuperTypes.add(actualType);
}
public void recordTypeConversion(TypeBinding superType, TypeBinding subType) {
// must record the hierarchy of the subType that is converted to the superType
recordSuperTypeReference(subType);
}
void recordTypeReference(TypeBinding type) {
if(referencedTypes == null)
return; // not recording dependencies
ReferenceBinding actualType = typeToRecord(type);
if(actualType != null && !referencedTypes.containsIdentical(actualType))
referencedTypes.add(actualType);
}
void recordTypeReferences(TypeBinding[] types) {
if(referencedTypes == null)
return; // not recording dependencies
if(types == null || types.length == 0)
return;
for(int i = 0, max = types.length; i < max; i++) {
// No need to record supertypes of method arguments & thrown exceptions, just the
// compoundName
// If a field/method is retrieved from such a type then a separate call does the job
ReferenceBinding actualType = null;
if(types[i] != null)
actualType = typeToRecord(types[i]);
if(actualType != null && !referencedTypes.containsIdentical(actualType))
referencedTypes.add(actualType);
}
}
Binding resolveSingleImport(ImportBinding importBinding) {
if(importBinding.resolvedImport == null) {
importBinding.resolvedImport = findSingleImport(importBinding.compoundName);
if(!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) {
if(this.imports != null) {
ImportBinding[] newImports = new ImportBinding[imports.length - 1];
for(int i = 0, n = 0, max = this.imports.length; i < max; i++)
if(this.imports[i] != importBinding)
newImports[n++] = this.imports[i];
this.imports = newImports;
}
return null;
}
}
return importBinding.resolvedImport;
}
public void storeDependencyInfo() {
// add the type hierarchy of each referenced supertype
// cannot do early since the hierarchy may not be fully resolved
for(int i = 0; i < referencedSuperTypes.size; i++) { // grows as more types are added
ReferenceBinding type = (ReferenceBinding) referencedSuperTypes.elementAt(i);
if(!referencedTypes.containsIdentical(type))
referencedTypes.add(type);
if(!type.isLocalType()) {
ReferenceBinding enclosing = type.enclosingType();
if(enclosing != null)
recordSuperTypeReference(enclosing);
}
ReferenceBinding superclass = type.getSuperBinding();
if(superclass != null)
recordSuperTypeReference(superclass);
}
for(int i = 0, l = referencedTypes.size; i < l; i++) {
ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i);
if(type instanceof MultipleTypeBinding) {
ReferenceBinding[] types = ((MultipleTypeBinding) type).types;
for(int j = 0; j < types.length; j++) {
if(!types[j].isLocalType())
recordQualifiedReference(types[j].isMemberType() ? CharOperation.splitOn('.',
types[j].readableName()) : types[j].compoundName);
}
} else if(!type.isLocalType())
recordQualifiedReference(type.isMemberType() ? CharOperation.splitOn('.', type.readableName())
: type.compoundName);
}
int size = qualifiedReferences.size;
char[][][] qualifiedRefs = new char[size][][];
for(int i = 0; i < size; i++)
qualifiedRefs[i] = qualifiedReferences.elementAt(i);
referenceContext.compilationResult.qualifiedReferences = qualifiedRefs;
size = simpleNameReferences.size;
char[][] simpleRefs = new char[size][];
for(int i = 0; i < size; i++)
simpleRefs[i] = simpleNameReferences.elementAt(i);
referenceContext.compilationResult.simpleNameReferences = simpleRefs;
}
public String toString() {
return "--- JavaScriptUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$
}
private ReferenceBinding typeToRecord(TypeBinding type) {
while(type.isArrayType())
type = ((ArrayBinding) type).leafComponentType;
switch(type.kind()) {
case Binding.BASE_TYPE:
return null;
}
if(type instanceof CompilationUnitBinding)
return null;
ReferenceBinding refType = (ReferenceBinding) type;
if(refType.isLocalType())
return null;
return refType;
}
public void cleanup() {
if(this.referencedTypes != null)
for(int i = 0, l = referencedTypes.size; i < l; i++) {
Object obj = referencedTypes.elementAt(i);
if(obj instanceof SourceTypeBinding) {
SourceTypeBinding type = (SourceTypeBinding) obj;
type.cleanup();
}
}
}
public void addExternalVar(LocalVariableBinding binding) {
externalCompilationUnits.add(binding.declaringScope.compilationUnitScope());
}
/**
* @return the shouldBuildGlobalSuperType
*/
public boolean shouldBuildGlobalSuperType() {
return shouldBuildGlobalSuperType;
}
/**
* @param shouldBuildGlobalSuperType the shouldBuildGlobalSuperType to set
*/
public void setShouldBuildGlobalSuperType(boolean shouldBuild) {
this.shouldBuildGlobalSuperType = shouldBuild;
}
}