X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java index 858d480..7cc8aeb 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/lookup/Scope.java @@ -1,20 +1,30 @@ /******************************************************************************* - * 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.impl.CompilerOptions; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; +import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; + +import net.sourceforge.phpdt.core.compiler.CharOperation; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; -import net.sourceforge.phpdt.internal.compiler.util.CharOperation; import net.sourceforge.phpdt.internal.compiler.util.ObjectVector; +import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration; +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 abstract class Scope implements @@ -56,12 +66,6 @@ public abstract class Scope return true; } - /* Answer true if the left type can be assigned to right - */ - public static boolean areTypesCompatible(TypeBinding left, TypeBinding right) { - return left.isCompatibleWith(right); - } - /* Answer an int describing the relationship between the given types. * * NotRelated @@ -69,9 +73,9 @@ public abstract class Scope * MoreGeneric : right is compatible with left */ public static int compareTypes(TypeBinding left, TypeBinding right) { - if (areTypesCompatible(left, right)) + if (left.isCompatibleWith(right)) return EqualOrMoreSpecific; - if (areTypesCompatible(right, left)) + if (right.isCompatibleWith(left)) return MoreGeneric; return NotRelated; } @@ -105,6 +109,22 @@ public abstract class Scope return new ArrayBinding(type, dimension); } + public final ClassScope enclosingClassScope() { + Scope scope = this; + while ((scope = scope.parent) != null) { + if (scope instanceof ClassScope) return (ClassScope)scope; + } + return null; // may answer null if no type around + } + + public final MethodScope enclosingMethodScope() { + Scope scope = this; + while ((scope = scope.parent) != null) { + if (scope instanceof MethodScope) return (MethodScope)scope; + } + return null; // may answer null if no method around + } + /* Answer the receiver's enclosing source type. */ public final SourceTypeBinding enclosingSourceType() { @@ -174,6 +194,11 @@ public abstract class Scope public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite) { if (receiverType.isBaseType()) return null; if (receiverType.isArrayType()) { + TypeBinding leafType = receiverType.leafComponentType(); + if (leafType instanceof ReferenceBinding) { + if (!((ReferenceBinding) leafType).canBeSeenBy(this)) + return new ProblemFieldBinding((ReferenceBinding)leafType, fieldName, ReceiverTypeNotVisible); + } if (CharOperation.equals(fieldName, LENGTH)) return ArrayBinding.LengthField; return null; @@ -183,8 +208,7 @@ public abstract class Scope ReferenceBinding currentType = (ReferenceBinding) receiverType; if (!currentType.canBeSeenBy(this)) - return new ProblemFieldBinding(currentType, fieldName, NotVisible); - // *** Need a new problem id - TypeNotVisible? + return new ProblemFieldBinding(currentType, fieldName, ReceiverTypeNotVisible); FieldBinding field = currentType.getField(fieldName); if (field != null) { @@ -419,11 +443,40 @@ public abstract class Scope currentType = getJavaLangObject(); } +// boolean isCompliant14 = compilationUnitScope().environment.options.complianceLevel >= CompilerOptions.JDK1_4; // superclass lookup ReferenceBinding classHierarchyStart = currentType; while (currentType != null) { MethodBinding[] currentMethods = currentType.getMethods(selector); int currentLength = currentMethods.length; + + /* + * if 1.4 compliant, must filter out redundant protected methods from superclasses + */ +// if (isCompliant14){ +// nextMethod: for (int i = 0; i < currentLength; i++){ +// MethodBinding currentMethod = currentMethods[i]; +// // protected method need to be checked only - default access is already dealt with in #canBeSeen implementation +// // when checking that p.C -> q.B -> p.A cannot see default access members from A through B. +// if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod; +// if (matchingMethod != null){ +// if (currentMethod.areParametersEqual(matchingMethod)){ +// currentLength--; +// currentMethods[i] = null; // discard this match +// continue nextMethod; +// } +// } else { +// for (int j = 0, max = found.size; j < max; j++) { +// if (((MethodBinding)found.elementAt(j)).areParametersEqual(currentMethod)){ +// currentLength--; +// currentMethods[i] = null; +// continue nextMethod; +// } +// } +// } +// } +// } + if (currentLength == 1 && matchingMethod == null && found.size == 0) { matchingMethod = currentMethods[0]; } else if (currentLength > 0) { @@ -431,15 +484,31 @@ public abstract class Scope found.add(matchingMethod); matchingMethod = null; } - found.addAll(currentMethods); + // append currentMethods, filtering out null entries + int maxMethod = currentMethods.length; + if (maxMethod == currentLength) { // no method was eliminated for 1.4 compliance (see above) + found.addAll(currentMethods); + } else { + for (int i = 0, max = currentMethods.length; i < max; i++) { + MethodBinding currentMethod = currentMethods[i]; + if (currentMethod != null) found.add(currentMethod); + } + } } currentType = currentType.superclass(); } int foundSize = found.size; if (foundSize == 0) { - if (matchingMethod != null && areParametersAssignable(matchingMethod.parameters, argumentTypes)) + if (matchingMethod != null && areParametersAssignable(matchingMethod.parameters, argumentTypes)) { + // (if no default abstract) must explicitly look for one instead, which could be a better match + if (!matchingMethod.canBeSeenBy(receiverType, invocationSite, this)) { + // ignore matching method (to be consistent with multiple matches, none visible (matching method is then null) + MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found); + if (interfaceMethod != null) return interfaceMethod; + } return matchingMethod; + } return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); } @@ -498,7 +567,7 @@ public abstract class Scope MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found); if (interfaceMethod != null) return interfaceMethod; - return new ProblemMethodBinding(candidates[0].selector, argumentTypes, candidates[0].declaringClass, NotVisible); + return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, NotVisible); } if (candidates[0].declaringClass.isClass()) { return mostSpecificClassMethodBinding(candidates, visiblesCount); @@ -625,6 +694,12 @@ public abstract class Scope TypeBinding[] argumentTypes, InvocationSite invocationSite) { + TypeBinding leafType = receiverType.leafComponentType(); + if (leafType instanceof ReferenceBinding) { + if (!((ReferenceBinding) leafType).canBeSeenBy(this)) + return new ProblemMethodBinding(selector, MethodBinding.NoParameters, (ReferenceBinding)leafType, ReceiverTypeNotVisible); + } + ReferenceBinding object = getJavaLangObject(); MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes); if (methodBinding != null) { @@ -653,9 +728,9 @@ public abstract class Scope NotFound); if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this)) return new ProblemMethodBinding( + methodBinding, selector, - argumentTypes, - methodBinding.declaringClass, + methodBinding.parameters, NotVisible); } return methodBinding; @@ -673,8 +748,6 @@ public abstract class Scope return null; if (typeBinding.isValidBinding()) { -// Not convinced that this is necessary -// compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes if (declarationPackage != invocationPackage && !typeBinding.canBeSeenBy(invocationPackage)) return new ProblemReferenceBinding(typeName, typeBinding, NotVisible); } @@ -749,6 +822,42 @@ public abstract class Scope unitScope = scope; return ((CompilationUnitScope) unitScope).fPackage; } + /** + * Returns the modifiers of the innermost enclosing declaration. + * @return modifiers + */ + public int getDeclarationModifiers(){ + switch(this.kind){ + case Scope.BLOCK_SCOPE : + case Scope.METHOD_SCOPE : + MethodScope methodScope = methodScope(); + if (!methodScope.isInsideInitializer()){ + // check method modifiers to see if deprecated + MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding; + if (context != null) { + return context.modifiers; + } + } else { + SourceTypeBinding type = ((BlockScope)this).referenceType().binding; + + // inside field declaration ? check field modifier to see if deprecated + if (methodScope.initializedField != null) { + return methodScope.initializedField.modifiers; + } + if (type != null) { + return type.modifiers; + } + } + break; + case Scope.CLASS_SCOPE : + ReferenceBinding context = ((ClassScope)this).referenceType().binding; + if (context != null) { + return context.modifiers; + } + break; + } + return -1; + } public final ReferenceBinding getJavaIoSerializable() { compilationUnitScope().recordQualifiedReference(JAVA_IO_SERIALIZABLE); @@ -826,7 +935,7 @@ public abstract class Scope ReferenceBinding type = environment().getType(JAVA_LANG_THROWABLE); if (type != null) return type; - problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit()); +// problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit()); return null; // will not get here since the above error aborts the compilation } @@ -972,7 +1081,6 @@ public abstract class Scope /* Internal use only */ final Binding getTypeOrPackage(char[] name, int mask) { - Scope scope = this; ReferenceBinding foundType = null; if ((mask & TYPE) == 0) { @@ -993,12 +1101,7 @@ public abstract class Scope break; case CLASS_SCOPE : SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding; - if (CharOperation.equals(sourceType.sourceName, name)) { - if (foundType != null && foundType != sourceType) - return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); - return sourceType; - } - + // 6.5.5.1 - simple name favors member type over top-level type in same unit ReferenceBinding memberType = findMemberType(name, sourceType); if (memberType != null) { // skip it if we did not find anything if (memberType.problemId() == Ambiguous) { @@ -1009,23 +1112,28 @@ public abstract class Scope // make the user qualify the type, likely wants the first inherited type return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); } - if (memberType.isValidBinding()) { - if (sourceType == memberType.enclosingType() - || environment().options.complianceLevel >= CompilerOptions.JDK1_4) { - // found a valid type in the 'immediate' scope (ie. not inherited) - // OR in 1.4 mode (inherited shadows enclosing) - if (foundType == null) - return memberType; - if (foundType.isValidBinding()) - // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) - if (foundType != memberType) - return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); - } - } +// if (memberType.isValidBinding()) { +// if (sourceType == memberType.enclosingType() +// || environment().options.complianceLevel >= CompilerOptions.JDK1_4) { +// // found a valid type in the 'immediate' scope (ie. not inherited) +// // OR in 1.4 mode (inherited shadows enclosing) +// if (foundType == null) +// return memberType; +// if (foundType.isValidBinding()) +// // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited) +// if (foundType != memberType) +// return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); +// } +// } if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible)) // only remember the memberType if its the first one found or the previous one was not visible & memberType is... foundType = memberType; } + if (CharOperation.equals(sourceType.sourceName, name)) { + if (foundType != null && foundType != sourceType && foundType.problemId() != NotVisible) + return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName); + return sourceType; + } break; case COMPILATION_UNIT_SCOPE : break done; @@ -1038,39 +1146,45 @@ public abstract class Scope // at this point the scope is a compilation unit scope CompilationUnitScope unitScope = (CompilationUnitScope) scope; + PackageBinding currentPackage = unitScope.fPackage; // ask for the imports + name if ((mask & TYPE) != 0) { // check single type imports. ImportBinding[] imports = unitScope.imports; - if (imports != null){ + if (imports != null) { // copy the list, since single type imports are removed if they cannot be resolved for (int i = 0, length = imports.length; i < length; i++) { ImportBinding typeImport = imports[i]; - if (!typeImport.onDemand) - if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) + if (!typeImport.onDemand) { + if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) { if (unitScope.resolveSingleTypeImport(typeImport) != null) { - if (typeImport.reference != null) typeImport.reference.used = true; + ImportReference importReference = typeImport.reference; + if (importReference != null) importReference.used = true; return typeImport.resolvedImport; // already know its visible } + } + } } } - // check if the name is in the current package (answer the problem binding unless its not found in which case continue to look) - ReferenceBinding type = findType(name, unitScope.fPackage, unitScope.fPackage); // is always visible - if (type != null) return type; + // check if the name is in the current package, skip it if its a sub-package + unitScope.recordReference(currentPackage.compoundName, name); + Binding binding = currentPackage.getTypeOrPackage(name); + if (binding instanceof ReferenceBinding) return binding; // type is always visible to its own package // check on demand imports boolean foundInImport = false; - if (imports != null){ + ReferenceBinding type = null; + if (imports != null) { for (int i = 0, length = imports.length; i < length; i++) { ImportBinding someImport = imports[i]; if (someImport.onDemand) { Binding resolvedImport = someImport.resolvedImport; - ReferenceBinding temp = - (resolvedImport instanceof PackageBinding) - ? findType(name, (PackageBinding) resolvedImport, unitScope.fPackage) + ReferenceBinding temp = resolvedImport instanceof PackageBinding + ? findType(name, (PackageBinding) resolvedImport, currentPackage) : findDirectMemberType(name, (ReferenceBinding) resolvedImport); if (temp != null && temp.isValidBinding()) { - if (someImport.reference != null) someImport.reference.used = true; +// ImportReference importReference = someImport.reference; +// if (importReference != null) importReference.used = true; if (foundInImport) // Answer error binding -- import on demand conflict; name found in two import on demand packages. return new ProblemReferenceBinding(name, Ambiguous); @@ -1080,22 +1194,17 @@ public abstract class Scope } } } - if (type != null) - return type; + if (type != null) return type; } - // see if the name is a package + + unitScope.recordSimpleReference(name); if ((mask & PACKAGE) != 0) { - compilationUnitScope().recordSimpleReference(name); PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name); - if (packageBinding != null) - return packageBinding; + if (packageBinding != null) return packageBinding; } - compilationUnitScope().recordSimpleReference(name); // Answer error binding -- could not find name - if (foundType != null){ - return foundType; - } + if (foundType != null) return foundType; // problem type from above return new ProblemReferenceBinding(name, NotFound); } @@ -1121,17 +1230,104 @@ public abstract class Scope return false; } - public final boolean isJavaIoSerializable(TypeBinding tb) { - //a first -none optimized version-...:-).... - //please modify as needed + /* Answer true if the scope is nested inside a given field declaration. + * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed + * e.g. during name resolution. + */ + public final boolean isDefinedInField(FieldBinding field) { + Scope scope = this; + do { + if (scope instanceof MethodScope) { + MethodScope methodScope = (MethodScope) scope; + ReferenceContext refContext = methodScope.referenceContext; + if (refContext instanceof TypeDeclaration + && ((TypeDeclaration)refContext).binding == field.declaringClass + && methodScope.fieldDeclarationIndex == field.id) { + return true; + } + } + scope = scope.parent; + } while (scope != null); + return false; + } + /* Answer true if the scope is nested inside a given method declaration + */ + public final boolean isDefinedInMethod(MethodBinding method) { + Scope scope = this; + do { + if (scope instanceof MethodScope) { + ReferenceContext refContext = ((MethodScope) scope).referenceContext; + if (refContext instanceof AbstractMethodDeclaration + && ((AbstractMethodDeclaration)refContext).binding == method) { + return true; + } + } + scope = scope.parent; + } while (scope != null); + return false; + } + + /* Answer true if the scope is nested inside a given type declaration + */ + public final boolean isDefinedInType(ReferenceBinding type) { + Scope scope = this; + do { + if (scope instanceof ClassScope) + if (((ClassScope) scope).referenceContext.binding == type){ + return true; + } + scope = scope.parent; + } while (scope != null); + return false; + } + + public boolean isInsideDeprecatedCode(){ + switch(kind){ + case Scope.BLOCK_SCOPE : + case Scope.METHOD_SCOPE : + MethodScope methodScope = methodScope(); + if (!methodScope.isInsideInitializer()){ + // check method modifiers to see if deprecated + MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding; + if (context != null && context.isViewedAsDeprecated()) { + return true; + } + } else { + SourceTypeBinding type = ((BlockScope)this).referenceType().binding; + + // inside field declaration ? check field modifier to see if deprecated + if (methodScope.fieldDeclarationIndex != MethodScope.NotInFieldDecl) { + for (int i = 0; i < type.fields.length; i++){ + if (type.fields[i].id == methodScope.fieldDeclarationIndex) { + // currently inside this field initialization + if (type.fields[i].isViewedAsDeprecated()){ + return true; + } + break; + } + } + } + if (type != null && type.isViewedAsDeprecated()) { + return true; + } + } + break; + case Scope.CLASS_SCOPE : + ReferenceBinding context = ((ClassScope)this).referenceType().binding; + if (context != null && context.isViewedAsDeprecated()) { + return true; + } + break; + } + return false; + } + + public final boolean isJavaIoSerializable(TypeBinding tb) { return tb == getJavaIoSerializable(); } public final boolean isJavaLangCloneable(TypeBinding tb) { - //a first -none optimized version-...:-).... - //please modify as needed - return tb == getJavaLangCloneable(); } @@ -1259,4 +1455,4 @@ public abstract class Scope int startIndex() { return 0; } -} \ No newline at end of file +}