package org.eclipse.jdt.internal.compiler.lookup;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ImportReference;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-import org.eclipse.jdt.internal.compiler.util.CompoundNameVector;
-import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
-import org.eclipse.jdt.internal.compiler.util.HashtableOfType;
-import org.eclipse.jdt.internal.compiler.util.ObjectVector;
-import org.eclipse.jdt.internal.compiler.util.SimpleNameVector;
+import org.eclipse.jdt.internal.compiler.util.*;
public class CompilationUnitScope extends Scope {
private CompoundNameVector qualifiedReferences;
private SimpleNameVector simpleNameReferences;
private ObjectVector referencedTypes;
+ private ObjectVector referencedSuperTypes;
HashtableOfType constantPoolNameUsage;
this.qualifiedReferences = new CompoundNameVector();
this.simpleNameReferences = new SimpleNameVector();
this.referencedTypes = new ObjectVector();
+ this.referencedSuperTypes = new ObjectVector();
} else {
this.qualifiedReferences = null; // used to test if dependencies should be recorded
this.simpleNameReferences = null;
this.referencedTypes = null;
+ this.referencedSuperTypes = null;
}
}
void buildFieldsAndMethods() {
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].scope.buildFieldsAndMethods();
}
-void buildTypeBindings() {
+void buildTypeBindings(AccessRestriction accessRestriction) {
topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved
if (referenceContext.compilationResult.compilationUnit != null) {
char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName();
}
ClassScope child = new ClassScope(this, typeDecl);
- SourceTypeBinding type = child.buildType(null, fPackage);
+ SourceTypeBinding type = child.buildType(null, fPackage, accessRestriction);
if(type != null) {
topLevelTypes[count++] = type;
}
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)) {
+ if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens) && !importReference.isStatic()) {
numberOfImports--;
break;
}
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)
+ for (int j = 0; j < index; j++) {
+ ImportBinding resolved = resolvedImports[j];
+ if (resolved.onDemand == importReference.onDemand && resolved.isStatic() == importReference.isStatic())
if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
continue nextImport;
- if (importReference.onDemand == true)
+ }
+
+ if (importReference.onDemand) {
if (CharOperation.equals(compoundName, currentPackageName))
continue nextImport;
- if (importReference.onDemand) {
- Binding importBinding = findOnDemandImport(compoundName);
- if (!importBinding.isValidBinding())
+ Binding importBinding = findImport(compoundName, compoundName.length);
+ if (!importBinding.isValidBinding() || (importReference.isStatic() && importBinding instanceof PackageBinding))
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);
}
}
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)) {
+ if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens) && !importReference.isStatic()) {
numberOfImports--;
break;
}
resolvedImports[0] = getDefaultImports()[0];
int index = 1;
+ // 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++)
- if (resolvedImports[j].onDemand == importReference.onDemand)
- if (CharOperation.equals(compoundName, resolvedImports[j].compoundName)) {
+ for (int j = 0; j < index; j++) {
+ ImportBinding resolved = resolvedImports[j];
+ if (resolved.onDemand == importReference.onDemand && resolved.isStatic() == importReference.isStatic()) {
+ if (CharOperation.equals(compoundName, resolved.compoundName)) {
problemReporter().unusedImport(importReference); // since skipped, must be reported now
continue nextImport;
}
- if (importReference.onDemand == true)
+ }
+ }
+ if (importReference.onDemand) {
if (CharOperation.equals(compoundName, currentPackageName)) {
problemReporter().unusedImport(importReference); // since skipped, must be reported now
continue nextImport;
}
- if (importReference.onDemand) {
- Binding importBinding = findOnDemandImport(compoundName);
+
+ Binding importBinding = findImport(compoundName, compoundName.length);
if (!importBinding.isValidBinding()) {
problemReporter().importProblem(importReference, importBinding);
continue nextImport;
}
+ if (importReference.isStatic() && importBinding instanceof PackageBinding) {
+ problemReporter().cannotImportPackage(importReference);
+ continue nextImport;
+ }
resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference);
} else {
- Binding typeBinding = findSingleTypeImport(compoundName);
- if (!typeBinding.isValidBinding()) {
- problemReporter().importProblem(importReference, typeBinding);
+ Binding importBinding = findSingleImport(compoundName, importReference.isStatic());
+ if (!importBinding.isValidBinding()) {
+ problemReporter().importProblem(importReference, importBinding);
continue nextImport;
}
- if (typeBinding instanceof PackageBinding) {
+ if (importBinding 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);
+ // collisions between an imported static field & a type should be checked according to spec... but currently not by javac
+ if (importBinding instanceof ReferenceBinding) {
+ ReferenceBinding referenceBinding = (ReferenceBinding) importBinding;
+ if (importReference.isTypeUseDeprecated(referenceBinding, this))
+ problemReporter().deprecatedType(referenceBinding, 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 == referenceBinding)
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;
}
- problemReporter().duplicateImport(importReference);
- continue nextImport;
+ typesBySimpleNames.put(compoundName[compoundName.length - 1], referenceBinding);
}
- resolvedImports[index++] = new ImportBinding(compoundName, false, typeBinding, importReference);
- typesBySimpleNames.put(compoundName[compoundName.length - 1], (ReferenceBinding) typeBinding);
+ resolvedImports[index++] = new ImportBinding(compoundName, false, importBinding, importReference);
}
}
resolvedSingeTypeImports = new HashtableOfObject(length);
for (int i = 0; i < length; i++) {
ImportBinding binding = imports[i];
- if (!binding.onDemand)
+ if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding)
resolvedSingeTypeImports.put(binding.compoundName[binding.compoundName.length - 1], binding);
}
}
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].faultInTypesForFieldsAndMethods();
}
-private Binding findOnDemandImport(char[][] compoundName) {
+private Binding findImport(char[][] compoundName, int length) {
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) {
ReferenceBinding type;
if (binding == null) {
- if (environment.defaultPackage == null
- || environment.options.complianceLevel >= ClassFileConstants.JDK1_4){
- return new ProblemReferenceBinding(
- CharOperation.subarray(compoundName, 0, i),
- NotFound);
- }
+ if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.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);
+ 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);
- }
+ while (i < length) {
+ if (!type.canBeSeenBy(fPackage))
+ return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type, 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), NotFound);
}
if (!type.canBeSeenBy(fPackage))
return new ProblemReferenceBinding(compoundName, type, NotVisible);
return type;
}
-private Binding findSingleTypeImport(char[][] compoundName) {
+private Binding findSingleImport(char[][] compoundName, boolean findStaticImports) {
if (compoundName.length == 1) {
// findType records the reference
// the name cannot be a package
- if (environment.defaultPackage == null
- || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
+ if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
return new ProblemReferenceBinding(compoundName, NotFound);
ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage);
if (typeBinding == null)
return new ProblemReferenceBinding(compoundName, NotFound);
return typeBinding;
}
- return findOnDemandImport(compoundName);
+
+ if (findStaticImports)
+ return findSingleStaticImport(compoundName);
+ return findImport(compoundName, compoundName.length);
+}
+private Binding findSingleStaticImport(char[][] compoundName) {
+ Binding binding = findImport(compoundName, compoundName.length - 1);
+ if (!binding.isValidBinding()) return binding;
+
+ char[] name = compoundName[compoundName.length - 1];
+ if (binding instanceof PackageBinding) {
+ Binding temp = ((PackageBinding) binding).getTypeOrPackage(name);
+ if (temp != null && temp instanceof ReferenceBinding) // must resolve to a member type or field, not a top level type
+ return new ProblemReferenceBinding(compoundName, InvalidTypeForStaticImport);
+ return binding; // cannot be a package, error is caught in sender
+ }
+
+ // look to see if its a static field first
+ ReferenceBinding type = (ReferenceBinding) binding;
+ FieldBinding field = findField(type, name, null, true);
+ if (field != null && field.isStatic() && field.canBeSeenBy(fPackage))
+ return field;
+
+ type = findMemberType(name, type);
+ if (type == null || !type.isStatic())
+ return new ProblemReferenceBinding(compoundName, type, NotFound);
+ if (!type.canBeSeenBy(fPackage))
+ return new ProblemReferenceBinding(compoundName, type, NotVisible);
+ return type;
}
ImportBinding[] getDefaultImports() {
// initialize the default imports if necessary... share the default java.lang.* import
return environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding, null)};
}
+// NOT Public API
+public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) {
+ if (onDemand)
+ return findImport(compoundName, compoundName.length);
+ return findSingleImport(compoundName, isStaticImport);
+}
/* Answer the problem reporter to use for raising new problems.
*
* Note that as a side-effect, this updates the current reference context
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) {
+ recordSuperTypeReference(subType); // must record the hierarchy of the subType that is converted to the superType
+}
void recordTypeReference(TypeBinding type) {
if (referencedTypes == null) return; // not recording dependencies
- if (type.isArrayType())
- type = ((ArrayBinding) type).leafComponentType;
-
- if (type.isBaseType()) return;
- if (referencedTypes.containsIdentical(type)) return;
- if (((ReferenceBinding) type).isLocalType()) return;
-
- referencedTypes.add(type);
+ ReferenceBinding actualType = typeToRecord(type);
+ if (actualType != null && !referencedTypes.containsIdentical(actualType))
+ referencedTypes.add(actualType);
}
void recordTypeReferences(TypeBinding[] types) {
- if (qualifiedReferences == null) return; // not recording dependencies
+ 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
- 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);
- }
+ ReferenceBinding actualType = typeToRecord(types[i]);
+ if (actualType != null && !referencedTypes.containsIdentical(actualType))
+ referencedTypes.add(actualType);
}
}
-Binding resolveSingleTypeImport(ImportBinding importBinding) {
+Binding resolveSingleImport(ImportBinding importBinding) {
if (importBinding.resolvedImport == null) {
- importBinding.resolvedImport = findSingleTypeImport(importBinding.compoundName);
+ importBinding.resolvedImport = findSingleImport(importBinding.compoundName, importBinding.isStatic());
if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) {
- if (this.imports != null){
+ 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){
+ 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
+ // add the type hierarchy of each referenced supertype
// 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);
+ 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()) {
- 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
+ if (enclosing != null)
+ recordSuperTypeReference(enclosing);
}
ReferenceBinding superclass = type.superclass();
- if (superclass != null && !referencedTypes.containsIdentical(superclass))
- referencedTypes.add(superclass); // to record its supertypes
+ if (superclass != null)
+ recordSuperTypeReference(superclass);
ReferenceBinding[] interfaces = type.superInterfaces();
- if (interfaces != null && interfaces.length > 0)
+ if (interfaces != null)
for (int j = 0, length = interfaces.length; j < length; j++)
- if (!referencedTypes.containsIdentical(interfaces[j]))
- referencedTypes.add(interfaces[j]); // to record its supertypes
+ recordSuperTypeReference(interfaces[j]);
+ }
+
+ for (int i = 0, l = referencedTypes.size; i < l; i++) {
+ ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i);
+ if (!type.isLocalType())
+ recordQualifiedReference(type.isMemberType()
+ ? CharOperation.splitOn('.', type.readableName())
+ : type.compoundName);
}
int size = qualifiedReferences.size;
public String toString() {
return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$
}
+private ReferenceBinding typeToRecord(TypeBinding type) {
+ if (type.isArrayType())
+ type = ((ArrayBinding) type).leafComponentType;
+
+ switch (type.kind()) {
+ case Binding.TYPE_PARAMETER :
+ case Binding.WILDCARD_TYPE :
+ return null;
+ case Binding.PARAMETERIZED_TYPE :
+ case Binding.RAW_TYPE :
+ type = type.erasure();
+ }
+
+ if (type instanceof ReferenceBinding) {
+ ReferenceBinding refType = (ReferenceBinding) type;
+ if (!refType.isLocalType()) return refType;
+ }
+ return null;
+}
public void verifyMethods(MethodVerifier verifier) {
for (int i = 0, length = topLevelTypes.length; i < length; i++)
topLevelTypes[i].verifyMethods(verifier);