/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.internal.compiler.lookup; import java.util.ArrayList; import org.eclipse.wst.jsdt.core.compiler.CharOperation; import org.eclipse.wst.jsdt.core.infer.InferredAttribute; import org.eclipse.wst.jsdt.core.infer.InferredMethod; import org.eclipse.wst.jsdt.core.infer.InferredType; import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.wst.jsdt.internal.compiler.ast.TypeReference; import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction; import org.eclipse.wst.jsdt.internal.compiler.problem.AbortCompilation; import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter; import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject; public class ClassScope extends Scope { public TypeDeclaration referenceContext; public TypeReference superTypeReference; public InferredType inferredType; public ClassScope(Scope parent, TypeDeclaration context) { super(CLASS_SCOPE, parent); this.referenceContext = context; } public ClassScope(Scope parent, InferredType type) { super(CLASS_SCOPE, parent); this.inferredType = type; } void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) { LocalTypeBinding anonymousType = buildLocalType(enclosingType, enclosingType.fPackage); SourceTypeBinding sourceType = getReferenceBinding(); sourceType.superclass = supertype; connectMemberTypes(); buildFieldsAndMethods(); anonymousType.faultInTypesForFieldsAndMethods(); sourceType.verifyMethods(environment().methodVerifier()); } private void buildFields() { if (referenceContext.fields == null) { getReferenceBinding().setFields(Binding.NO_FIELDS); return; } // count the number of fields vs. initializers FieldDeclaration[] fields = referenceContext.fields; int size = fields.length; int count = 0; for (int i = 0; i < size; i++) { switch (fields[i].getKind()) { case AbstractVariableDeclaration.FIELD: count++; } } // iterate the field declarations to create the bindings, lose all duplicates FieldBinding[] fieldBindings = new FieldBinding[count]; HashtableOfObject knownFieldNames = new HashtableOfObject(count); boolean duplicate = false; count = 0; for (int i = 0; i < size; i++) { FieldDeclaration field = fields[i]; if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) { } else { //FieldBinding fieldBinding = new FieldBinding(field.name, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, getReferenceBinding()); FieldBinding fieldBinding = new FieldBinding(field.binding, getReferenceBinding()); fieldBinding.id = count; // field's type will be resolved when needed for top level types checkAndSetModifiersForField(fieldBinding, field); if (knownFieldNames.containsKey(field.name)) { duplicate = true; FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name); if (previousBinding != null) { for (int f = 0; f < i; f++) { FieldDeclaration previousField = fields[f]; if (previousField.binding == previousBinding) { problemReporter().duplicateFieldInType(getReferenceBinding(), previousField); previousField.binding = null; break; } } } knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed problemReporter().duplicateFieldInType(getReferenceBinding(), field); field.binding = null; } else { knownFieldNames.put(field.name, fieldBinding); // remember that we have seen a field with this name fieldBindings[count++] = fieldBinding; } } } // remove duplicate fields if (duplicate) { FieldBinding[] newFieldBindings = new FieldBinding[fieldBindings.length]; // we know we'll be removing at least 1 duplicate name size = count; count = 0; for (int i = 0; i < size; i++) { FieldBinding fieldBinding = fieldBindings[i]; if (knownFieldNames.get(fieldBinding.name) != null) { fieldBinding.id = count; newFieldBindings[count++] = fieldBinding; } } fieldBindings = newFieldBindings; } if (count != fieldBindings.length) System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); getReferenceBinding().setFields(fieldBindings); } void buildFieldsAndMethods() { buildFields(); buildMethods(); SourceTypeBinding sourceType = getReferenceBinding(); ReferenceBinding[] memberTypes = sourceType.memberTypes; for (int i = 0, length = memberTypes.length; i < length; i++) ((SourceTypeBinding) memberTypes[i]).classScope.buildFieldsAndMethods(); } public SourceTypeBinding getReferenceBinding() { if (referenceContext!=null) return referenceContext.binding; else return inferredType.binding; } private LocalTypeBinding buildLocalType(SourceTypeBinding enclosingType, PackageBinding packageBinding) { referenceContext.scope = this; referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); referenceContext.initializerScope = new MethodScope(this, referenceContext, false); // build the binding or the local type LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType, this.innermostSwitchCase()); referenceContext.binding = localType; checkAndSetModifiers(); // Look at member types ReferenceBinding[] memberTypeBindings = Binding.NO_MEMBER_TYPES; if (referenceContext.memberTypes != null) { int size = referenceContext.memberTypes.length; memberTypeBindings = new ReferenceBinding[size]; int count = 0; nextMember : for (int i = 0; i < size; i++) { TypeDeclaration memberContext = referenceContext.memberTypes[i]; ReferenceBinding type = localType; // check that the member does not conflict with an enclosing type do { if (CharOperation.equals(type.sourceName, memberContext.name)) { continue nextMember; } type = type.enclosingType(); } while (type != null); // check the member type does not conflict with another sibling member type for (int j = 0; j < i; j++) { if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { continue nextMember; } } ClassScope memberScope = new ClassScope(this, referenceContext.memberTypes[i]); LocalTypeBinding memberBinding = memberScope.buildLocalType(localType, packageBinding); memberBinding.setAsMemberType(); memberTypeBindings[count++] = memberBinding; } if (count != size) System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); } localType.memberTypes = memberTypeBindings; return localType; } void buildLocalTypeBinding(SourceTypeBinding enclosingType) { LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage); connectTypeHierarchy(); buildFieldsAndMethods(); localType.faultInTypesForFieldsAndMethods(); getReferenceBinding().verifyMethods(environment().methodVerifier()); } private void buildMemberTypes(AccessRestriction accessRestriction) { SourceTypeBinding sourceType = getReferenceBinding(); ReferenceBinding[] memberTypeBindings = Binding.NO_MEMBER_TYPES; if (referenceContext.memberTypes != null) { int length = referenceContext.memberTypes.length; memberTypeBindings = new ReferenceBinding[length]; int count = 0; nextMember : for (int i = 0; i < length; i++) { TypeDeclaration memberContext = referenceContext.memberTypes[i]; ReferenceBinding type = sourceType; // check that the member does not conflict with an enclosing type do { if (CharOperation.equals(type.sourceName, memberContext.name)) { continue nextMember; } type = type.enclosingType(); } while (type != null); // check that the member type does not conflict with another sibling member type for (int j = 0; j < i; j++) { if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) { continue nextMember; } } ClassScope memberScope = new ClassScope(this, memberContext); memberTypeBindings[count++] = memberScope.buildType(sourceType, sourceType.fPackage, accessRestriction); } if (count != length) System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); } sourceType.memberTypes = memberTypeBindings; } private void buildMethods() { if (referenceContext.methods == null) { getReferenceBinding().setMethods(Binding.NO_METHODS); return; } // iterate the method declarations to create the bindings AbstractMethodDeclaration[] methods = referenceContext.methods; int size = methods == null ? 0 : methods.length; // look for <clinit> method int clinitIndex = -1; for (int i = 0; i < size; i++) { if (methods[i].isClinit()) { clinitIndex = i; break; } } int count = 0; // reserve 2 slots for special enum methods: #values() and #valueOf(String) MethodBinding[] methodBindings = new MethodBinding[(clinitIndex == -1 ? size : size - 1) + count]; // create special methods for enums SourceTypeBinding sourceType = getReferenceBinding(); // if (isEnum) { // methodBindings[0] = sourceType.addSyntheticEnumMethod(TypeConstants.VALUES); // add <EnumType>[] values() // methodBindings[1] = sourceType.addSyntheticEnumMethod(TypeConstants.VALUEOF); // add <EnumType> valueOf() // } // create bindings for source methods for (int i = 0; i < size; i++) { if (i != clinitIndex) { MethodScope scope = new MethodScope(this, methods[i], false); MethodBinding methodBinding = scope.createMethod(methods[i],methods[i].selector,sourceType,false,false); if (methodBinding != null) // is null if binding could not be created methodBindings[count++] = methodBinding; } } if (count != methodBindings.length) System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count); sourceType.tagBits &= ~TagBits.AreMethodsSorted; // in case some static imports reached already into this type sourceType.setMethods(methodBindings); } SourceTypeBinding buildType(SourceTypeBinding enclosingType, PackageBinding packageBinding, AccessRestriction accessRestriction) { // provide the typeDeclaration with needed scopes referenceContext.scope = this; referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true); referenceContext.initializerScope = new MethodScope(this, referenceContext, false); if (enclosingType == null) { char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, referenceContext.name); if (referenceContext!=null) referenceContext.binding= new SourceTypeBinding(className, packageBinding, this); } else { char[][] className = CharOperation.deepCopy(enclosingType.compoundName); className[className.length - 1] = CharOperation.concat(className[className.length - 1], referenceContext.name, '$'); ReferenceBinding existingType = packageBinding.getType0(className[className.length - 1]); referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); } SourceTypeBinding sourceType = getReferenceBinding(); environment().setAccessRestriction(sourceType, accessRestriction); sourceType.fPackage.addType(sourceType); checkAndSetModifiers(); buildMemberTypes(accessRestriction); return sourceType; } private void checkAndSetModifiers() { SourceTypeBinding sourceType = getReferenceBinding(); int modifiers = sourceType.modifiers; ReferenceBinding enclosingType = sourceType.enclosingType(); boolean isMemberType = sourceType.isMemberType(); if (isMemberType) { modifiers |= (enclosingType.modifiers & (ClassFileConstants.AccStrictfp)); // checks for member types before local types to catch local members if (enclosingType.isViewedAsDeprecated() && !sourceType.isDeprecated()) modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; } else if (sourceType.isLocalType()) { if (sourceType.isAnonymousType()) { modifiers |= ClassFileConstants.AccFinal; } Scope scope = this; do { switch (scope.kind) { case METHOD_SCOPE : MethodScope methodScope = (MethodScope) scope; if (methodScope.isInsideInitializer()) { SourceTypeBinding type = ((TypeDeclaration) methodScope.referenceContext).binding; // inside field declaration ? check field modifier to see if deprecated if (methodScope.initializedField != null) { // currently inside this field initialization if (methodScope.initializedField.isViewedAsDeprecated() && !sourceType.isDeprecated()) modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; } else { if (type.isStrictfp()) modifiers |= ClassFileConstants.AccStrictfp; if (type.isViewedAsDeprecated() && !sourceType.isDeprecated()) modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; } } else { MethodBinding method = ((AbstractMethodDeclaration) methodScope.referenceContext).binding; if (method != null) { if (method.isStrictfp()) modifiers |= ClassFileConstants.AccStrictfp; if (method.isViewedAsDeprecated() && !sourceType.isDeprecated()) modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; } } break; case CLASS_SCOPE : // local member if (enclosingType.isStrictfp()) modifiers |= ClassFileConstants.AccStrictfp; if (enclosingType.isViewedAsDeprecated() && !sourceType.isDeprecated()) modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; break; } scope = scope.parent; } while (scope != null); } // after this point, tests on the 16 bits reserved. int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; if (isMemberType) { // test visibility modifiers inconsistency, isolate the accessors bits int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); if ((accessorBits & (accessorBits - 1)) > 1) { // need to keep the less restrictive so disable Protected/Private as necessary if ((accessorBits & ClassFileConstants.AccPublic) != 0) { if ((accessorBits & ClassFileConstants.AccProtected) != 0) modifiers &= ~ClassFileConstants.AccProtected; if ((accessorBits & ClassFileConstants.AccPrivate) != 0) modifiers &= ~ClassFileConstants.AccPrivate; } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { modifiers &= ~ClassFileConstants.AccPrivate; } } } sourceType.modifiers = modifiers; } /* This method checks the modifiers of a field. * * 9.3 & 8.3 * Need to integrate the check for the final modifiers for nested types * * Note : A scope is accessible by : fieldBinding.declaringClass.scope */ private void checkAndSetModifiersForField(FieldBinding fieldBinding, FieldDeclaration fieldDecl) { int modifiers = fieldBinding.modifiers; final ReferenceBinding declaringClass = fieldBinding.declaringClass; // after this point, tests on the 16 bits reserved. int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); if ((accessorBits & (accessorBits - 1)) > 1) { // need to keep the less restrictive so disable Protected/Private as necessary if ((accessorBits & ClassFileConstants.AccPublic) != 0) { if ((accessorBits & ClassFileConstants.AccProtected) != 0) modifiers &= ~ClassFileConstants.AccProtected; if ((accessorBits & ClassFileConstants.AccPrivate) != 0) modifiers &= ~ClassFileConstants.AccPrivate; } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { modifiers &= ~ClassFileConstants.AccPrivate; } } if (fieldDecl.initialization == null && (modifiers & ClassFileConstants.AccFinal) != 0) modifiers |= ExtraCompilerModifiers.AccBlankFinal; fieldBinding.modifiers = modifiers; } public void checkParameterizedSuperTypeCollisions() { ReferenceBinding[] memberTypes = getReferenceBinding().memberTypes; if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) for (int i = 0, size = memberTypes.length; i < size; i++) ((SourceTypeBinding) memberTypes[i]).classScope.checkParameterizedSuperTypeCollisions(); } private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) { // search up the hierarchy of the sourceType to see if any superType defines a member type // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit // assumes super types have already been checked & tagged ReferenceBinding currentType = sourceType; do { if (currentType.hasMemberTypes()) // avoid resolving member types eagerly return; /* BC- Added cycle check BUG 200501 */ } while (currentType.superclass()!=currentType && (currentType = currentType.superclass()) != null && (currentType.tagBits & TagBits.HasNoMemberTypes) == 0); // tag the sourceType and all of its superclasses, unless they have already been tagged currentType = sourceType; do { currentType.tagBits |= TagBits.HasNoMemberTypes; } while ((currentType = currentType.superclass()) != null && (currentType.tagBits & TagBits.HasNoMemberTypes) == 0); } private void connectMemberTypes() { SourceTypeBinding sourceType = getReferenceBinding(); ReferenceBinding[] memberTypes = sourceType.memberTypes; if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) { for (int i = 0, size = memberTypes.length; i < size; i++) ((SourceTypeBinding) memberTypes[i]).classScope.connectTypeHierarchy(); } } /* Our current belief based on available JCK tests is: inherited member types are visible as a potential superclass. inherited interfaces are not visible when defining a superinterface. Error recovery story: ensure the superclass is set to java.lang.Object if a problem is detected resolving the superclass. Answer false if an error was reported against the sourceType. */ private boolean connectSuperclass() { SourceTypeBinding sourceType = getReferenceBinding(); if (sourceType.id == T_JavaLangObject) { // handle the case of redefining java.lang.Object up front sourceType.superclass = null; return true; // do not propagate Object's hierarchy problems down to every subtype } if ( (referenceContext!=null && referenceContext.superclass == null) || (inferredType!=null && inferredType.superClass==null)) { sourceType.superclass = getJavaLangObject(); return !detectHierarchyCycle(sourceType, sourceType.superclass, null); } if (referenceContext!=null) { TypeReference superclassRef = referenceContext.superclass; ReferenceBinding superclass = findSupertype(superclassRef); if (superclass != null) { // is null if a cycle was detected cycle or a problem // only want to reach here when no errors are reported sourceType.superclass = superclass; return true; } } else { ReferenceBinding superclass = findInferredSupertype(inferredType); if (superclass != null) { // is null if a cycle was detected cycle or a problem // only want to reach here when no errors are reported sourceType.superclass = superclass; if (superclass.isValidBinding()) return true; } } sourceType.tagBits |= TagBits.HierarchyHasProblems; sourceType.superclass = getJavaLangObject(); if ((sourceType.superclass.tagBits & TagBits.BeginHierarchyCheck) == 0) detectHierarchyCycle(sourceType, sourceType.superclass, null); return false; // reported some error against the source type } /** * <p>Iterate through all of the inferred types mixed in types and "mixin" the fields * and methods from the mixed in types into this scopes inferred type.</p> * * <p>NOTE: this can only successfully be done when all inference is done.</p> * * @return <code>true</code> if no problems occurred, <code>false</code> otherwise */ protected boolean connectMixins() { SourceTypeBinding sourceType = this.inferredType.binding; if (sourceType.id == T_JavaLangObject) // already handled the case of redefining java.lang.Object return true; if (this.inferredType.mixins==null || this.inferredType.mixins.isEmpty()) return true; boolean noProblems = true; int length = this.inferredType.mixins.size(); nextExtends : for (int i = 0; i < length; i++) { char []mixinsName=(char [])this.inferredType.mixins.get(i); ReferenceBinding mixinBinding = (ReferenceBinding)this.getType(mixinsName); if (mixinBinding == null) { // detected cycle sourceType.tagBits |= TagBits.HierarchyHasProblems; noProblems = false; continue nextExtends; } //loop through the nextTypes of the mixinBinding because each contains a partial inferred type while(mixinBinding != null) { // get the partial inferred type InferredType mixinInferredType = mixinBinding.getInferredType(); if(mixinInferredType !=null) { InferredAttribute[] attributes = mixinInferredType.attributes; ArrayList methods = mixinInferredType.methods; if(methods == null) methods = new ArrayList(1); // get the full list of methods and attributes from the mix class and its super class InferredType mixSuperType = mixinInferredType.superClass; while(mixSuperType != null && !CharOperation.equals(mixSuperType.getName(), "Object".toCharArray())) { //$NON-NLS-1$ // attributes InferredAttribute[] tempAttributes = new InferredAttribute[attributes.length + mixSuperType.attributes.length]; System.arraycopy(attributes, 0, tempAttributes, 0, attributes.length); System.arraycopy(mixSuperType.attributes, 0, tempAttributes, attributes.length - 1, mixSuperType.attributes.length); attributes = tempAttributes; // methods if (mixSuperType.methods != null) methods.addAll(mixSuperType.methods); mixSuperType = mixSuperType.superClass; } // add attributes to the type for(int a = 0; a < attributes.length; a++) { if(attributes[a] != null) { InferredAttribute attr = this.inferredType.findAttribute( attributes[a].name ); if(attr == null || attr.type == null) { attr = this.inferredType.addAttribute( attributes[a].name, attributes[a].node , attributes[a].nameStart); attr.type=attributes[a].type; attr.isStatic = false; attr.nameStart = attributes[a].nameStart; } } } // add methods to the type for(int m = 0; m < methods.size(); m++) { if(!((InferredMethod)methods.get(m)).isConstructor) { InferredMethod method = this.inferredType.findMethod(((InferredMethod)methods.get(m)).name, null); //ignore if the attribute exists and has a type if(method == null) { method = this.inferredType.addMethod(((InferredMethod)methods.get(m)).name, ((InferredMethod)methods.get(m)).getFunctionDeclaration(),((InferredMethod)methods.get(m)).nameStart); method.isStatic=false; } } } } //get the next partial source type for this 'mixin' if(mixinBinding instanceof SourceTypeBinding) { mixinBinding = ((SourceTypeBinding)mixinBinding).nextType; } else { mixinBinding = null; } } } return noProblems; } void connectTypeHierarchy() { SourceTypeBinding sourceType = getReferenceBinding(); if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) == 0) { sourceType.tagBits |= TagBits.BeginHierarchyCheck; boolean noProblems = connectSuperclass(); noProblems &= connectMixins(); //noProblems &= connectSuperInterfaces(); sourceType.tagBits |= TagBits.EndHierarchyCheck; // noProblems &= connectTypeVariables(referenceContext.typeParameters, false); if (noProblems && sourceType.isHierarchyInconsistent()) problemReporter().hierarchyHasProblems(sourceType); } connectMemberTypes(); LookupEnvironment env = environment(); try { env.missingClassFileLocation = referenceContext; checkForInheritedMemberTypes(sourceType); } catch (AbortCompilation e) { e.updateContext(referenceContext, referenceCompilationUnit().compilationResult); throw e; } finally { env.missingClassFileLocation = null; } } private void connectTypeHierarchyWithoutMembers() { // must ensure the imports are resolved if (parent instanceof CompilationUnitScope) { if (((CompilationUnitScope) parent).imports == null) ((CompilationUnitScope) parent).checkAndSetImports(); } else if (parent instanceof ClassScope) { // ensure that the enclosing type has already been checked ((ClassScope) parent).connectTypeHierarchyWithoutMembers(); } // double check that the hierarchy search has not already begun... SourceTypeBinding sourceType = getReferenceBinding(); if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) != 0) return; sourceType.tagBits |= TagBits.BeginHierarchyCheck; boolean noProblems = connectSuperclass(); noProblems &= connectMixins(); // noProblems &= connectSuperInterfaces(); sourceType.tagBits |= TagBits.EndHierarchyCheck; // noProblems &= connectTypeVariables(referenceContext.typeParameters, false); if (noProblems && sourceType.isHierarchyInconsistent()) problemReporter().hierarchyHasProblems(sourceType); } public boolean detectHierarchyCycle(TypeBinding superType, TypeReference reference) { if (!(superType instanceof ReferenceBinding)) return false; if (reference == this.superTypeReference) { // see findSuperType() // abstract class X<K,V> implements java.util.Map<K,V> // static abstract class M<K,V> implements Entry<K,V> compilationUnitScope().recordSuperTypeReference(superType); // to record supertypes return detectHierarchyCycle(getReferenceBinding(), (ReferenceBinding) superType, reference); } if ((superType.tagBits & TagBits.BeginHierarchyCheck) == 0 && superType instanceof SourceTypeBinding) // ensure if this is a source superclass that it has already been checked ((SourceTypeBinding) superType).classScope.connectTypeHierarchyWithoutMembers(); return false; } // Answer whether a cycle was found between the sourceType & the superType private boolean detectHierarchyCycle(SourceTypeBinding sourceType, ReferenceBinding superType, TypeReference reference) { // by this point the superType must be a binary or source type if (sourceType == superType) { problemReporter().hierarchyCircularity(sourceType, superType, reference); sourceType.tagBits |= TagBits.HierarchyHasProblems; return true; } if (superType.isMemberType()) { ReferenceBinding current = superType.enclosingType(); do { if (current.isHierarchyBeingConnected() && current == sourceType) { problemReporter().hierarchyCircularity(sourceType, current, reference); sourceType.tagBits |= TagBits.HierarchyHasProblems; current.tagBits |= TagBits.HierarchyHasProblems; return true; } } while ((current = current.enclosingType()) != null); } if (superType.isBinaryBinding()) { // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of: // - a binary type... this case MUST be caught & reported here // - another source type... this case is reported against the other source type boolean hasCycle = false; ReferenceBinding parentType = superType.superclass(); if (parentType != null) { if (sourceType == parentType) { problemReporter().hierarchyCircularity(sourceType, superType, reference); sourceType.tagBits |= TagBits.HierarchyHasProblems; superType.tagBits |= TagBits.HierarchyHasProblems; return true; } hasCycle |= detectHierarchyCycle(sourceType, parentType, reference); if ((parentType.tagBits & TagBits.HierarchyHasProblems) != 0) { sourceType.tagBits |= TagBits.HierarchyHasProblems; parentType.tagBits |= TagBits.HierarchyHasProblems; // propagate down the hierarchy } } return hasCycle; } if (superType.isHierarchyBeingConnected()) { org.eclipse.wst.jsdt.internal.compiler.ast.TypeReference ref = ((SourceTypeBinding) superType).classScope.superTypeReference; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=133071 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=121734 if (ref != null && (ref.resolvedType == null || ((ReferenceBinding) ref.resolvedType).isHierarchyBeingConnected())) { problemReporter().hierarchyCircularity(sourceType, superType, reference); sourceType.tagBits |= TagBits.HierarchyHasProblems; superType.tagBits |= TagBits.HierarchyHasProblems; return true; } } if ((superType.tagBits & TagBits.BeginHierarchyCheck) == 0) // ensure if this is a source superclass that it has already been checked ((SourceTypeBinding) superType).classScope.connectTypeHierarchyWithoutMembers(); if ((superType.tagBits & TagBits.HierarchyHasProblems) != 0) sourceType.tagBits |= TagBits.HierarchyHasProblems; return false; } private ReferenceBinding findInferredSupertype(InferredType type) { try { // typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes compilationUnitScope().recordQualifiedReference(new char[][]{type.superClass.getName()}); // this.superTypeReference = typeReference; ReferenceBinding superType = type.resolveSuperType(this); this.superTypeReference = null; return superType; } catch (AbortCompilation e) { e.updateContext(type, referenceCompilationUnit().compilationResult); throw e; } } private ReferenceBinding findSupertype(TypeReference typeReference) { CompilationUnitScope unitScope = compilationUnitScope(); LookupEnvironment env = unitScope.environment; try { env.missingClassFileLocation = typeReference; typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes unitScope.recordQualifiedReference(typeReference.getTypeName()); this.superTypeReference = typeReference; ReferenceBinding superType = (ReferenceBinding) typeReference.resolveSuperType(this); return superType; } catch (AbortCompilation e) { e.updateContext(typeReference, referenceCompilationUnit().compilationResult); throw e; } finally { env.missingClassFileLocation = null; this.superTypeReference = null; } } /* 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() { MethodScope outerMethodScope; if ((outerMethodScope = outerMostMethodScope()) == null) { ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; problemReporter.referenceContext = referenceContext; return problemReporter; } return outerMethodScope.problemReporter(); } /* Answer the reference type of this scope. * It is the nearest enclosing type of this scope. */ public TypeDeclaration referenceType() { return referenceContext; } public String toString() { if (referenceContext != null) return "--- Class Scope ---\n\n" //$NON-NLS-1$ + getReferenceBinding().toString(); return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$ } SourceTypeBinding buildInferredType(SourceTypeBinding enclosingType, PackageBinding packageBinding, AccessRestriction accessRestriction) { // provide the typeDeclaration with needed scopes inferredType.scope = this; if (enclosingType == null) { char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, inferredType.getName()); inferredType.binding = new SourceTypeBinding(className, packageBinding, this); //@GINO: Anonymous set bits if( inferredType.isAnonymous ) inferredType.binding.tagBits |= TagBits.AnonymousTypeMask; if( inferredType.isObjectLiteral ) inferredType.binding.tagBits |= TagBits.IsObjectLiteralType; } else { // char[][] className = CharOperation.deepCopy(enclosingType.compoundName); // className[className.length - 1] = // CharOperation.concat(className[className.length - 1], referenceContext.name, '$'); // referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); } SourceTypeBinding sourceType = inferredType.binding; LookupEnvironment environment = environment(); environment.setAccessRestriction(sourceType, accessRestriction); environment.defaultPackage.addType(sourceType); if (environment.defaultPackage != sourceType.fPackage) sourceType.fPackage.addType(sourceType); return sourceType; } }