blob: 230c76a9ec6f2bd66d22f4c5bcc6056e24810712 [file] [log] [blame]
package org.eclipse.jdt.internal.compiler.lookup;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.problem.*;
import org.eclipse.jdt.internal.compiler.util.*;
public class CompilationUnitScope extends Scope {
public LookupEnvironment environment;
public CompilationUnitDeclaration referenceContext;
public char[][] currentPackageName;
public PackageBinding fPackage;
public ImportBinding[] imports;
public SourceTypeBinding[] topLevelTypes;
private ObjectVector namespaceDependencies;
private ObjectVector typeDependencies;
public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
super(COMPILATION_UNIT_SCOPE, null);
this.environment = environment;
this.referenceContext = unit;
unit.scope = this;
this.currentPackageName = unit.currentPackage == null ? NoCharChar : unit.currentPackage.tokens;
if (environment.options.produceReferenceInfo) {
this.namespaceDependencies = new ObjectVector();
this.typeDependencies = new ObjectVector();
} else {
this.namespaceDependencies = null; // used to test if dependencies should be recorded
this.typeDependencies = null;
}
}
public void addNamespaceReference(PackageBinding packageBinding) {
if (namespaceDependencies == null) return; // we're not recording dependencies
if (packageBinding.isValidBinding()) {
if (!namespaceDependencies.contains(packageBinding))
namespaceDependencies.add(packageBinding);
} else {
for (int i = namespaceDependencies.size; --i >= 0;) {
PackageBinding next = (PackageBinding) namespaceDependencies.elementAt(i);
if (!next.isValidBinding() && CharOperation.equals(packageBinding.compoundName, next.compoundName))
return;
}
namespaceDependencies.add(packageBinding);
}
}
public void addTypeReference(TypeBinding type) {
if (typeDependencies == null) return; // we're not recording dependencies
if (type.isArrayType())
type = ((ArrayBinding) type).leafComponentType;
if (!type.isBaseType()) {
ReferenceBinding actualType = (ReferenceBinding) type;
if (!typeDependencies.contains(actualType))
typeDependencies.add(actualType);
}
}
public void addTypeReferences(TypeBinding[] types) {
if (typeDependencies == null) return; // we're not recording dependencies
if (types == null || types == NoExceptions) return;
for (int i = 0, max = types.length; i < max; i++) addTypeReference(types[i]);
}
void buildFieldsAndMethods() {
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].scope.buildFieldsAndMethods();
}
void buildTypeBindings() {
topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved
if (currentPackageName == NoCharChar) {
if ((fPackage = environment.defaultPackage) == null) {
problemReporter().mustSpecifyPackage(referenceContext);
return;
}
} else {
if ((fPackage = environment.createPackage(currentPackageName)) == null) {
problemReporter().packageCollidesWithType(referenceContext);
return;
}
}
// Skip typeDeclarations which know of previously reported errors
TypeDeclaration[] types = referenceContext.types;
int typeLength = (types == null) ? 0 : types.length;
topLevelTypes = new SourceTypeBinding[typeLength];
int count = 0;
nextType: for (int i = 0; i < typeLength; i++) {
TypeDeclaration typeDecl = types[i];
ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name);
if (typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) {
// if a type exists, it must be a valid type - cannot be a NotFound problem type
// unless its an unresolved type which is now being defined
problemReporter().duplicateTypes(referenceContext, typeDecl);
continue nextType;
}
if (currentPackageName != NoCharChar) {
if ((fPackage.getPackage0(typeDecl.name)) != null || environment.isPackage(currentPackageName, typeDecl.name)) {
// if a package exists, it must be a valid package - cannot be a NotFound problem package
problemReporter().typeCollidesWithPackage(referenceContext, typeDecl);
continue nextType;
}
}
if ((typeDecl.modifiers & AccPublic) != 0) {
if (!CharOperation.equals(referenceContext.getMainTypeName(), typeDecl.name)) {
problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl);
continue nextType;
}
}
ClassScope child = new ClassScope(this, typeDecl);
topLevelTypes[count++] = child.buildType(null, fPackage);
}
// shrink topLevelTypes... only happens if an error was reported
if (count != topLevelTypes.length)
System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count);
}
void checkAndSetImports() {
// initialize the default imports if necessary... share the default java.lang.* import
if (environment.defaultImports == null) {
Binding importBinding = environment.getTopLevelPackage(JAVA);
if (importBinding != null)
importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]);
// abort if java.lang cannot be found...
if (importBinding == null || !importBinding.isValidBinding())
problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit());
environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding)};
}
if (referenceContext.imports == null) {
imports = environment.defaultImports;
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.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) {
numberOfImports--;
break;
}
}
ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
resolvedImports[0] = environment.defaultImports[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++)
if (resolvedImports[j].onDemand == importReference.onDemand)
if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
continue nextImport;
if (importReference.onDemand == true)
if (CharOperation.equals(compoundName, currentPackageName))
continue nextImport;
if (importReference.onDemand) {
Binding importBinding = findOnDemandImport(compoundName);
if (!importBinding.isValidBinding())
continue nextImport; // we report all problems in faultInImports()
resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding);
} else {
resolvedImports[index++] = new ImportBinding(compoundName, false, null);
}
}
// 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;
}
void connectTypeHierarchy() {
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].scope.connectTypeHierarchy();
}
void faultInImports() {
if (referenceContext.imports == null)
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].onDemand) {
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
int numberOfImports = numberOfStatements + 1;
for (int i = 0; i < numberOfStatements; i++) {
ImportReference importReference = referenceContext.imports[i];
if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens)) {
numberOfImports--;
break;
}
}
ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
resolvedImports[0] = environment.defaultImports[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++)
if (resolvedImports[j].onDemand == importReference.onDemand)
if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
continue nextImport;
if (importReference.onDemand == true)
if (CharOperation.equals(compoundName, currentPackageName))
continue nextImport;
if (importReference.onDemand) {
Binding importBinding = findOnDemandImport(compoundName);
if (!importBinding.isValidBinding()) {
problemReporter().importProblem(importReference, importBinding);
continue nextImport;
}
resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding);
} else {
Binding typeBinding = findSingleTypeImport(compoundName);
if (!typeBinding.isValidBinding()) {
problemReporter().importProblem(importReference, typeBinding);
continue nextImport;
}
if (typeBinding instanceof PackageBinding) {
problemReporter().cannotImportPackage(importReference);
continue nextImport;
}
ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]);
if (existingType != null) {
// duplicate test above should have caught this case, but make sure
if (existingType == typeBinding)
continue nextImport;
// either the type collides with a top level type or another imported type
for (int j = 0, length = topLevelTypes.length; j < length; j++) {
if (CharOperation.equals(topLevelTypes[j].sourceName, existingType.sourceName)) {
problemReporter().conflictingImport(importReference);
continue nextImport;
}
}
problemReporter().duplicateImport(importReference);
continue nextImport;
}
resolvedImports[index++] = new ImportBinding(compoundName, false, typeBinding);
typesBySimpleNames.put(compoundName[compoundName.length - 1], (ReferenceBinding) typeBinding);
}
}
// 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;
}
public void faultInTypes() {
faultInImports();
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].faultInTypesForFieldsAndMethods();
}
private Binding findOnDemandImport(char[][] compoundName) {
Binding binding = environment.getPackage0(compoundName[0]);
if (binding == null) {
if (environment.isPackage(null, compoundName[0]))
binding = environment.getTopLevelPackage(compoundName[0]);
else // hold onto a problem package since a real one will never be created
addNamespaceReference(new ProblemPackageBinding(compoundName[0], NotFound));
} else {
if (binding == environment.theNotFoundPackage)
binding = null; // forget the NotFound package
}
int i = 1;
int length = compoundName.length;
foundNothingOrType: if (binding != null) {
PackageBinding packageBinding = (PackageBinding) binding;
addNamespaceReference(packageBinding);
while (i < length) {
binding = packageBinding.getTypeOrPackage(compoundName[i++]);
if (binding == null || !binding.isValidBinding()) {
binding = null;
break foundNothingOrType;
}
if (!(binding instanceof PackageBinding))
break foundNothingOrType;
packageBinding = (PackageBinding) binding;
addNamespaceReference(packageBinding);
}
return packageBinding;
}
ReferenceBinding type;
if (binding == null) {
if (environment.defaultPackage == null)
return new ProblemReferenceBinding(compoundName, NotFound);
type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage);
if (type == null || !type.isValidBinding())
return new ProblemReferenceBinding(compoundName, NotFound);
i = 1; // reset to look for member types inside the default package type
} else {
type = (ReferenceBinding) binding;
}
for (; i < length; i++) {
addTypeReference(type);
// does not look for inherited member types on purpose
if ((type = type.getMemberType(compoundName[i])) == null)
return new ProblemReferenceBinding(compoundName, NotFound);
}
addTypeReference(type);
if (!type.canBeSeenBy(fPackage))
return new ProblemReferenceBinding(compoundName, NotVisible);
return type;
}
private Binding findSingleTypeImport(char[][] compoundName) {
if (compoundName.length == 1) {
// the name cannot be a package
if (environment.defaultPackage == null)
return new ProblemReferenceBinding(compoundName, NotFound);
ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage);
if (typeBinding == null)
return new ProblemReferenceBinding(compoundName, NotFound);
else
return typeBinding;
}
return findOnDemandImport(compoundName);
}
/* 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;
}
Binding resolveSingleTypeImport(ImportBinding importBinding) {
if (importBinding.resolvedImport == null) {
importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName);
if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) {
ImportBinding[] newImports = new ImportBinding[imports.length - 1];
for (int i = 0, n = 0, max = imports.length; i < max; i++)
if (imports[i] != importBinding)
newImports[n++] = imports[i];
imports = newImports;
return null;
}
}
return importBinding.resolvedImport;
}
public void storeDependencyInfo() {
for (int i = 0; i < typeDependencies.size; i++) { // grows as more types are added
// add all the supertypes & associated packages
ReferenceBinding type = (ReferenceBinding) typeDependencies.elementAt(i);
addNamespaceReference(type.fPackage); // is this necessary? If so what about a & a.b from a.b.c?
if (type.enclosingType() != null)
addTypeReference(type.enclosingType());
if (type.superclass() != null)
addTypeReference(type.superclass());
ReferenceBinding[] interfaces = type.superInterfaces();
for (int j = 0, length = interfaces.length; j < length; j++)
addTypeReference(interfaces[j]);
}
int length = namespaceDependencies.size;
char[][] namespaceNames = new char[length][];
for (int i = 0; i < length; i++)
namespaceNames[i] = ((PackageBinding) namespaceDependencies.elementAt(i)).readableName();
referenceContext.compilationResult.namespaceDependencies = namespaceNames;
length = typeDependencies.size;
int toplevelTypeCount = 0;
for (int i = 0; i < length; i++)
if (!((ReferenceBinding) typeDependencies.elementAt(i)).isNestedType())
toplevelTypeCount++;
char[][] fileNames = new char[toplevelTypeCount][];
for (int i = 0; i < length; i++)
if (!((ReferenceBinding) typeDependencies.elementAt(i)).isNestedType())
fileNames[--toplevelTypeCount] = ((ReferenceBinding) typeDependencies.elementAt(i)).getFileName();
// eliminate duplicates
int unique = 0;
char[] ownFileName = referenceContext.getFileName();
next : for (int i = 0, l = fileNames.length; i < l; i++) {
char[] fileName = fileNames[i];
if (CharOperation.equals(fileName, ownFileName)) {
fileNames[i] = null;
continue next;
}
for (int j = i + 1; j < l; j++) {
if (CharOperation.equals(fileName, fileNames[j])) {
fileNames[i] = null;
continue next;
}
}
unique++;
}
if (unique < fileNames.length) {
char[][] uniqueFileNames = new char[unique][];
for (int i = fileNames.length; --i >= 0;)
if (fileNames[i] != null)
uniqueFileNames[--unique] = fileNames[i];
fileNames = uniqueFileNames;
}
referenceContext.compilationResult.fileDependencies = fileNames;
}
public String toString() {
return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$
}
public void verifyMethods(MethodVerifier verifier) {
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].verifyMethods(verifier);
}
}