public final boolean canBeSeenBy( TypeBinding receiverType, InvocationSite invocationSite, Scope scope) { if (isPublic()) return true; SourceTypeBinding invocationType = scope.enclosingSourceType(); if (invocationType == this.declaringClass && invocationType == receiverType) return true; if (invocationType == null) // static import call return !isPrivate() && scope.getCurrentPackage() == this.declaringClass.fPackage; if (isProtected()) { // answer true if the invocationType is the declaringClass or they are in the same package // OR the invocationType is a subclass of the declaringClass // AND the receiverType is the invocationType or its subclass // OR the method is a static method accessed directly through a type // OR previous assertions are true for one of the enclosing type if (invocationType == this.declaringClass) return true; if (invocationType.fPackage == this.declaringClass.fPackage) return true; ReferenceBinding currentType = invocationType; int depth = 0; ReferenceBinding receiverErasure = (ReferenceBinding) receiverType.erasure(); ReferenceBinding declaringErasure = (ReferenceBinding) this.declaringClass.erasure(); do { if (currentType.findSuperTypeOriginatingFrom(declaringErasure) != null) { if (invocationSite.isSuperAccess()) return true; // receiverType can be an array binding in one case... see if you can change it if (receiverType instanceof ArrayBinding) return false; if (isStatic()) { if (depth > 0) invocationSite.setDepth(depth); return true; // see 1FMEPDL - return invocationSite.isTypeAccess(); } if (currentType == receiverErasure || receiverErasure.findSuperTypeOriginatingFrom(currentType) != null) { if (depth > 0) invocationSite.setDepth(depth); return true; } } depth++; currentType = currentType.enclosingType(); } while (currentType != null); return false; } if (isPrivate()) { // answer true if the receiverType is the declaringClass // AND the invocationType and the declaringClass have a common enclosingType receiverCheck: { if (receiverType != this.declaringClass) { // special tolerance for type variable direct bounds if (receiverType.isTypeVariable() && ((TypeVariableBinding) receiverType) .isErasureBoundTo(this.declaringClass.erasure())) break receiverCheck; return false; } } if (invocationType != this.declaringClass) { ReferenceBinding outerInvocationType = invocationType; ReferenceBinding temp = outerInvocationType.enclosingType(); while (temp != null) { outerInvocationType = temp; temp = temp.enclosingType(); } ReferenceBinding outerDeclaringClass = (ReferenceBinding) this.declaringClass.erasure(); temp = outerDeclaringClass.enclosingType(); while (temp != null) { outerDeclaringClass = temp; temp = temp.enclosingType(); } if (outerInvocationType != outerDeclaringClass) return false; } return true; } // isDefault() PackageBinding declaringPackage = this.declaringClass.fPackage; if (invocationType.fPackage != declaringPackage) return false; // receiverType can be an array binding in one case... see if you can change it if (receiverType instanceof ArrayBinding) return false; TypeBinding originalDeclaringClass = this.declaringClass.original(); ReferenceBinding currentType = (ReferenceBinding) receiverType; do { if (originalDeclaringClass == currentType.original()) return true; PackageBinding currentPackage = currentType.fPackage; // package could be null for wildcards/intersection types, ignore and recurse in superclass if (currentPackage != null && currentPackage != declaringPackage) return false; } while ((currentType = currentType.superclass()) != null); return false; }