X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java index dc4f59f..c6dcbb6 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/CompilationUnitScope.java @@ -1,508 +1,576 @@ /******************************************************************************* - * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 + * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html + * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation - ******************************************************************************/ + *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.lookup; -import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; -import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; -import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; -import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; +import java.util.ArrayList; + +import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; -import net.sourceforge.phpdt.internal.compiler.util.CharOperation; import net.sourceforge.phpdt.internal.compiler.util.CompoundNameVector; import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType; import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; import net.sourceforge.phpdt.internal.compiler.util.SimpleNameVector; +import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference; +import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration; public class CompilationUnitScope extends Scope { - public LookupEnvironment environment; - public CompilationUnitDeclaration referenceContext; - public char[][] currentPackageName; - public PackageBinding fPackage; - public ImportBinding[] imports; - - public SourceTypeBinding[] topLevelTypes; - - private CompoundNameVector qualifiedReferences; - private SimpleNameVector simpleNameReferences; - private ObjectVector referencedTypes; - -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.qualifiedReferences = new CompoundNameVector(); - this.simpleNameReferences = new SimpleNameVector(); - this.referencedTypes = new ObjectVector(); - } else { - this.qualifiedReferences = null; // used to test if dependencies should be recorded - this.simpleNameReferences = null; - this.referencedTypes = null; - } -} -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 (referenceContext.compilationResult.compilationUnit != null) { - char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName(); - if (expectedPackageName != null && !CharOperation.equals(currentPackageName, expectedPackageName)) { - problemReporter().packageIsNotExpectedPackage(referenceContext); - currentPackageName = expectedPackageName.length == 0 ? NoCharChar : expectedPackageName; - } - } - if (currentPackageName == NoCharChar) { - if ((fPackage = environment.defaultPackage) == null) { - problemReporter().mustSpecifyPackage(referenceContext); - return; - } - } else { - if ((fPackage = environment.createPackage(currentPackageName)) == null) { - problemReporter().packageCollidesWithType(referenceContext); - return; - } - recordQualifiedReference(currentPackageName); // always dependent on your own package - } - - // 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); - recordSimpleReference(typeDecl.name); // needed to detect collision cases - 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; - } - boolean packageExists = currentPackageName == NoCharChar - ? environment.getTopLevelPackage(typeDecl.name) != null - : (fPackage.getPackage(typeDecl.name)) != null; - if (packageExists) { - // 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) { - char[] mainTypeName; - if ((mainTypeName = referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided to return null - && !CharOperation.equals(mainTypeName, 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, null)}; - } - 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, importReference); - } else { - 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; -} -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, importReference); - } 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, importReference); - 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) { - recordQualifiedReference(compoundName); - - Binding binding = environment.getTopLevelPackage(compoundName[0]); - int i = 1; - int length = compoundName.length; - foundNothingOrType: if (binding != null) { - PackageBinding packageBinding = (PackageBinding) binding; - 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; - } - return packageBinding; - } - - ReferenceBinding type; - if (binding == null) { - if (environment.defaultPackage == null - || environment.options.complianceLevel >= CompilerOptions.JDK1_4){ - return new ProblemReferenceBinding( - CharOperation.subarray(compoundName, 0, i), - NotFound); - } - type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); - if (type == null || !type.isValidBinding()) - return new ProblemReferenceBinding( - CharOperation.subarray(compoundName, 0, i), - NotFound); - i = 1; // reset to look for member types inside the default package type - } else { - type = (ReferenceBinding) binding; - } - - for (; i < length; i++) { - // does not look for inherited member types on purpose - if ((type = type.getMemberType(compoundName[i])) == null) - return new ProblemReferenceBinding( - CharOperation.subarray(compoundName, 0, i + 1), - NotFound); - } - if (!type.canBeSeenBy(fPackage)) - return new ProblemReferenceBinding(compoundName, type, NotVisible); - return type; -} -private Binding findSingleTypeImport(char[][] compoundName) { - if (compoundName.length == 1) { - // findType records the reference - // the name cannot be a package - if (environment.defaultPackage == null - || environment.options.complianceLevel >= CompilerOptions.JDK1_4) - 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; -} - -/* -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 recordSimpleReference(char[] simpleName) { - if (simpleNameReferences == null) return; // not recording dependencies - - if (!simpleNameReferences.contains(simpleName)) - simpleNameReferences.add(simpleName); -} -void recordTypeReference(TypeBinding type) { - if (referencedTypes == null) return; // not recording dependencies - - if (type.isArrayType()) - type = ((ArrayBinding) type).leafComponentType; - if (!type.isBaseType() && !referencedTypes.containsIdentical(type)) - referencedTypes.add(type); -} -void recordTypeReferences(TypeBinding[] types) { - if (qualifiedReferences == 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 - TypeBinding type = types[i]; - if (type.isArrayType()) - type = ((ArrayBinding) type).leafComponentType; - if (!type.isBaseType()) { - ReferenceBinding actualType = (ReferenceBinding) type; - if (!actualType.isLocalType()) - recordQualifiedReference(actualType.isMemberType() - ? CharOperation.splitOn('.', actualType.readableName()) - : actualType.compoundName); - } - } -} -Binding resolveSingleTypeImport(ImportBinding importBinding) { - if (importBinding.resolvedImport == null) { - importBinding.resolvedImport = findSingleTypeImport(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 type - // cannot do early since the hierarchy may not be fully resolved - for (int i = 0; i < referencedTypes.size; i++) { // grows as more types are added - ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i); - if (!type.isLocalType()) { - recordQualifiedReference(type.isMemberType() - ? CharOperation.splitOn('.', type.readableName()) - : type.compoundName); - ReferenceBinding enclosing = type.enclosingType(); - if (enclosing != null && !referencedTypes.containsIdentical(enclosing)) - referencedTypes.add(enclosing); // to record its supertypes - } - ReferenceBinding superclass = type.superclass(); - if (superclass != null && !referencedTypes.containsIdentical(superclass)) - referencedTypes.add(superclass); // to record its supertypes - ReferenceBinding[] interfaces = type.superInterfaces(); - if (interfaces != null && interfaces.length > 0) - for (int j = 0, length = interfaces.length; j < length; j++) - if (!referencedTypes.containsIdentical(interfaces[j])) - referencedTypes.add(interfaces[j]); // to record its supertypes - } - - 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 "--- 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); + public LookupEnvironment environment; + public CompilationUnitDeclaration referenceContext; + public char[][] currentPackageName; + public PackageBinding fPackage; + public ImportBinding[] imports; + + public SourceTypeBinding[] topLevelTypes; + + private CompoundNameVector qualifiedReferences; + private SimpleNameVector simpleNameReferences; + private ObjectVector referencedTypes; + + HashtableOfType constantPoolNameUsage; + + 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 ? CharOperation.NO_CHAR_CHAR : unit.currentPackage.tokens; + this.currentPackageName = null; + // if (environment.options.produceReferenceInfo) { + // this.qualifiedReferences = new CompoundNameVector(); + // this.simpleNameReferences = new SimpleNameVector(); + // this.referencedTypes = new ObjectVector(); + // } else { + this.qualifiedReferences = null; // used to test if dependencies should be recorded + this.simpleNameReferences = null; + this.referencedTypes = null; + // } + } + void buildFieldsAndMethods() { + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].scope.buildFieldsAndMethods(); + } + void buildTypeBindings() { + if (referenceContext.compilationResult.compilationUnit != null) { + char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName(); + if (expectedPackageName != null && !CharOperation.equals(currentPackageName, expectedPackageName)) { + + // only report if the unit isn't structurally empty + // if (referenceContext.currentPackage != null + // || referenceContext.types != null + // || referenceContext.imports != null) { + // problemReporter().packageIsNotExpectedPackage(referenceContext); + // } + currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName; + } + } + if (currentPackageName == CharOperation.NO_CHAR_CHAR) { + if ((fPackage = environment.defaultPackage) == null) { + problemReporter().mustSpecifyPackage(referenceContext); + return; + } + } else { + if ((fPackage = environment.createPackage(currentPackageName)) == null) { +// problemReporter().packageCollidesWithType(referenceContext); + return; + } + recordQualifiedReference(currentPackageName); // always dependent on your own package + } + + // Skip typeDeclarations which know of previously reported errors + ArrayList types = referenceContext.types; + int typeLength = (types == null) ? 0 : types.size(); + topLevelTypes = new SourceTypeBinding[typeLength]; + int count = 0; + nextType : for (int i = 0; i < typeLength; i++) { + if (types.get(i) instanceof TypeDeclaration) { + TypeDeclaration typeDecl = (TypeDeclaration) types.get(i); + ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name); + recordSimpleReference(typeDecl.name); // needed to detect collision cases + 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 (fPackage != environment.defaultPackage && fPackage.getPackage(typeDecl.name) != null) { + // 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) { + char[] mainTypeName; + if ((mainTypeName = referenceContext.getMainTypeName()) != null + // mainTypeName == null means that implementor of ICompilationUnit decided to return null + && !CharOperation.equals(mainTypeName, typeDecl.name)) { + problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl); + continue nextType; + } + } + + ClassScope child = new ClassScope(this, typeDecl); + SourceTypeBinding type = child.buildType(null, fPackage); + if (type != null) { + topLevelTypes[count++] = type; + } + } + } + + // 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, null)}; +// } +// 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, importReference); +// } else { +// 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; + 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()) { + candidateName = CharOperation.concat(outerMostEnclosingType.constantPoolName(), String.valueOf(index + 1).toCharArray(), '$'); + } 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() { + 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)) { +// problemReporter().unusedImport(importReference); // since skipped, must be reported now +// continue nextImport; +// } +// if (importReference.onDemand == true) +// if (CharOperation.equals(compoundName, currentPackageName)) { +// problemReporter().unusedImport(importReference); // since skipped, must be reported now +// 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, importReference); +// } else { +// Binding typeBinding = findSingleTypeImport(compoundName); +// if (!typeBinding.isValidBinding()) { +// problemReporter().importProblem(importReference, typeBinding); +// continue nextImport; +// } +// if (typeBinding instanceof PackageBinding) { +// problemReporter().cannotImportPackage(importReference); +// continue nextImport; +// } +// if (typeBinding instanceof ReferenceBinding) { +// ReferenceBinding referenceBinding = (ReferenceBinding) typeBinding; +// if (importReference.isTypeUseDeprecated(referenceBinding, this)) { +// problemReporter().deprecatedType((TypeBinding) typeBinding, importReference); +// } +// } +// 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, importReference); +// 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(); + if (topLevelTypes==null) { + topLevelTypes = new SourceTypeBinding[0]; + } + for (int i = 0, length = topLevelTypes.length; i < length; i++) + topLevelTypes[i].faultInTypesForFieldsAndMethods(); + } + private Binding findOnDemandImport(char[][] compoundName) { + recordQualifiedReference(compoundName); + + Binding binding = environment.getTopLevelPackage(compoundName[0]); + int i = 1; + int length = compoundName.length; + foundNothingOrType : if (binding != null) { + PackageBinding packageBinding = (PackageBinding) binding; + 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; + } + return packageBinding; + } + + ReferenceBinding type; + if (binding == null) { + // if (environment.defaultPackage == null + // || environment.options.complianceLevel >= CompilerOptions.JDK1_4){ + // return new ProblemReferenceBinding( + // CharOperation.subarray(compoundName, 0, i), + // NotFound); + // } + type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage); + if (type == null || !type.isValidBinding()) + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound); + i = 1; // reset to look for member types inside the default package type + } else { + type = (ReferenceBinding) binding; + } + + for (; i < length; i++) { + if (!type.canBeSeenBy(fPackage)) { + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type, NotVisible); + } + // does not look for inherited member types on purpose + if ((type = type.getMemberType(compoundName[i])) == null) { + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i + 1), NotFound); + } + } + if (!type.canBeSeenBy(fPackage)) + return new ProblemReferenceBinding(compoundName, type, NotVisible); + return type; + } + private Binding findSingleTypeImport(char[][] compoundName) { + if (compoundName.length == 1) { + // findType records the reference + // the name cannot be a package + // if (environment.defaultPackage == null + // || environment.options.complianceLevel >= CompilerOptions.JDK1_4) + // 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; + } + + /* + 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 recordSimpleReference(char[] simpleName) { + if (simpleNameReferences == null) + return; // not recording dependencies + + if (!simpleNameReferences.contains(simpleName)) + simpleNameReferences.add(simpleName); + } + void recordTypeReference(TypeBinding type) { + if (referencedTypes == null) + return; // not recording dependencies + + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType() && !referencedTypes.containsIdentical(type)) + referencedTypes.add(type); + } + void recordTypeReferences(TypeBinding[] types) { + if (qualifiedReferences == 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 + TypeBinding type = types[i]; + if (type.isArrayType()) + type = ((ArrayBinding) type).leafComponentType; + if (!type.isBaseType()) { + ReferenceBinding actualType = (ReferenceBinding) type; + if (!actualType.isLocalType()) + recordQualifiedReference(actualType.isMemberType() ? CharOperation.splitOn('.', actualType.readableName()) : actualType.compoundName); + } + } + } + Binding resolveSingleTypeImport(ImportBinding importBinding) { + if (importBinding.resolvedImport == null) { + importBinding.resolvedImport = findSingleTypeImport(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 type + // cannot do early since the hierarchy may not be fully resolved + for (int i = 0; i < referencedTypes.size; i++) { // grows as more types are added + ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i); + if (!type.isLocalType()) { + recordQualifiedReference(type.isMemberType() ? CharOperation.splitOn('.', type.readableName()) : type.compoundName); + ReferenceBinding enclosing = type.enclosingType(); + if (enclosing != null && !referencedTypes.containsIdentical(enclosing)) + referencedTypes.add(enclosing); // to record its supertypes + } + ReferenceBinding superclass = type.superclass(); + if (superclass != null && !referencedTypes.containsIdentical(superclass)) + referencedTypes.add(superclass); // to record its supertypes + ReferenceBinding[] interfaces = type.superInterfaces(); + if (interfaces != null && interfaces.length > 0) + for (int j = 0, length = interfaces.length; j < length; j++) + if (!referencedTypes.containsIdentical(interfaces[j])) + referencedTypes.add(interfaces[j]); // to record its supertypes + } + + 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 "--- 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); + } } -} \ No newline at end of file