| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Fraunhofer FIRST - extended API and implementation |
| * Technical University Berlin - extended API and implementation |
| * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for |
| * Bug 328281 - visibility leaks not detected when analyzing unused field in private class |
| * Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries |
| * Bug 354536 - compiling package-info.java still depends on the order of compilation units |
| * Bug 349326 - [1.7] new warning for missing try-with-resources |
| * Bug 358903 - Filter practically unimportant resource leak warnings |
| * Bug 395977 - [compiler][resource] Resource leak warning behavior possibly incorrect for anonymous inner class |
| * Bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. |
| * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables |
| * Bug 427199 - [1.8][resource] avoid resource leak warnings on Streams that have no resource |
| * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault |
| * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class |
| * Bug 444024 - [1.8][compiler][null] Type mismatch error in annotation generics assignment which happens "sometimes" |
| * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() |
| * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for |
| * Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes |
| * het@google.com - Bug 456986 - Bogus error when annotation processor generates annotation type |
| * Lars Vogel <Lars.Vogel@vogella.com> - Contributions for |
| * Bug 473178 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.lookup; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.core.compiler.IProblem; |
| import org.eclipse.jdt.internal.compiler.CompilationResult.CheckPoint; |
| import org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.Expression.DecapsulationState; |
| import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; |
| import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeParameter; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.env.AccessRestriction; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme; |
| import org.eclipse.jdt.internal.compiler.impl.IrritantSet; |
| import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; |
| import org.eclipse.jdt.internal.compiler.problem.IProblemRechecker; |
| import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; |
| import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; |
| import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; |
| import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeValueParameter; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.control.StateHelper; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutScope; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.OTClassScope; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleMigrationImplementor; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleSplitter; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.StandardElementGenerator; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.IAlienScopeTypeReference; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.Protections; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.Sorting; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.TSuperHelper; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer; |
| |
| /** |
| * OTDT changes: |
| * |
| * GENERAL: |
| * What: Additional setup: |
| * + Super-team linkage (connectSuperTeam() from connectAllSupers()) |
| * + Base-class linkage (connectBaseclass() from buildFieldsAndMethods()) |
| * + build method mappings (buildCallinCallouts() from buildFieldsAndMethods()) |
| * + setup RoleFileCache for team (from buildType()) |
| * |
| * What: Connect building of local type bindings with Dependencies. |
| * Why: Local types are found late, need to catch up in the translation process |
| * |
| * What: Do additional setup when linking referenceContext to its binding. |
| * How: Use TypeDeclaration.setBinding() instead of a direct assignment. |
| * |
| * What: Create OTClassScope for nested teams. |
| * Why: While nested teams are member types (not created by CompilationUnitScope) |
| * they still need a specialized scope. |
| * |
| * What: Add generated elements (addGenerated{Type,Field,Method}()) |
| * These methods create (unresolved) bindings. |
| * |
| * What: Public entries for connecting generated elements |
| * Which: + connectTypeHierarchyForGenerated() |
| * + connectSuperclassForGenerated() |
| * + buildFieldsAndMethodsForGenerated() |
| * |
| * ROLE FILES: |
| * What: Add member types also to the enclosing team-package |
| * |
| * What: Manipulate order of processing for role files. |
| * Why: Establishing STATE_BINDINGS_COMPLETE may trigger introduction of role files. |
| * Compiler.accept will try to complete these which conflicts with the current process. |
| * How: + TypeModel._currentlyProcessedState and TeamModel._blockCatchup |
| * capture the state of processing |
| * + buildFieldsAndMethods() and connectTypeHierarchy() bail out during blockCatchup |
| * + traversing members in buildFieldsAndMethods() and connectMemberTypes() |
| * include newly introduces role files within their loops. |
| * |
| * VALIDITY: |
| * What: Allow interfaces in nested teams. |
| * |
| * What: Flags/modifiers: |
| * + check for role / team modifiers |
| * + accept AccRole and AccSynthetic |
| * + accept AccProtected for roles in role files |
| * Why: top level types cannot be protected, but role files are not top-level ;-) |
| * |
| * What: Team.Confined must not have a superclass. |
| * |
| * What: Team must not extend non-team and vice versa. |
| * |
| * LOOKUP: |
| * What: if findSupertype() failed, consider dropping __OT__ |
| * Why: RoleSplitter might have been over-eager. |
| * How: need to roll back: remove problem binding, remove IProblem. |
| */ |
| @SuppressWarnings({"rawtypes"}) |
| public class ClassScope extends Scope { |
| |
| public TypeDeclaration referenceContext; |
| public TypeReference superTypeReference; |
| java.util.ArrayList<Object> deferredBoundChecks; // contains TypeReference or Runnable. TODO consider making this a List<Runnable> |
| |
| public ClassScope(Scope parent, TypeDeclaration context) { |
| super(Scope.CLASS_SCOPE, parent); |
| this.referenceContext = context; |
| this.deferredBoundChecks = null; // initialized if required |
| } |
| |
| void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) { |
| LocalTypeBinding anonymousType = buildLocalType(enclosingType, enclosingType.fPackage); |
| anonymousType.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; // tag all anonymous types as used locally |
| int inheritedBits = supertype.typeBits; // for anonymous class assume same properties as its super (as a closeable) ... |
| // ... unless it overrides close(): |
| if ((inheritedBits & TypeIds.BitWrapperCloseable) != 0) { |
| AbstractMethodDeclaration[] methods = this.referenceContext.methods; |
| if (methods != null) { |
| for (int i=0; i<methods.length; i++) { |
| if (CharOperation.equals(TypeConstants.CLOSE, methods[i].selector) && methods[i].arguments == null) { |
| inheritedBits &= TypeIds.InheritableBits; |
| break; |
| } |
| } |
| } |
| } |
| anonymousType.typeBits |= inheritedBits; |
| if (supertype.isInterface()) { |
| anonymousType.setSuperClass(getJavaLangObject()); |
| anonymousType.setSuperInterfaces(new ReferenceBinding[] { supertype }); |
| TypeReference typeReference = this.referenceContext.allocation.type; |
| if (typeReference != null) { |
| this.referenceContext.superInterfaces = new TypeReference[] { typeReference }; |
| if ((supertype.tagBits & TagBits.HasDirectWildcard) != 0) { |
| problemReporter().superTypeCannotUseWildcard(anonymousType, typeReference, supertype); |
| anonymousType.tagBits |= TagBits.HierarchyHasProblems; |
| anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); |
| } |
| } |
| } else { |
| anonymousType.setSuperClass(supertype); |
| anonymousType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); |
| TypeReference typeReference = this.referenceContext.allocation.type; |
| if (typeReference != null) { // no check for enum constant body |
| this.referenceContext.superclass = typeReference; |
| if (supertype.erasure().id == TypeIds.T_JavaLangEnum) { |
| problemReporter().cannotExtendEnum(anonymousType, typeReference, supertype); |
| anonymousType.tagBits |= TagBits.HierarchyHasProblems; |
| anonymousType.setSuperClass(getJavaLangObject()); |
| } else if (supertype.isFinal()) { |
| problemReporter().anonymousClassCannotExtendFinalClass(typeReference, supertype); |
| anonymousType.tagBits |= TagBits.HierarchyHasProblems; |
| anonymousType.setSuperClass(getJavaLangObject()); |
| } else if ((supertype.tagBits & TagBits.HasDirectWildcard) != 0) { |
| problemReporter().superTypeCannotUseWildcard(anonymousType, typeReference, supertype); |
| anonymousType.tagBits |= TagBits.HierarchyHasProblems; |
| anonymousType.setSuperClass(getJavaLangObject()); |
| } |
| } |
| } |
| connectMemberTypes(); |
| buildFieldsAndMethods(); |
| //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies): |
| if (this.referenceContext.isRole()) { |
| RoleModel role = this.referenceContext.getRoleModel(); |
| Dependencies.ensureRoleState(role, ITranslationStates.STATE_FAULT_IN_TYPES-1); |
| /*orig*/anonymousType.faultInTypesForFieldsAndMethods(); |
| Dependencies.ensureRoleState(role, ITranslationStates.STATE_METHODS_VERIFIED-1); |
| } else { |
| // orig: |
| anonymousType.faultInTypesForFieldsAndMethods(); |
| // :giro |
| } |
| // SH} |
| anonymousType.verifyMethods(environment().methodVerifier()); |
| } |
| |
| void buildFields() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (sourceType.areFieldsInitialized()) return; |
| //{ObjectTeams: prepare for merging value parameters into fields: |
| int valueParamCount = valueParamCount(this.referenceContext.typeParameters); |
| if (this.referenceContext.fields == null && valueParamCount > 0) |
| this.referenceContext.fields = new FieldDeclaration[0]; |
| // SH} |
| if (this.referenceContext.fields == null) { |
| sourceType.setFields(Binding.NO_FIELDS); |
| return; |
| } |
| // count the number of fields vs. initializers |
| FieldDeclaration[] fields = this.referenceContext.fields; |
| int size = fields.length; |
| //{ObjectTeams: value parameters: |
| /* orig: |
| int count = 0; |
| */ |
| int count = valueParamCount; |
| // SH} |
| for (int i = 0; i < size; i++) { |
| switch (fields[i].getKind()) { |
| case AbstractVariableDeclaration.FIELD: |
| case AbstractVariableDeclaration.ENUM_CONSTANT: |
| count++; |
| } |
| } |
| |
| // iterate the field declarations to create the bindings, lose all duplicates |
| FieldBinding[] fieldBindings = new FieldBinding[count]; |
| HashtableOfObject knownFieldNames = new HashtableOfObject(count); |
| //{ObjectTeams: add fields from value parameters |
| if (this.referenceContext.typeParameters != null) { |
| TypeValueParameter.resolveValueParameters(this.referenceContext.typeParameters, this, fieldBindings, knownFieldNames); |
| count = valueParamCount; |
| } else |
| // SH} |
| count = 0; |
| for (int i = 0; i < size; i++) { |
| FieldDeclaration field = fields[i]; |
| if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) { |
| // We used to report an error for initializers declared inside interfaces, but |
| // now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713 |
| } else { |
| FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType); |
| fieldBinding.id = count; |
| // field's type will be resolved when needed for top level types |
| checkAndSetModifiersForField(fieldBinding, field); |
| |
| if (knownFieldNames.containsKey(field.name)) { |
| 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(sourceType, previousField); |
| break; |
| } |
| } |
| } |
| knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed |
| problemReporter().duplicateFieldInType(sourceType, 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 (count != fieldBindings.length) |
| System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count); |
| sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type |
| sourceType.setFields(fieldBindings); |
| } |
| |
| //{ObjectTeams: helper for the above |
| private int valueParamCount(TypeParameter[] typeParameters) { |
| int count = 0; |
| if (typeParameters != null) |
| for (int i = 0; i < typeParameters.length; i++) |
| if (typeParameters[i] instanceof TypeValueParameter) |
| count++; |
| |
| return count; |
| } |
| // SH} |
| |
| void buildFieldsAndMethods() { |
| //{ObjectTeams: signal proccessing: |
| if (!StateHelper.startProcessing(this.referenceContext, |
| ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS, |
| LookupEnvironment.BUILD_FIELDS_AND_METHODS)) |
| return; // catchup was blocked. |
| // SH} |
| buildFields(); |
| buildMethods(); |
| //{ObjectTeams: build callins and callouts |
| buildCallinCallouts(); |
| // now, as we have field bindings, connect baseclass (which might depend on a field as anchor): |
| connectBaseclass(); |
| // Markus Witte} |
| |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (!sourceType.isPrivate() && sourceType.superclass instanceof SourceTypeBinding && sourceType.superclass.isPrivate()) |
| ((SourceTypeBinding) sourceType.superclass).tagIndirectlyAccessibleMembers(); |
| |
| if (sourceType.isMemberType() && !sourceType.isLocalType()) |
| ((MemberTypeBinding) sourceType).checkSyntheticArgsAndFields(); |
| |
| //{ObjectTeams: similar for value parameters: |
| if (this.referenceContext.typeParameters != null) { |
| TypeParameter[] typeParameters = this.referenceContext.typeParameters; |
| for (int i = 0; i < typeParameters.length; i++) { |
| if (typeParameters[i] instanceof TypeValueParameter) { |
| TypeValueParameter param = (TypeValueParameter)typeParameters[i]; |
| sourceType.addSyntheticArgForValParam(param); |
| } |
| } |
| // 2. go: type anchors may refer to value parameters (connected above) |
| for (int i = 0; i < typeParameters.length; i++) { |
| if (!(typeParameters[i] instanceof TypeValueParameter)) |
| typeParameters[i].connectTypeAnchors(this); |
| } |
| } |
| // SH} |
| //{ObjectTeams: don't cache member types/length, new role files might be added during the loop: |
| /* Orig: |
| ReferenceBinding[] memberTypes = sourceType.memberTypes; |
| for (int i = 0, length = memberTypes.length; i < length; i++) |
| :giro */ |
| for (int i = 0; i < sourceType.memberTypes.length; i++) { |
| ReferenceBinding memberType = sourceType.memberTypes[i]; |
| |
| //addition: roles can be binary! or already compiled along some other path |
| if ( !memberType.isBinaryBinding() |
| && !StateHelper.hasState(memberType, ITranslationStates.STATE_FINAL)) |
| /* orig: |
| ((SourceTypeBinding) memberTypes[i]).scope.buildFieldsAndMethods(); |
| :giro */ |
| ((SourceTypeBinding) memberType).scope.buildFieldsAndMethods(); |
| } |
| // SH} |
| } |
| |
| private LocalTypeBinding buildLocalType(SourceTypeBinding enclosingType, PackageBinding packageBinding) { |
| |
| this.referenceContext.scope = this; |
| this.referenceContext.staticInitializerScope = new MethodScope(this, this.referenceContext, true); |
| this.referenceContext.initializerScope = new MethodScope(this, this.referenceContext, false); |
| |
| // build the binding or the local type |
| LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType, innermostSwitchCase()); |
| //{ObjectTeams: was assignment; use setter to allow additional setup |
| /* @original |
| this.referenceContext.binding = localType; |
| */ |
| this.referenceContext.setBinding(localType); |
| // SH} |
| checkAndSetModifiers(); |
| buildTypeVariables(); |
| |
| // Look at member types |
| ReferenceBinding[] memberTypeBindings = Binding.NO_MEMBER_TYPES; |
| if (this.referenceContext.memberTypes != null) { |
| int size = this.referenceContext.memberTypes.length; |
| memberTypeBindings = new ReferenceBinding[size]; |
| int count = 0; |
| nextMember : for (int i = 0; i < size; i++) { |
| TypeDeclaration memberContext = this.referenceContext.memberTypes[i]; |
| switch(TypeDeclaration.kind(memberContext.modifiers)) { |
| case TypeDeclaration.INTERFACE_DECL : |
| case TypeDeclaration.ANNOTATION_TYPE_DECL : |
| problemReporter().illegalLocalTypeDeclaration(memberContext); |
| continue nextMember; |
| } |
| ReferenceBinding type = localType; |
| // check that the member does not conflict with an enclosing type |
| do { |
| if (CharOperation.equals(type.sourceName, memberContext.name)) { |
| problemReporter().typeCollidesWithEnclosingType(memberContext); |
| 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(this.referenceContext.memberTypes[j].name, memberContext.name)) { |
| problemReporter().duplicateNestedType(memberContext); |
| continue nextMember; |
| } |
| } |
| ClassScope memberScope = new ClassScope(this, 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.setMemberTypes(memberTypeBindings); |
| return localType; |
| } |
| |
| void buildLocalTypeBinding(SourceTypeBinding enclosingType) { |
| |
| LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage); |
| connectTypeHierarchy(); |
| if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { |
| checkParameterizedTypeBounds(); |
| checkParameterizedSuperTypeCollisions(); |
| } |
| buildFieldsAndMethods(); |
| //{ObjectTeams: catchup also in OT-specific process (see class comment concerning local types in Dependencies). |
| if (this.referenceContext.isRole()) { |
| RoleModel role = this.referenceContext.getRoleModel(); |
| Dependencies.ensureRoleState(role, ITranslationStates.STATE_FAULT_IN_TYPES-1); |
| /*orig*/localType.faultInTypesForFieldsAndMethods(); |
| Dependencies.ensureRoleState(role, ITranslationStates.STATE_METHODS_VERIFIED-1); |
| } else { |
| // orig: |
| localType.faultInTypesForFieldsAndMethods(); |
| // :giro |
| } |
| // SH} |
| |
| this.referenceContext.binding.verifyMethods(environment().methodVerifier()); |
| } |
| |
| private void buildMemberTypes(AccessRestriction accessRestriction) { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| ReferenceBinding[] memberTypeBindings = Binding.NO_MEMBER_TYPES; |
| if (this.referenceContext.memberTypes != null) { |
| int length = this.referenceContext.memberTypes.length; |
| memberTypeBindings = new ReferenceBinding[length]; |
| int count = 0; |
| nextMember : for (int i = 0; i < length; i++) { |
| TypeDeclaration memberContext = this.referenceContext.memberTypes[i]; |
| if (this.environment().root.isProcessingAnnotations && this.environment().isMissingType(memberContext.name)) { |
| throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the type |
| } |
| switch(TypeDeclaration.kind(memberContext.modifiers)) { |
| case TypeDeclaration.INTERFACE_DECL : |
| case TypeDeclaration.ANNOTATION_TYPE_DECL : |
| if (sourceType.isNestedType() |
| && sourceType.isClass() // no need to check for enum, since implicitly static |
| //{ObjectTeams: check for team (may indeed contain interface): |
| && !sourceType.isTeam() |
| // SH} |
| && !sourceType.isStatic()) { |
| problemReporter().illegalLocalTypeDeclaration(memberContext); |
| continue nextMember; |
| } |
| break; |
| } |
| ReferenceBinding type = sourceType; |
| // check that the member does not conflict with an enclosing type |
| do { |
| if (CharOperation.equals(type.sourceName, memberContext.name)) { |
| problemReporter().typeCollidesWithEnclosingType(memberContext); |
| //{ObjectTeams: tagging the type should suffice, keep going (otherwise breaks B.1.1-otjld-sh-15) |
| break; |
| /* orig: |
| continue nextMember; |
| :giro */ |
| // SH} |
| } |
| 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(this.referenceContext.memberTypes[j].name, memberContext.name)) { |
| problemReporter().duplicateNestedType(memberContext); |
| continue nextMember; |
| } |
| } |
| |
| //{ObjectTeams: what kind of scope is needed? |
| /* orig: |
| ClassScope memberScope = new ClassScope(this, memberContext); |
| :giro */ |
| ClassScope memberScope = memberContext.isTeam() ? // only for teams, no OTClassScope for inline roles. |
| OTClassScope.createMemberOTClassScope(this, memberContext) : |
| new ClassScope(this, memberContext); |
| // SH} |
| memberTypeBindings[count++] = memberScope.buildType(sourceType, sourceType.fPackage, accessRestriction); |
| } |
| if (count != length) |
| System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count); |
| } |
| sourceType.setMemberTypes(memberTypeBindings); |
| } |
| |
| void buildMethods() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (sourceType.areMethodsInitialized()) return; |
| |
| boolean isEnum = TypeDeclaration.kind(this.referenceContext.modifiers) == TypeDeclaration.ENUM_DECL; |
| if (this.referenceContext.methods == null && !isEnum) { |
| this.referenceContext.binding.setMethods(Binding.NO_METHODS); |
| return; |
| } |
| |
| // iterate the method declarations to create the bindings |
| AbstractMethodDeclaration[] methods = this.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 = isEnum ? 2 : 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 |
| 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 |
| boolean hasNativeMethods = false; |
| if (sourceType.isAbstract()) { |
| for (int i = 0; i < size; i++) { |
| if (i != clinitIndex) { |
| //{ObjectTeams: Twisted scope for methods moved from a role to its team: |
| /* orig: |
| MethodScope scope = new MethodScope(this, methods[i], false); |
| :giro */ |
| MethodScope scope = createMethodScope(methods[i]); |
| // SH} |
| MethodBinding methodBinding = scope.createMethod(methods[i]); |
| if (methodBinding != null) { // is null if binding could not be created |
| methodBindings[count++] = methodBinding; |
| hasNativeMethods = hasNativeMethods || methodBinding.isNative(); |
| } |
| } |
| } |
| } else { |
| boolean hasAbstractMethods = false; |
| for (int i = 0; i < size; i++) { |
| if (i != clinitIndex) { |
| //{ObjectTeams: Twisted scope for methods moved from a role to its team: |
| /* orig: |
| MethodScope scope = new MethodScope(this, methods[i], false); |
| :giro */ |
| MethodScope scope = createMethodScope(methods[i]); |
| // SH} |
| MethodBinding methodBinding = scope.createMethod(methods[i]); |
| if (methodBinding != null) { // is null if binding could not be created |
| methodBindings[count++] = methodBinding; |
| hasAbstractMethods = hasAbstractMethods || methodBinding.isAbstract(); |
| hasNativeMethods = hasNativeMethods || methodBinding.isNative(); |
| } |
| } |
| } |
| if (hasAbstractMethods) |
| //{ObjectTeams: support rechecking, because callout implementation might remove abstractness: |
| { |
| if (sourceType.isDirectRole()) |
| problemReporter() |
| .setRechecker(new IProblemRechecker() { @Override |
| public boolean shouldBeReported(IrritantSet[] foundIrritants) { |
| for (MethodBinding methodBinding : ClassScope.this.referenceContext.binding.methods()) |
| if (methodBinding.isAbstract()) |
| return true; |
| return false; // false alarm |
| }}) |
| .abstractMethodInConcreteClass(sourceType); |
| else |
| // orig: |
| problemReporter().abstractMethodInConcreteClass(sourceType); |
| // :giro |
| } |
| // SH} |
| } |
| if (count != methodBindings.length) |
| System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count); |
| sourceType.tagBits &= ~(TagBits.AreMethodsSorted|TagBits.AreMethodsComplete); // in case some static imports reached already into this type |
| sourceType.setMethods(methodBindings); |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=243917, conservatively tag all methods and fields as |
| // being in use if there is a native method in the class. |
| if (hasNativeMethods) { |
| for (int i = 0; i < methodBindings.length; i++) { |
| methodBindings[i].modifiers |= ExtraCompilerModifiers.AccLocallyUsed; |
| } |
| FieldBinding[] fields = sourceType.unResolvedFields(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=301683 |
| for (int i = 0; i < fields.length; i++) { |
| fields[i].modifiers |= ExtraCompilerModifiers.AccLocallyUsed; |
| } |
| } |
| if (isEnum && compilerOptions().isAnnotationBasedNullAnalysisEnabled) { |
| // mark return types of values & valueOf as nonnull (needed to wait till after setMethods() to avoid reentrance): |
| LookupEnvironment environment = this.environment(); |
| ((SyntheticMethodBinding)methodBindings[0]).markNonNull(environment); |
| ((SyntheticMethodBinding)methodBindings[1]).markNonNull(environment); |
| } |
| } |
| |
| //{ObjectTeams: accessible to sub-class: |
| protected |
| // SH} |
| SourceTypeBinding buildType(SourceTypeBinding enclosingType, PackageBinding packageBinding, AccessRestriction accessRestriction) { |
| // provide the typeDeclaration with needed scopes |
| this.referenceContext.scope = this; |
| this.referenceContext.staticInitializerScope = new MethodScope(this, this.referenceContext, true); |
| this.referenceContext.initializerScope = new MethodScope(this, this.referenceContext, false); |
| |
| //{ObjectTeams: ROFI: |
| boolean isRoleFile = false; |
| //SH} |
| |
| if (enclosingType == null) { |
| char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, this.referenceContext.name); |
| //{ObjectTeams: was assignment; use setter to allow additional setup: |
| /* @original |
| this.referenceContext.binding = new SourceTypeBinding(className, packageBinding, this); |
| */ |
| this.referenceContext.setBinding(new SourceTypeBinding(className, packageBinding, this)); |
| // SH} |
| } else { |
| //{ObjectTeams: ROFI: |
| isRoleFile = enclosingType.teamPackage != null; |
| // SH} |
| char[][] className = CharOperation.deepCopy(enclosingType.compoundName); |
| className[className.length - 1] = |
| CharOperation.concat(className[className.length - 1], this.referenceContext.name, '$'); |
| if (packageBinding.hasType0Any(className[className.length - 1])) { |
| // report the error against the parent - its still safe to answer the member type |
| //{ObjectTeams: role files are handled below: |
| if (!isRoleFile) |
| //SH} |
| this.parent.problemReporter().duplicateNestedType(this.referenceContext); |
| } |
| //{ObjectTeams: was assignment; use setter to allow additional setup: |
| /* @original |
| this.referenceContext.binding = new MemberTypeBinding(className, this, enclosingType); |
| */ |
| this.referenceContext.setBinding(new MemberTypeBinding(className, this, enclosingType)); |
| // SH} |
| } |
| |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| sourceType.module = module(); |
| environment().setAccessRestriction(sourceType, accessRestriction); |
| |
| TypeParameter[] typeParameters = this.referenceContext.typeParameters; |
| sourceType.typeVariables = typeParameters == null || typeParameters.length == 0 ? Binding.NO_TYPE_VARIABLES : null; |
| sourceType.fPackage.addType(sourceType); |
| //{ObjectTeams: ROFI |
| if (isRoleFile) { |
| // role types should be found also in the corresponding team package: |
| enclosingType.teamPackage.addType(sourceType); |
| // check duplicates: |
| if (this.referenceContext.compilationUnit != null) // non-ROFI is analyzed below |
| { |
| TypeDeclaration[] memberTypes = this.parent.referenceType().memberTypes; |
| for (int i = 0; i < memberTypes.length; i++) { |
| if ( CharOperation.equals(memberTypes[i].name, this.referenceContext.name) |
| && TypeBinding.notEquals(memberTypes[i].binding, sourceType)) |
| { |
| // mark the existing type (first in list of member types), |
| // because ReferenceBinding.getMemberType() prefers elements |
| // towards the end of the array, wouldn't want to continue |
| // working with the type marked erroneous. |
| |
| // report only for interface part, has the nicer name ;-) |
| if (this.referenceContext.isInterface()) |
| // while marking existing type still use this type's positions. |
| problemReporter().duplicateNestedType(memberTypes[i], this.referenceContext.sourceStart, this.referenceContext.sourceEnd); |
| else |
| memberTypes[i].tagAsHavingErrors(); |
| break; |
| } |
| } |
| } |
| } |
| if (TypeAnalyzer.isOrgObjectteamsTeam(sourceType)) {// handle the case of compiling org.objectteams.Team up front |
| this.referenceContext.adjustOrgObjectteamsTeam(); |
| this.environment().getTeamMethodGenerator().registerOOTeamClass(sourceType); |
| } |
| // SH} |
| checkAndSetModifiers(); |
| buildTypeVariables(); |
| |
| buildMemberTypes(accessRestriction); |
| //{ObjectTeams: setup cache for known role files: |
| if (this.referenceContext.isTeam()) |
| this.referenceContext.getTeamModel().setupRoFiCache(this, environment()); |
| // SH} |
| return sourceType; |
| } |
| |
| private void buildTypeVariables() { |
| |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| TypeParameter[] typeParameters = this.referenceContext.typeParameters; |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850, If they exist at all, process type parameters irrespective of source level. |
| if (typeParameters == null || typeParameters.length == 0) { |
| sourceType.setTypeVariables(Binding.NO_TYPE_VARIABLES); |
| return; |
| } |
| sourceType.setTypeVariables(Binding.NO_TYPE_VARIABLES); // safety |
| |
| if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front |
| problemReporter().objectCannotBeGeneric(this.referenceContext); |
| return; |
| } |
| //{ObjectTeams: remove type value parameters |
| typeParameters = filterTypeValueVariables(typeParameters); |
| if (typeParameters.length == 0) |
| return; // consumed all parameters |
| // SH} |
| sourceType.setTypeVariables(createTypeVariables(typeParameters, sourceType)); |
| sourceType.modifiers |= ExtraCompilerModifiers.AccGenericSignature; |
| } |
| |
| //{ObjectTeams: build additional structural elements |
| /** |
| * @param typeParameters all type parameters perhaps including type value parameters. |
| * @return remaining unconsumed type parameters. |
| */ |
| private TypeParameter[] filterTypeValueVariables(TypeParameter[] typeParameters) |
| { |
| int count = 0; |
| TypeParameter[] filteredParams = new TypeParameter[typeParameters.length]; |
| for (int i = 0; i < typeParameters.length; i++) { |
| if (!(typeParameters[i] instanceof TypeValueParameter)) |
| filteredParams[count++] = typeParameters[i]; |
| } |
| if (count < typeParameters.length) { |
| TypeParameter[] remainder = new TypeParameter[count]; |
| System.arraycopy(filteredParams, 0, remainder, 0, count); |
| return remainder; |
| } |
| return typeParameters; |
| } |
| /** |
| * build Callin and Callout |
| */ |
| public void buildCallinCallouts() { |
| if (this.referenceContext.callinCallouts == null) { |
| this.referenceContext.binding.callinCallouts = Binding.NO_CALLIN_CALLOUT_BINDINGS; |
| return; |
| } |
| |
| if (!this.referenceContext.isSourceRole()) { |
| problemReporter().methodMappingNotInBoundRole(this.referenceContext.callinCallouts[0], this.referenceContext); |
| this.referenceContext.callinCallouts = null; |
| this.referenceContext.binding.callinCallouts = Binding.NO_CALLIN_CALLOUT_BINDINGS; |
| return; |
| } |
| |
| if (this.referenceContext.binding.callinCallouts != null) |
| return; // already done |
| |
| // iterate the binding declarations to create the bindings |
| AbstractMethodMappingDeclaration[] callinCallouts = this.referenceContext.callinCallouts; |
| int size = callinCallouts.length; |
| CallinCalloutBinding[] bindings = new CallinCalloutBinding[size]; |
| |
| int count = 0; |
| HashSet<String> labels = new HashSet<String>(); |
| for (int i = 0; i < size; i++) { |
| if (this.referenceContext.isInterface() && callinCallouts[i].mappings != null) { |
| problemReporter().paramMapInInterface(callinCallouts[i], this.referenceContext.binding); |
| continue; |
| } |
| |
| CallinCalloutScope scope = new CallinCalloutScope(this, callinCallouts[i]); |
| CallinCalloutBinding binding = scope.createBinding(callinCallouts[i]); |
| if (binding != null) // is null if binding could not be created |
| bindings[count++] = binding; |
| if (callinCallouts[i].isCallin()) { |
| CallinMappingDeclaration callinMapping = (CallinMappingDeclaration)callinCallouts[i]; |
| if (callinMapping.name[0] != '<') { // generated name? |
| String label = String.valueOf(callinMapping.name); |
| if (!labels.contains(label)) |
| labels.add(label); |
| else |
| scope.problemReporter().duplicateCallinName(callinMapping); |
| } |
| } |
| } |
| if (count != bindings.length) |
| System.arraycopy(bindings, 0, bindings = new CallinCalloutBinding[count], 0, count); |
| this.referenceContext.binding.callinCallouts = bindings; |
| this.referenceContext.binding.modifiers |= ExtraCompilerModifiers.AccUnresolved; // until methods() is sent |
| } |
| |
| public void addGeneratedType (TypeDeclaration memberTypeDeclaration) |
| { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| |
| // FIXME(SH): if memberType is a team, don't we need an OTClassScope? |
| ClassScope memberScope = new ClassScope(this, memberTypeDeclaration); |
| if ((memberTypeDeclaration.bits & ASTNode.IsLocalType) != 0) |
| { |
| // not added to member types |
| memberScope.buildLocalType(sourceType, getCurrentPackage()); |
| // ensure the copy has the same relative constant pool name (e.g., "1" as in T$__OT__R$1) |
| char[] computedConstantPoolName = CharOperation.concatWith( |
| new char[][]{sourceType.constantPoolName(), memberTypeDeclaration.name}, '$'); |
| LocalTypeBinding localTypeBinding = (LocalTypeBinding)memberTypeDeclaration.binding; |
| localTypeBinding.setConstantPoolName(computedConstantPoolName); |
| referenceCompilationUnit().record(localTypeBinding); |
| } else { |
| assert (this.referenceContext.memberTypes != null); |
| |
| // build the binding: |
| SourceTypeBinding newBinding; |
| if (memberTypeDeclaration.isRoleFile()) { |
| memberScope.environment().internalBuildTypeBindings(memberTypeDeclaration.compilationUnit, null); |
| newBinding= memberTypeDeclaration.binding; |
| } else { |
| newBinding= memberScope.buildType(sourceType, getCurrentPackage(), /*accessRestriction*/null); |
| } |
| |
| // search for an equal but binary type binding: |
| int size = sourceType.memberTypes.length; |
| for (int i=0; i<size; i++) { |
| ReferenceBinding member = sourceType.memberTypes[i]; |
| if ( member.isBinaryBinding() |
| && CharOperation.equals(member.compoundName, newBinding.compoundName)) |
| { |
| sourceType.memberTypes[i] = newBinding; // found, simply replace |
| return; |
| } |
| } |
| |
| if (!memberTypeDeclaration.isRoleFile()) { // otherwise OTClassScope.buildType() did this. |
| // need to actually add: |
| ReferenceBinding[] newMembers = new ReferenceBinding[size+1]; |
| System.arraycopy(sourceType.memberTypes, 0, newMembers, 0, size); |
| newMembers[size]= newBinding; |
| sourceType.setMemberTypes(newMembers); |
| } |
| } |
| } |
| |
| public FieldBinding addGeneratedField(FieldDeclaration fieldDeclaration, boolean hasTypeProblem) { |
| |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (sourceType.model.getState() >= ITranslationStates.STATE_BYTE_CODE_PREPARED) |
| { |
| problemReporter().compilationOrderProblem("Too late to add a field", this.referenceContext); //$NON-NLS-1$ |
| return null; |
| } |
| // perform initialization according to buildFields() |
| FieldBinding fieldBinding = new FieldBinding( |
| fieldDeclaration, null, fieldDeclaration.modifiers|ExtraCompilerModifiers.AccUnresolved, sourceType); |
| |
| sourceType.addField(fieldBinding); |
| checkAndSetModifiersForField(fieldBinding, fieldDeclaration); |
| |
| // FIXME(SH): does this improve robustness? |
| // if ((sourceType.tagBits & TagBits.AreMethodsComplete) != 0) |
| // trigger resolveTypeFor(FieldBinding) |
| if (!hasTypeProblem) |
| sourceType.getField(fieldDeclaration.name, true); |
| return fieldBinding; |
| } |
| |
| // TODO(SH): migrate clients to use SourceTypeBinding.addMethod() directly |
| public SourceTypeBinding addGeneratedMethod(MethodBinding methodBinding) |
| { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| sourceType.addMethod(methodBinding); |
| this.referenceContext.binding.modifiers |= ExtraCompilerModifiers.AccUnresolved; // until methods() is sent |
| return sourceType; |
| } |
| |
| MethodBinding createMethod(AbstractMethodDeclaration methodDecl) { |
| if (methodDecl.binding != null) |
| return methodDecl.binding; // nothing to do, observed on accessors for callout to private role field |
| MethodScope scope = createMethodScope(methodDecl); |
| return scope.createMethod(methodDecl); |
| } |
| |
| private MethodScope createMethodScope(AbstractMethodDeclaration methodDecl) { |
| MethodScope scope; |
| if (methodDecl.model != null && methodDecl.model._sourceDeclaringType != null) { |
| TypeDeclaration foreignType = methodDecl.model._sourceDeclaringType; |
| scope = new MethodScope(foreignType.scope, methodDecl, false) { |
| @Override |
| public TypeDeclaration referenceType() { |
| return ClassScope.this.referenceContext; |
| } |
| @Override |
| public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean denyEnclosingArgInConstructorCall) { |
| Scope parentSave = this.parent; |
| try { |
| this.parent = ClassScope.this; |
| return super.getEmulationPath(targetEnclosingType, onlyExactMatch, |
| denyEnclosingArgInConstructorCall); |
| } finally { |
| this.parent = parentSave; |
| } |
| } |
| }; |
| } else { |
| scope = new MethodScope(this, methodDecl, false); |
| } |
| return scope; |
| } |
| //Markus Witte} |
| |
| @Override |
| void resolveTypeParameter(TypeParameter typeParameter) { |
| typeParameter.resolve(this); |
| } |
| |
| private void checkAndSetModifiers() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| int modifiers = sourceType.modifiers; |
| if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) |
| problemReporter().duplicateModifierForType(sourceType); |
| ReferenceBinding enclosingType = sourceType.enclosingType(); |
| boolean isMemberType = sourceType.isMemberType(); |
| //{ObjectTeams: OT_CLASS_FLAGS attribute: |
| WordValueAttribute.maybeCreateClassFlagsAttribute(this.referenceContext); |
| // SH} |
| if (isMemberType) { |
| if (sourceType.hasEnclosingInstanceContext()) |
| modifiers |= (enclosingType.modifiers & ExtraCompilerModifiers.AccGenericSignature); |
| modifiers |= (enclosingType.modifiers & ClassFileConstants.AccStrictfp); |
| // checks for member types before local types to catch local members |
| if (enclosingType.isInterface()) |
| modifiers |= ClassFileConstants.AccPublic; |
| //{ObjectTeams: check for role / team modifiers |
| modifiers = Protections.checkRoleModifiers(modifiers, this.referenceContext, this); |
| // SH} |
| if (sourceType.isEnum()) { |
| if (!enclosingType.isStatic()) |
| problemReporter().nonStaticContextForEnumMemberType(sourceType); |
| else |
| modifiers |= ClassFileConstants.AccStatic; |
| } else if (sourceType.isInterface()) { |
| modifiers |= ClassFileConstants.AccStatic; // 8.5.1 |
| } |
| } else if (sourceType.isLocalType()) { |
| if (sourceType.isEnum()) { |
| problemReporter().illegalLocalTypeDeclaration(this.referenceContext); |
| sourceType.modifiers = 0; |
| //{ObjectTeams: if inside a role mark as role instead of enum (possible by very broken code only): |
| if (enclosingType.isRole()) { |
| sourceType.roleModel = this.referenceContext.getRoleModel(); |
| sourceType.roleModel.setBinding(sourceType); |
| } |
| // SH} |
| return; |
| } |
| if (sourceType.isAnonymousType()) { |
| if (compilerOptions().complianceLevel < ClassFileConstants.JDK9) |
| modifiers |= ClassFileConstants.AccFinal; |
| // set AccEnum flag for anonymous body of enum constants |
| if (this.referenceContext.allocation.type == null) |
| modifiers |= ClassFileConstants.AccEnum; |
| } |
| Scope scope = this; |
| do { |
| switch (scope.kind) { |
| case METHOD_SCOPE : |
| MethodScope methodScope = (MethodScope) scope; |
| if (methodScope.isLambdaScope()) |
| methodScope = methodScope.namedMethodScope(); |
| 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; |
| sourceType.tagBits |= enclosingType.tagBits & TagBits.AnnotationTerminallyDeprecated; |
| } |
| break; |
| } |
| scope = scope.parent; |
| } while (scope != null); |
| } |
| |
| // after this point, tests on the 16 bits reserved. |
| //{ObjectTeams: also include _some_ extra modifiers like AccTeam / AccRole: |
| /* orig: |
| int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; |
| :giro */ |
| int realModifiers = modifiers & ExtraCompilerModifiers.AccOTTypeJustFlag; |
| // SH} |
| |
| if ((realModifiers & ClassFileConstants.AccInterface) != 0) { // interface and annotation type |
| // detect abnormal cases for interfaces |
| if (isMemberType) { |
| final int UNEXPECTED_MODIFIERS = |
| ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract | ClassFileConstants.AccInterface | ClassFileConstants.AccStrictfp | ClassFileConstants.AccAnnotation |
| //{ObjectTeams more flags allowed for interfaces: |
| | ExtraCompilerModifiers.AccRole | ClassFileConstants.AccSynthetic |
| // SH} |
| ); |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { |
| if ((realModifiers & ClassFileConstants.AccAnnotation) != 0) |
| problemReporter().illegalModifierForAnnotationMemberType(sourceType); |
| else |
| problemReporter().illegalModifierForMemberInterface(sourceType); |
| //{ObjectTeams: prevent downstream problems with types illegally marked as team: |
| modifiers &= ~ExtraCompilerModifiers.AccTeam; |
| this.referenceContext.modifiers &= ~ExtraCompilerModifiers.AccTeam; |
| // SH} |
| } |
| /* |
| } else if (sourceType.isLocalType()) { //interfaces cannot be defined inside a method |
| int unexpectedModifiers = ~(AccAbstract | AccInterface | AccStrictfp); |
| if ((realModifiers & unexpectedModifiers) != 0) |
| problemReporter().illegalModifierForLocalInterface(sourceType); |
| */ |
| } else { |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ClassFileConstants.AccInterface | ClassFileConstants.AccStrictfp | ClassFileConstants.AccAnnotation |
| //{ObjectTeams |
| | ClassFileConstants.AccSynthetic |
| ); |
| //SH} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { |
| if ((realModifiers & ClassFileConstants.AccAnnotation) != 0) |
| problemReporter().illegalModifierForAnnotationType(sourceType); |
| else |
| problemReporter().illegalModifierForInterface(sourceType); |
| } |
| } |
| /* |
| * AccSynthetic must be set if the target is greater than 1.5. 1.5 VM don't support AccSynthetics flag. |
| */ |
| if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME && compilerOptions().targetJDK > ClassFileConstants.JDK1_5) { |
| modifiers |= ClassFileConstants.AccSynthetic; |
| } |
| modifiers |= ClassFileConstants.AccAbstract; |
| } else if ((realModifiers & ClassFileConstants.AccEnum) != 0) { |
| // detect abnormal cases for enums |
| if (isMemberType) { // includes member types defined inside local types |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStatic | ClassFileConstants.AccStrictfp | ClassFileConstants.AccEnum |
| //{ObjectTeams more flags allowed for types: |
| | ExtraCompilerModifiers.AccRole | ExtraCompilerModifiers.AccTeam | ClassFileConstants.AccSynthetic |
| ); |
| // Markus Witte} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { |
| problemReporter().illegalModifierForMemberEnum(sourceType); |
| modifiers &= ~ClassFileConstants.AccAbstract; // avoid leaking abstract modifier |
| realModifiers &= ~ClassFileConstants.AccAbstract; |
| // modifiers &= ~(realModifiers & UNEXPECTED_MODIFIERS); |
| // realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; |
| } |
| } else if (sourceType.isLocalType()) { |
| // each enum constant is an anonymous local type and its modifiers were already checked as an enum constant field |
| } else { |
| int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccStrictfp | ClassFileConstants.AccEnum |
| //{ObjectTeams more flags allowed for types |
| | ExtraCompilerModifiers.AccTeam | ExtraCompilerModifiers.AccRole); |
| if ((realModifiers & ExtraCompilerModifiers.AccRole) != 0) |
| UNEXPECTED_MODIFIERS ^= ClassFileConstants.AccProtected; // even toplevel roles may be protected. |
| // Markus Witte+SH} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) |
| problemReporter().illegalModifierForEnum(sourceType); |
| } |
| if (!sourceType.isAnonymousType()) { |
| checkAbstractEnum: { |
| // does define abstract methods ? |
| if ((this.referenceContext.bits & ASTNode.HasAbstractMethods) != 0) { |
| modifiers |= ClassFileConstants.AccAbstract; |
| break checkAbstractEnum; |
| } |
| // body of enum constant must implement any inherited abstract methods |
| // enum type needs to implement abstract methods if one of its constants does not supply a body |
| TypeDeclaration typeDeclaration = this.referenceContext; |
| FieldDeclaration[] fields = typeDeclaration.fields; |
| int fieldsLength = fields == null ? 0 : fields.length; |
| if (fieldsLength == 0) break checkAbstractEnum; // has no constants so must implement the method itself |
| AbstractMethodDeclaration[] methods = typeDeclaration.methods; |
| int methodsLength = methods == null ? 0 : methods.length; |
| // TODO (kent) cannot tell that the superinterfaces are empty or that their methods are implemented |
| boolean definesAbstractMethod = typeDeclaration.superInterfaces != null; |
| for (int i = 0; i < methodsLength && !definesAbstractMethod; i++) |
| definesAbstractMethod = methods[i].isAbstract(); |
| if (!definesAbstractMethod) break checkAbstractEnum; // all methods have bodies |
| boolean needAbstractBit = false; |
| for (int i = 0; i < fieldsLength; i++) { |
| FieldDeclaration fieldDecl = fields[i]; |
| if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { |
| if (fieldDecl.initialization instanceof QualifiedAllocationExpression) { |
| needAbstractBit = true; |
| } else { |
| break checkAbstractEnum; |
| } |
| } |
| } |
| // tag this enum as abstract since an abstract method must be implemented AND all enum constants define an anonymous body |
| // as a result, each of its anonymous constants will see it as abstract and must implement each inherited abstract method |
| if (needAbstractBit) { |
| modifiers |= ClassFileConstants.AccAbstract; |
| } |
| } |
| // final if no enum constant with anonymous body |
| checkFinalEnum: { |
| TypeDeclaration typeDeclaration = this.referenceContext; |
| FieldDeclaration[] fields = typeDeclaration.fields; |
| if (fields != null) { |
| for (int i = 0, fieldsLength = fields.length; i < fieldsLength; i++) { |
| FieldDeclaration fieldDecl = fields[i]; |
| if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { |
| if (fieldDecl.initialization instanceof QualifiedAllocationExpression) { |
| break checkFinalEnum; |
| } |
| } |
| } |
| } |
| modifiers |= ClassFileConstants.AccFinal; |
| } |
| } |
| } else { |
| // detect abnormal cases for classes |
| if (isMemberType) { // includes member types defined inside local types |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract | ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp |
| //{ObjectTeams more flags allowed for types: |
| | ExtraCompilerModifiers.AccRole | ExtraCompilerModifiers.AccTeam | ClassFileConstants.AccSynthetic |
| ); |
| //SH} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) |
| problemReporter().illegalModifierForMemberClass(sourceType); |
| } else if (sourceType.isLocalType()) { |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp |
| //{ObjectTeams more flags allowed for types: |
| | ExtraCompilerModifiers.AccRole |
| ); |
| //SH} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) |
| problemReporter().illegalModifierForLocalClass(sourceType); |
| } else { |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp |
| //{ObjectTeams more flags allowed for types: |
| | ExtraCompilerModifiers.AccRole | ExtraCompilerModifiers.AccTeam | ClassFileConstants.AccSynthetic |
| ); |
| // SH} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) |
| problemReporter().illegalModifierForClass(sourceType); |
| } |
| |
| // check that Final and Abstract are not set together |
| if ((realModifiers & (ClassFileConstants.AccFinal | ClassFileConstants.AccAbstract)) == (ClassFileConstants.AccFinal | ClassFileConstants.AccAbstract)) |
| problemReporter().illegalModifierCombinationFinalAbstractForClass(sourceType); |
| } |
| |
| if (isMemberType) { |
| // test visibility modifiers inconsistency, isolate the accessors bits |
| if (enclosingType.isInterface()) { |
| if ((realModifiers & (ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate)) != 0) { |
| problemReporter().illegalVisibilityModifierForInterfaceMemberType(sourceType); |
| |
| // need to keep the less restrictive |
| if ((realModifiers & ClassFileConstants.AccProtected) != 0) |
| modifiers &= ~ClassFileConstants.AccProtected; |
| if ((realModifiers & ClassFileConstants.AccPrivate) != 0) |
| modifiers &= ~ClassFileConstants.AccPrivate; |
| } |
| } else { |
| int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); |
| if ((accessorBits & (accessorBits - 1)) > 1) { |
| problemReporter().illegalVisibilityModifierCombinationForMemberType(sourceType); |
| |
| // 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; |
| } |
| } |
| } |
| |
| // static modifier test |
| if ((realModifiers & ClassFileConstants.AccStatic) == 0) { |
| if (enclosingType.isInterface()) |
| modifiers |= ClassFileConstants.AccStatic; |
| } else if (!enclosingType.isStatic()) { |
| //{ObjectTeams: member-interfaces are always (implicitly) static, |
| // role interfaces need to be members (at any level of nesting)! |
| if (!sourceType.isRole()) |
| // SH} |
| // error the enclosing type of a static field must be static or a top-level type |
| problemReporter().illegalStaticModifierForMemberType(sourceType); |
| } |
| } |
| |
| 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) { |
| //{ObjectTeams: share model if set: |
| if (fieldDecl.model != null) |
| fieldDecl.model.setBinding(fieldBinding); |
| // SH} |
| int modifiers = fieldBinding.modifiers; |
| final ReferenceBinding declaringClass = fieldBinding.declaringClass; |
| if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) |
| problemReporter().duplicateModifierForField(declaringClass, fieldDecl); |
| |
| //{ObjectTeams: synthetic role interfaces may have any access modifier. |
| /*@original |
| if (declaringClass.isInterface()) { |
| */ |
| if (declaringClass.isRegularInterface()) { |
| // SH} |
| final int IMPLICIT_MODIFIERS = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; |
| // set the modifiers |
| modifiers |= IMPLICIT_MODIFIERS; |
| |
| // and then check that they are the only ones |
| if ((modifiers & ExtraCompilerModifiers.AccJustFlag) != IMPLICIT_MODIFIERS) { |
| if ((declaringClass.modifiers & ClassFileConstants.AccAnnotation) != 0) |
| problemReporter().illegalModifierForAnnotationField(fieldDecl); |
| else |
| problemReporter().illegalModifierForInterfaceField(fieldDecl); |
| } |
| fieldBinding.modifiers = modifiers; |
| return; |
| } else if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { |
| // check that they are not modifiers in source |
| if ((modifiers & ExtraCompilerModifiers.AccJustFlag) != 0) |
| problemReporter().illegalModifierForEnumConstant(declaringClass, fieldDecl); |
| |
| // set the modifiers |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=267670. Force all enumerators to be marked |
| // as used locally. We are unable to track the usage of these reliably as they could be used |
| // in non obvious ways via the synthesized methods values() and valueOf(String) or by using |
| // Enum.valueOf(Class<T>, String). |
| final int IMPLICIT_MODIFIERS = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccEnum | ExtraCompilerModifiers.AccLocallyUsed; |
| fieldBinding.modifiers|= IMPLICIT_MODIFIERS; |
| return; |
| } |
| |
| // after this point, tests on the 16 bits reserved. |
| int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; |
| final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccFinal | ClassFileConstants.AccStatic | ClassFileConstants.AccTransient | ClassFileConstants.AccVolatile |
| //{ObjectTeams: synthetic fields |
| | ClassFileConstants.AccSynthetic); |
| //MacWitte} |
| if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { |
| problemReporter().illegalModifierForField(declaringClass, fieldDecl); |
| modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS; |
| } |
| |
| int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); |
| if ((accessorBits & (accessorBits - 1)) > 1) { |
| problemReporter().illegalVisibilityModifierCombinationForField(declaringClass, fieldDecl); |
| |
| // 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; |
| } |
| } |
| //{ObjectTeams: static role fields must be final (limitation): |
| if (declaringClass.isRole() && ((modifiers & ClassFileConstants.AccStatic) != 0)) { |
| if ((modifiers & ClassFileConstants.AccFinal) == 0) { |
| problemReporter().staticRoleFieldMustBeFinal(fieldDecl); |
| } |
| } |
| // SH} |
| |
| if ((realModifiers & (ClassFileConstants.AccFinal | ClassFileConstants.AccVolatile)) == (ClassFileConstants.AccFinal | ClassFileConstants.AccVolatile)) |
| problemReporter().illegalModifierCombinationFinalVolatileForField(declaringClass, fieldDecl); |
| |
| if (fieldDecl.initialization == null && (modifiers & ClassFileConstants.AccFinal) != 0) |
| modifiers |= ExtraCompilerModifiers.AccBlankFinal; |
| fieldBinding.modifiers = modifiers; |
| } |
| |
| public void checkParameterizedSuperTypeCollisions() { |
| // check for parameterized interface collisions (when different parameterizations occur) |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| ReferenceBinding[] interfaces = sourceType.superInterfaces; |
| Map invocations = new HashMap(2); |
| ReferenceBinding itsSuperclass = sourceType.isInterface() ? null : sourceType.superclass; |
| nextInterface: for (int i = 0, length = interfaces.length; i < length; i++) { |
| ReferenceBinding one = interfaces[i]; |
| if (one == null) continue nextInterface; |
| //{ObjectTeams: confined have no superclass/superinterface |
| if (TypeAnalyzer.isTopConfined(one)) |
| continue nextInterface; |
| //SH} |
| if (itsSuperclass != null && hasErasedCandidatesCollisions(itsSuperclass, one, invocations, sourceType, this.referenceContext)) |
| continue nextInterface; |
| nextOtherInterface: for (int j = 0; j < i; j++) { |
| ReferenceBinding two = interfaces[j]; |
| if (two == null) continue nextOtherInterface; |
| if (hasErasedCandidatesCollisions(one, two, invocations, sourceType, this.referenceContext)) |
| continue nextInterface; |
| } |
| } |
| |
| TypeParameter[] typeParameters = this.referenceContext.typeParameters; |
| nextVariable : for (int i = 0, paramLength = typeParameters == null ? 0 : typeParameters.length; i < paramLength; i++) { |
| TypeParameter typeParameter = typeParameters[i]; |
| TypeVariableBinding typeVariable = typeParameter.binding; |
| if (typeVariable == null || !typeVariable.isValidBinding()) continue nextVariable; |
| |
| TypeReference[] boundRefs = typeParameter.bounds; |
| if (boundRefs != null) { |
| boolean checkSuperclass = TypeBinding.equalsEquals(typeVariable.firstBound, typeVariable.superclass); |
| for (int j = 0, boundLength = boundRefs.length; j < boundLength; j++) { |
| TypeReference typeRef = boundRefs[j]; |
| TypeBinding superType = typeRef.resolvedType; |
| if (superType == null || !superType.isValidBinding()) continue; |
| |
| // check against superclass |
| if (checkSuperclass) |
| if (hasErasedCandidatesCollisions(superType, typeVariable.superclass, invocations, typeVariable, typeRef)) |
| continue nextVariable; |
| // check against superinterfaces |
| for (int index = typeVariable.superInterfaces.length; --index >= 0;) |
| if (hasErasedCandidatesCollisions(superType, typeVariable.superInterfaces[index], invocations, typeVariable, typeRef)) |
| continue nextVariable; |
| } |
| } |
| } |
| |
| ReferenceBinding[] memberTypes = this.referenceContext.binding.memberTypes; |
| if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) |
| for (int i = 0, size = memberTypes.length; i < size; i++) |
| //{ObjectTeams: consider binary role files, and fully translated ones: |
| if ( !memberTypes[i].isBinaryBinding() |
| && !StateHelper.hasState(memberTypes[i], ITranslationStates.STATE_FINAL)) |
| // SH} |
| ((SourceTypeBinding) memberTypes[i]).scope.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; |
| ReferenceBinding[] interfacesToVisit = null; |
| int nextPosition = 0; |
| do { |
| if (currentType.hasMemberTypes()) // avoid resolving member types eagerly |
| return; |
| |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| // in code assist cases when source types are added late, may not be finished connecting hierarchy |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| if (interfacesToVisit == null) { |
| interfacesToVisit = itsInterfaces; |
| nextPosition = interfacesToVisit.length; |
| } else { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| } while ((currentType = currentType.superclass()) != null && (currentType.tagBits & TagBits.HasNoMemberTypes) == 0); |
| |
| if (interfacesToVisit != null) { |
| // contains the interfaces between the sourceType and any superclass, which was tagged as having no member types |
| boolean needToTag = false; |
| for (int i = 0; i < nextPosition; i++) { |
| ReferenceBinding anInterface = interfacesToVisit[i]; |
| if ((anInterface.tagBits & TagBits.HasNoMemberTypes) == 0) { // skip interface if it already knows it has no member types |
| if (anInterface.hasMemberTypes()) // avoid resolving member types eagerly |
| return; |
| |
| needToTag = true; |
| ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| int itsLength = itsInterfaces.length; |
| if (nextPosition + itsLength >= interfacesToVisit.length) |
| System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition); |
| nextInterface : for (int a = 0; a < itsLength; a++) { |
| ReferenceBinding next = itsInterfaces[a]; |
| for (int b = 0; b < nextPosition; b++) |
| if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface; |
| interfacesToVisit[nextPosition++] = next; |
| } |
| } |
| } |
| } |
| |
| if (needToTag) { |
| for (int i = 0; i < nextPosition; i++) |
| interfacesToVisit[i].tagBits |= TagBits.HasNoMemberTypes; |
| } |
| } |
| |
| // 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); |
| } |
| |
| // Perform deferred bound checks for parameterized type references (only done after hierarchy is connected) |
| public void checkParameterizedTypeBounds() { |
| //{ObjectTeams: expect re-entry: |
| /* orig: |
| for (int i = 0, l = this.deferredBoundChecks == null ? 0 : this.deferredBoundChecks.size(); i < l; i++) { |
| Object toCheck = this.deferredBoundChecks.get(i); |
| if (toCheck instanceof TypeReference) |
| ((TypeReference) toCheck).checkBounds(this); |
| else if (toCheck instanceof Runnable) |
| ((Runnable) toCheck).run(); |
| } |
| this.deferredBoundChecks = null; |
| :giro */ |
| ArrayList toCheckList = this.deferredBoundChecks; |
| this.deferredBoundChecks = null; |
| for (int i = 0, l = toCheckList == null ? 0 : toCheckList.size(); i < l; i++) { |
| Object toCheck = toCheckList.get(i); |
| if (toCheck instanceof TypeReference) |
| ((TypeReference) toCheck).checkBounds(this); |
| else if (toCheck instanceof Runnable) |
| ((Runnable) toCheck).run(); |
| } |
| // SH} |
| |
| ReferenceBinding[] memberTypes = this.referenceContext.binding.memberTypes; |
| if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) |
| for (int i = 0, size = memberTypes.length; i < size; i++) |
| //{ObjectTeams: binary roles need not be checked again (hopefully) (nor do completely translated ones) |
| if ( !memberTypes[i].isBinaryBinding() |
| && !StateHelper.hasState(memberTypes[i], ITranslationStates.STATE_FINAL)) |
| // SH} |
| ((SourceTypeBinding) memberTypes[i]).scope.checkParameterizedTypeBounds(); |
| } |
| |
| private void connectMemberTypes() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| //{ObjectTeams: extracted treatment of teams to new method: |
| if (this.referenceContext.isTeam()) { |
| connectTeamMemberTypes(); |
| return; |
| } |
| // SH} |
| ReferenceBinding[] memberTypes = sourceType.memberTypes; |
| if (memberTypes != null && memberTypes != Binding.NO_MEMBER_TYPES) { |
| for (int i = 0, size = memberTypes.length; i < size; i++) |
| //{ObjectTeams: respect reused binary members: |
| if (!memberTypes[i].isBinaryBinding()) |
| // SH} |
| ((SourceTypeBinding) memberTypes[i]).scope.connectTypeHierarchy(); |
| } |
| } |
| //{ObjectTeams: different order, more to do, for members of a team: |
| // @PRE: current is a team. |
| private void connectTeamMemberTypes() { |
| |
| // 1. shallow connecting of roles: |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| // don't cache memberTypes/size, loop might introduce new role files |
| if (sourceType.memberTypes != null && sourceType.memberTypes != Binding.NO_MEMBER_TYPES) { |
| for (int i = 0; i < sourceType.memberTypes.length; i++) { |
| ReferenceBinding memberType = sourceType.memberTypes[i]; |
| // cope with binary role in source type team and pre-translated roles |
| if ( !memberType.isBinaryBinding() |
| && !StateHelper.hasState(memberType, ITranslationStates.STATE_FINAL)) |
| { |
| ((SourceTypeBinding) memberType).scope.connectTypeHierarchyWithoutMembers(); |
| } |
| } |
| } |
| |
| // 2. copy roles and create OT-specific connections: |
| if ( !isOrgObjectteamsTeam(sourceType) |
| && (sourceType.tagBits & TagBits.HierarchyHasProblems) == 0) |
| { |
| CopyInheritance.copyRoles(sourceType); |
| } |
| |
| // 3. descend into roles: |
| if (sourceType.memberTypes != null && sourceType.memberTypes != Binding.NO_MEMBER_TYPES) { |
| Sorting.sortMemberTypes(sourceType); |
| for (int i = 0; i < sourceType.memberTypes.length; i++) { |
| ReferenceBinding memberType = sourceType.memberTypes[i]; |
| // cope with binary role in source type team and pre-translated roles |
| if ( !memberType.isBinaryBinding() |
| && !StateHelper.hasState(memberType, ITranslationStates.STATE_FINAL)) |
| { |
| ((SourceTypeBinding) memberType).scope.connectMemberTypes(); |
| } |
| } |
| } |
| } |
| // SH} |
| |
| /* |
| 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 = this.referenceContext.binding; |
| //{ObjectTeams: propagate hierarchy problems: |
| if (sourceType.isRole() && ((sourceType.enclosingType().tagBits & TagBits.HierarchyHasProblems) != 0)) |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| // separate treatment for team classes: |
| if (sourceType.isTeam()) |
| return connectSuperteam(); |
| // SH} |
| if (sourceType.id == TypeIds.T_JavaLangObject) { // handle the case of redefining java.lang.Object up front |
| sourceType.setSuperClass(null); |
| sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); |
| if (!sourceType.isClass()) |
| problemReporter().objectMustBeClass(sourceType); |
| if (this.referenceContext.superclass != null || (this.referenceContext.superInterfaces != null && this.referenceContext.superInterfaces.length > 0)) |
| problemReporter().objectCannotHaveSuperTypes(sourceType); |
| return true; // do not propagate Object's hierarchy problems down to every subtype |
| } |
| if (this.referenceContext.superclass == null) { |
| //{ObjectTeams: Confined roles may have no superclass |
| if (TypeAnalyzer.isTopConfined(sourceType)) |
| return true; |
| // SH} |
| if (sourceType.isEnum() && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) // do not connect if source < 1.5 as enum already got flagged as syntax error |
| return connectEnumSuperclass(); |
| sourceType.setSuperClass(getJavaLangObject()); |
| return !detectHierarchyCycle(sourceType, sourceType.superclass, null); |
| } |
| TypeReference superclassRef = this.referenceContext.superclass; |
| //{ObjectTeams: option to roll back problems: |
| CheckPoint cp = this.referenceContext.compilationResult.getCheckPoint(this.referenceContext); |
| // SH} |
| ReferenceBinding superclass = findSupertype(superclassRef); |
| //{ObjectTeams: for roles give a second chance |
| if (superclass == null || superclass.erasure() instanceof MissingTypeBinding) { // problem binding is in superclassRef.resolvedType |
| ReferenceBinding adjustedSuperclass = checkAdjustSuperclass(this.referenceContext.superclass, cp); |
| if (adjustedSuperclass == null || adjustedSuperclass.isValidBinding()) |
| superclass = adjustedSuperclass; |
| } |
| // SH} |
| if (superclass != null) { // is null if a cycle was detected cycle or a problem |
| //{ObjectTeams: additional check: |
| if (!Protections.checkCompatibleEnclosingForRoles( |
| this, |
| this.referenceContext, |
| this.referenceContext.binding, |
| superclass)) { |
| // nop, already reported inside |
| } else |
| // SH} |
| if (!superclass.isClass() && (superclass.tagBits & TagBits.HasMissingType) == 0) { |
| problemReporter().superclassMustBeAClass(sourceType, superclassRef, superclass); |
| } else if (superclass.isFinal()) { |
| problemReporter().classExtendFinalClass(sourceType, superclassRef, superclass); |
| } else if ((superclass.tagBits & TagBits.HasDirectWildcard) != 0) { |
| problemReporter().superTypeCannotUseWildcard(sourceType, superclassRef, superclass); |
| } else if (superclass.erasure().id == TypeIds.T_JavaLangEnum) { |
| problemReporter().cannotExtendEnum(sourceType, superclassRef, superclass); |
| } else if ((superclass.tagBits & TagBits.HierarchyHasProblems) != 0 |
| || !superclassRef.resolvedType.isValidBinding()) { |
| sourceType.setSuperClass(superclass); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; // propagate if missing supertype |
| return superclassRef.resolvedType.isValidBinding(); // reported some error against the source type ? |
| //{ObjectTeams: team super class only allowed for teams |
| } else if ((isOrgObjectteamsTeam(superclass) || superclass.isTeam()) |
| && !sourceType.isTeam()) |
| { |
| problemReporter().regularExtendsTeam(sourceType, this.referenceContext.superclass, superclass); |
| // SH} |
| } else { |
| // only want to reach here when no errors are reported |
| sourceType.setSuperClass(superclass); |
| sourceType.typeBits |= (superclass.typeBits & TypeIds.InheritableBits); |
| // further analysis against white lists for the unlikely case we are compiling java.io.*: |
| if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) |
| sourceType.typeBits |= sourceType.applyCloseableClassWhitelists(); |
| return true; |
| } |
| } |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| sourceType.setSuperClass(getJavaLangObject()); |
| if ((sourceType.superclass.tagBits & TagBits.BeginHierarchyCheck) == 0) |
| detectHierarchyCycle(sourceType, sourceType.superclass, null); |
| return false; // reported some error against the source type |
| } |
| |
| /** |
| * enum X (implicitly) extends Enum<X> |
| */ |
| private boolean connectEnumSuperclass() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| ReferenceBinding rootEnumType = getJavaLangEnum(); |
| if ((rootEnumType.tagBits & TagBits.HasMissingType) != 0) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; // mark missing supertpye |
| sourceType.setSuperClass(rootEnumType); |
| return false; |
| } |
| boolean foundCycle = detectHierarchyCycle(sourceType, rootEnumType, null); |
| // arity check for well-known Enum<E> |
| TypeVariableBinding[] refTypeVariables = rootEnumType.typeVariables(); |
| if (refTypeVariables == Binding.NO_TYPE_VARIABLES) { // check generic |
| problemReporter().nonGenericTypeCannotBeParameterized(0, null, rootEnumType, new TypeBinding[]{ sourceType }); |
| return false; // cannot reach here as AbortCompilation is thrown |
| } else if (1 != refTypeVariables.length) { // check arity |
| problemReporter().incorrectArityForParameterizedType(null, rootEnumType, new TypeBinding[]{ sourceType }); |
| return false; // cannot reach here as AbortCompilation is thrown |
| } |
| // check argument type compatibility |
| ParameterizedTypeBinding superType = environment().createParameterizedType( |
| rootEnumType, |
| new TypeBinding[]{ |
| environment().convertToRawType(sourceType, false /*do not force conversion of enclosing types*/), |
| } , |
| null); |
| sourceType.tagBits |= (superType.tagBits & TagBits.HierarchyHasProblems); // propagate if missing supertpye |
| sourceType.setSuperClass(superType); |
| // bound check (in case of bogus definition of Enum type) |
| if (!refTypeVariables[0].boundCheck(superType, sourceType, this, null).isOKbyJLS()) { |
| problemReporter().typeMismatchError(rootEnumType, refTypeVariables[0], sourceType, null); |
| } |
| return !foundCycle; |
| } |
| |
| //{ObjectTeams connect and adjust more class relationships: |
| |
| // RoleSplitter might have been over-eager: would we be better of, if we strip |
| // the OT_DELIM prefix of our superclass? |
| // We only get called, when the long name did not find a class, i.e., |
| // it can't be a role. |
| private ReferenceBinding checkAdjustSuperclass(TypeReference superRef, CheckPoint cp) |
| { |
| ReferenceBinding found = (ReferenceBinding)superRef.resolvedType; |
| if (found != null && found.isValidBinding()) |
| found = null; // returning found shall signal errors |
| // Note, that indeed superRef.resolveType() may have returned null, |
| // yet superRef.resolvedType can be a valid type. This happens, e.g., |
| // in org.eclipse.jdt.core.tests.compiler.regression.JavadocTest_1_4 |
| // testcasses testBug83127*: a parameterized type reference refers |
| // to a valid class but its parameters have errors. |
| if (!this.referenceContext.isSourceRole()) { |
| if ((this.referenceContext.binding.tagBits & TagBits.HierarchyHasProblems) != 0) |
| return null; // already detected a cycle, don't use 'found'! |
| return found; |
| } |
| if (superRef instanceof SingleTypeReference) { |
| SingleTypeReference singRef = (SingleTypeReference)superRef; |
| if (!RoleSplitter.isClassPartName(singRef.token)) |
| return found; |
| singRef.token = RoleSplitter.getInterfacePartName(singRef.token); |
| } else if (superRef instanceof QualifiedTypeReference) { |
| QualifiedTypeReference qualRef = (QualifiedTypeReference)superRef; |
| int pos = qualRef.tokens.length-1; |
| char[] lastToken = qualRef.tokens[pos]; |
| if (!RoleSplitter.isClassPartName(lastToken)) |
| return found; |
| lastToken = RoleSplitter.getInterfacePartName(lastToken); |
| qualRef.tokens[pos] = lastToken; |
| } |
| // before the second attempt delete first error: |
| superRef.resolvedType = null; // remove problem binding. |
| this.referenceContext.compilationResult.rollBack(cp); // remove IProblem |
| return findSupertype(superRef); |
| } |
| |
| public boolean connectBaseclass() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (!this.referenceContext.isDirectRole()) { |
| if (this.referenceContext.baseclass != null) |
| problemReporter().playedByInRegularClass(sourceType, this.referenceContext.baseclass); |
| return true; |
| } |
| if (sourceType.isSynthInterface()) |
| return true; // will transfer baseclass to the ifc part in Dependencies.linkBaseclass |
| if (this.referenceContext.baseclass == null) { |
| // leave sourceType.baseclass untouched, might be set by CopyInheritance.copyBaseclass() |
| return true; |
| } |
| if (sourceType.roleModel == null) { |
| // if we already have errors silently quit, otherwise there's a bug here: |
| if (!this.referenceContext.ignoreFurtherInvestigation) |
| throw new InternalCompilerError("Missing role model"); //$NON-NLS-1$ |
| return false; |
| } |
| try { |
| TypeReference baseclassRef = this.referenceContext.baseclass; |
| |
| ReferenceBinding baseclass= findBaseclass(baseclassRef); |
| |
| // detect cycle wrt. containment: |
| ReferenceBinding currentType = sourceType; |
| while (currentType != null && baseclass != null) { |
| if (TypeBinding.equalsEquals(currentType, baseclass)) { |
| problemReporter().playedByEnclosing(sourceType, this.referenceContext.baseclass, baseclass); |
| sourceType.roleModel._playedByEnclosing = true; |
| break; |
| } |
| currentType = currentType.enclosingType(); |
| } |
| |
| // check illegal containment cycle: |
| if (baseclass != null) { |
| ReferenceBinding currentClass = baseclass; |
| while (currentClass != null) { |
| if (TypeBinding.equalsEquals(currentClass, sourceType)) { |
| problemReporter().baseclassIsMember(sourceType, baseclassRef, baseclass); |
| baseclass = null; |
| break; |
| } |
| currentClass = currentClass.enclosingType(); |
| } |
| } |
| |
| if (baseclass != null) { // is null if a cycle was detected |
| |
| if ( baseclass.isRole() |
| && !baseclass.isRoleType()) |
| { |
| if (RoleModel.isRoleFromOuterEnclosing(sourceType, baseclass)) { |
| TeamModel outerTeam = baseclass.enclosingType().getTeamModel(); |
| baseclass = (ReferenceBinding)outerTeam.getTThis().getRoleTypeBinding(baseclass, 0); |
| } else { |
| // unused: TypeReference roleClassRef = TypeAnalyzer.getRoleClassReference(baseclassRef); |
| // TODO (SH): replace with general lookup of common enclosing team? |
| // (cf. RoleTypeBinding.findCommonEnclosingTeam()) |
| if ( TypeBinding.equalsEquals(baseclass.enclosingType(), sourceType.enclosingType()) |
| || TypeBinding.equalsEquals(baseclass.enclosingType(), sourceType.enclosingType().superclass())) |
| { |
| problemReporter().baseclassIsRoleOfTheSameTeam(sourceType, this.referenceContext.baseclass, baseclass); |
| sourceType.baseclass = null; |
| baseclassRef.resolvedType = null; |
| RoleModel.setTagBit(sourceType, RoleModel.BaseclassHasProblems); |
| this.referenceContext.pushDownBindingProblem(); |
| return false; |
| } |
| problemReporter().missingTypeAnchor(this.referenceContext.baseclass, baseclass); |
| } |
| } |
| TypeVariableBinding[] roleVariables = sourceType.typeVariables; |
| if (baseclass.isParameterizedType()) { |
| if (!areEqualTypeParameters(roleVariables, ((ParameterizedTypeBinding) baseclass).arguments)) { |
| problemReporter().parameterizedBaseclass(baseclassRef, baseclass); |
| baseclass = (ReferenceBinding)baseclass.erasure(); |
| } |
| } else if (sourceType.typeVariables() != Binding.NO_TYPE_VARIABLES) { |
| problemReporter().nonParameterizedBaseclass(baseclassRef, sourceType); |
| } |
| |
| if (baseclass.isFinal()) |
| problemReporter().decapsulationOfFinal(baseclassRef, baseclass); |
| if (baseclass instanceof BinaryTypeBinding |
| && ((BinaryTypeBinding)baseclass).version >= ClassFileConstants.JDK1_8 |
| && compilerOptions().weavingScheme == WeavingScheme.OTRE) { |
| problemReporter().otreCannotWeaveIntoJava8(baseclassRef, baseclass, (int) (((BinaryTypeBinding)baseclass).version >> 16)); |
| } |
| if (/* !sourceType.isInterface() // FIXME(SH): ifc playedBy ifc is currently incompatible with add/removeRole infrastructure. |
| && */baseclass.isInterface() && (baseclass.tagBits & TagBits.HasMissingType) == 0) |
| { |
| // Continue after reporting. |
| if (!baseclass.isSynthInterface()) // un-anchored reference to role type? (already reported above). |
| problemReporter().baseclassMustBeAClass(sourceType, this.referenceContext.baseclass, baseclass); |
| } |
| if ((baseclass.tagBits & TagBits.HierarchyHasProblems) != 0) |
| RoleModel.setTagBit(sourceType, RoleModel.BaseclassHasProblems); |
| if (!baseclass.isValidBinding() && baseclass instanceof ProblemReferenceBinding) { |
| TypeBinding match= ((ProblemReferenceBinding)baseclass).closestMatch(); |
| if (match instanceof ReferenceBinding) { |
| if (baseclassRef.getBaseclassDecapsulation() != DecapsulationState.CONFINED) //=> decaps confined already reported |
| problemReporter().invalidType(this.referenceContext.baseclass, baseclass); |
| } |
| } else if (sourceType.id == TypeIds.T_JavaLangObject) { |
| // can only happen if Object extends another type... will never happen unless we're testing for it. |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| sourceType.baseclass = null; |
| return true; |
| } else { |
| // only want to reach here when no errors are reported |
| sourceType.baseclass = baseclass; |
| |
| RoleModel roleModel = sourceType.roleModel; |
| roleModel._state.addJob(ITranslationStates.STATE_ROLES_LINKED, new Runnable() { |
| @Override |
| public void run() { |
| checkBaseClassRedefinition(ClassScope.this.referenceContext); |
| } |
| }); |
| |
| char[] packageName = baseclass.compoundName[0]; |
| if ( CharOperation.equals(packageName, "java".toCharArray()) //$NON-NLS-1$ |
| || CharOperation.equals(packageName, "javax".toCharArray())) //$NON-NLS-1$ |
| problemReporter().tryingToWeaveIntoSystemClass(this.referenceContext.baseclass, baseclass); |
| |
| // pretend "implements o.o.IBoundBase", will be generated by the OTRE: |
| baseclass.setIsBoundBase(sourceType); |
| |
| boolean createBinding = sourceType.unResolvedFields() != Binding.UNINITIALIZED_FIELDS; // don't create field binding if none have been built yet |
| StandardElementGenerator.checkCreateBaseField(this.referenceContext, baseclass, createBinding); |
| return true; |
| } |
| } |
| } finally { |
| // trap for selection/completion only after checking base.R things: |
| this.referenceContext.baseclass.aboutToResolve(this); |
| } |
| RoleModel.setTagBit(sourceType, RoleModel.BaseclassHasProblems); |
| // give at least some legal base class: |
| sourceType.baseclass = getJavaLangObject(); |
| if ((sourceType.baseclass.tagBits & TagBits.BeginHierarchyCheck) == 0) |
| detectHierarchyCycle(sourceType, sourceType.baseclass, null); |
| |
| this.referenceContext.pushDownBindingProblem(); |
| |
| return false; // reported some error against the source type |
| } |
| |
| public void connectBaseclassRecurse() { |
| connectBaseclass(); |
| TypeDeclaration[] members = this.referenceContext.memberTypes; |
| if (members != null) |
| for (TypeDeclaration member : members) |
| member.scope.connectBaseclassRecurse(); |
| } |
| |
| private boolean areEqualTypeParameters(TypeVariableBinding[] roleTypeVariables, TypeBinding[] baseTypeArguments) { |
| if (roleTypeVariables.length != baseTypeArguments.length) |
| return false; |
| for (int i = 0; i < roleTypeVariables.length; i++) { |
| if (TypeBinding.notEquals(roleTypeVariables[i], baseTypeArguments[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| // check OTJLD 2.1(c) and OTJLD 2.1(d) |
| void checkBaseClassRedefinition(TypeDeclaration roleDecl) |
| { |
| ReferenceBinding baseclass = roleDecl.binding.baseclass; |
| Dependencies.ensureBindingState(baseclass, ITranslationStates.STATE_ROLES_LINKED); |
| |
| ReferenceBinding superclass = roleDecl.binding.superclass; |
| if (superclass != null) { |
| ReferenceBinding superBase = superclass.rawBaseclass(); |
| if ( superBase != null |
| && !baseclass.isCompatibleWith(superBase)) |
| { |
| problemReporter().illegalPlayedByRedefinition(roleDecl.baseclass, baseclass, |
| superclass, superBase); |
| } |
| } |
| // for comparison with tsuper's baseclass separately check type and type-anchor: |
| ITeamAnchor baseAnchor = null; |
| if (RoleTypeBinding.isRoleWithExplicitAnchor(baseclass)) { |
| baseAnchor = ((RoleTypeBinding)baseclass)._teamAnchor; |
| baseclass = baseclass.getRealType(); |
| } |
| for (ReferenceBinding tsuperRole: roleDecl.getRoleModel().getTSuperRoleBindings()) { |
| ReferenceBinding tsuperBase = tsuperRole.baseclass(); |
| if ( tsuperBase != null && TypeBinding.notEquals(tsuperBase, baseclass)) { |
| ITeamAnchor tsuperAnchor = null; |
| if (RoleTypeBinding.isRoleWithExplicitAnchor(tsuperBase)) { |
| tsuperAnchor = ((RoleTypeBinding)tsuperBase)._teamAnchor; |
| tsuperBase = tsuperBase.getRealType(); |
| } |
| if ( !(TypeBinding.equalsEquals(baseclass, tsuperBase) || TSuperHelper.isTSubOf(baseclass, tsuperBase)) |
| || !TSuperHelper.isEquivalentField(baseAnchor, tsuperAnchor)) |
| { |
| problemReporter().overridesPlayedBy(ClassScope.this.referenceContext, tsuperBase); |
| } |
| } |
| } |
| } |
| |
| // mostly like connectSuperclass |
| private boolean connectSuperteam() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| // team: handle o.o.Team vaguely similar to j.l.Object: |
| if (isOrgObjectteamsTeam(sourceType)) { // handle the case of redefining org.objectteams.Team up front |
| this.referenceContext.modifiers |= ExtraCompilerModifiers.AccTeam; |
| sourceType.superclass = getJavaLangObject(); |
| if ( this.referenceContext.superclass != null) |
| problemReporter().teamCannotHaveSuperTypes(sourceType); |
| return true; // do not propagate Team's hierarchy problems down to every subtype |
| } |
| // :maet |
| |
| if (this.referenceContext.superclass == null) { |
| if (sourceType.isEnum() && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) // do not connect if source < 1.5 as enum already got flagged as syntax error |
| // team: enum not allowed for team, different default superclass |
| { |
| problemReporter().illegalModifierForTeam(this.referenceContext); |
| return false; |
| } |
| LookupEnvironment environment = environment(); |
| try { |
| environment.missingClassFileLocation = this.referenceContext; |
| sourceType.superclass = getOrgObjectteamsTeam(); |
| if (sourceType.superclass == null || (sourceType.superclass.tagBits & TagBits.HasMissingType) != 0) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| return false; // o.o.Team not found |
| } |
| } finally { |
| environment.missingClassFileLocation = null; |
| } |
| // :maet |
| return !detectHierarchyCycle(sourceType, sourceType.superclass, null); |
| } |
| TypeReference superclassRef = this.referenceContext.superclass; |
| //{ObjectTeams: option to roll back problems: |
| CheckPoint cp = this.referenceContext.compilationResult.getCheckPoint(this.referenceContext); |
| // SH} |
| ReferenceBinding superclass = findSupertype(superclassRef); |
| //{ObjectTeams: second chance. |
| if (superclass == null || superclass instanceof MissingTypeBinding) { // problem binding is in superclassRef.resolvedType |
| ReferenceBinding adjustedSuperclass = checkAdjustSuperclass(superclassRef, cp); |
| if (adjustedSuperclass != null && adjustedSuperclass.isValidBinding()) |
| superclass = adjustedSuperclass; |
| } |
| // SH} |
| |
| if (superclass != null) { // is null if a cycle was detected cycle or a problem |
| //{ObjectTeams: additional checks: |
| if (!Protections.checkCompatibleEnclosingForRoles( |
| this, |
| this.referenceContext, |
| this.referenceContext.binding, |
| superclass)) { |
| // nop, already reported inside |
| } else |
| // SH} |
| if (!superclass.isClass() && (superclass.tagBits & TagBits.HasMissingType) == 0) { |
| problemReporter().superclassMustBeAClass(sourceType, superclassRef, superclass); |
| } else if (superclass.isFinal()) { |
| problemReporter().classExtendFinalClass(sourceType, superclassRef, superclass); |
| } else if ((superclass.tagBits & TagBits.HasDirectWildcard) != 0) { |
| problemReporter().superTypeCannotUseWildcard(sourceType, superclassRef, superclass); |
| } else if (superclass.erasure().id == TypeIds.T_JavaLangEnum) { |
| problemReporter().cannotExtendEnum(sourceType, superclassRef, superclass); |
| } else if ((superclass.tagBits & TagBits.HierarchyHasProblems) != 0 |
| || !superclassRef.resolvedType.isValidBinding()) { |
| sourceType.superclass = superclass; |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; // propagate if missing supertype |
| return superclassRef.resolvedType.isValidBinding(); // reported some error against the source type ? |
| // :maet |
| } else { |
| // only want to reach here when no errors are reported |
| sourceType.superclass = superclass; |
| |
| // team: |
| // if superclass is not o.o.Team add "implements org.objectteams.ITeam": |
| if (!superclass.isTeam()) { |
| AstGenerator gen = new AstGenerator(this.referenceContext); |
| QualifiedTypeReference additionalSuperIfc = gen.qualifiedTypeReference(IOTConstants.ORG_OBJECTTEAMS_ITEAM); |
| if (this.referenceContext.superInterfaces != null) { |
| int len = this.referenceContext.superInterfaces.length; |
| System.arraycopy(this.referenceContext.superInterfaces, 0, this.referenceContext.superInterfaces = new TypeReference[len+1], 0, len); |
| this.referenceContext.superInterfaces[len] = additionalSuperIfc; |
| } else { |
| this.referenceContext.superInterfaces = new TypeReference[] { additionalSuperIfc }; |
| } |
| } |
| |
| // might need line numbers of super team, although parser thought we would not.. |
| if ( superclass instanceof SourceTypeBinding |
| && superclass.model.getState() != ITranslationStates.STATE_FINAL) |
| { |
| CompilationUnitDeclaration result = ((SourceTypeBinding)superclass).scope.referenceCompilationUnit(); |
| if (result.compilationResult.lineSeparatorPositions == null) |
| result.compilationResult.lineSeparatorPositions = new int[0]; |
| } |
| // :maet |
| return true; |
| } |
| } |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| if (!isOrgObjectteamsTeam(sourceType)) { |
| sourceType.superclass = getOrgObjectteamsTeam(); |
| if ((sourceType.superclass.tagBits & TagBits.BeginHierarchyCheck) == 0) |
| detectHierarchyCycle(sourceType, sourceType.superclass, null); |
| } |
| return false; // reported some error against the source type |
| } |
| // Markus Witte+SH} |
| |
| |
| /* |
| Our current belief based on available JCK 1.3 tests is: |
| inherited member types are visible as a potential superclass. |
| inherited interfaces are visible when defining a superinterface. |
| |
| Error recovery story: |
| ensure the superinterfaces contain only valid visible interfaces. |
| |
| Answer false if an error was reported against the sourceType. |
| */ |
| private boolean connectSuperInterfaces() { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); |
| if (this.referenceContext.superInterfaces == null) { |
| if (sourceType.isAnnotationType() && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { // do not connect if source < 1.5 as annotation already got flagged as syntax error) { |
| ReferenceBinding annotationType = getJavaLangAnnotationAnnotation(); |
| boolean foundCycle = detectHierarchyCycle(sourceType, annotationType, null); |
| sourceType.setSuperInterfaces(new ReferenceBinding[] { annotationType }); |
| return !foundCycle; |
| } |
| return true; |
| } |
| if (sourceType.id == TypeIds.T_JavaLangObject) // already handled the case of redefining java.lang.Object |
| return true; |
| |
| boolean noProblems = true; |
| int length = this.referenceContext.superInterfaces.length; |
| ReferenceBinding[] interfaceBindings = new ReferenceBinding[length]; |
| int count = 0; |
| nextInterface : for (int i = 0; i < length; i++) { |
| TypeReference superInterfaceRef = this.referenceContext.superInterfaces[i]; |
| ReferenceBinding superInterface = findSupertype(superInterfaceRef); |
| if (superInterface == null) { // detected cycle |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| noProblems = false; |
| continue nextInterface; |
| } |
| //{ObjectTeams: check special rules for "implements IXXXMigratable" |
| noProblems = RoleMigrationImplementor.checkMigratableInterfaces(sourceType, superInterfaceRef, superInterface, this); |
| if (!noProblems) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| continue nextInterface; |
| } |
| if ( sourceType.isInterface() |
| && TypeAnalyzer.isConfined(superInterface) |
| && this.referenceContext.superclass == null) |
| { |
| sourceType.superclass = null; // cancel premature superclass j.l.Object |
| } |
| // SH} |
| |
| // check for simple interface collisions |
| // Check for a duplicate interface once the name is resolved, otherwise we may be confused (i.e. a.b.I and c.d.I) |
| for (int j = 0; j < i; j++) { |
| if (TypeBinding.equalsEquals(interfaceBindings[j], superInterface)) { |
| problemReporter().duplicateSuperinterface(sourceType, superInterfaceRef, superInterface); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| noProblems = false; |
| continue nextInterface; |
| } |
| } |
| if (!superInterface.isInterface() && (superInterface.tagBits & TagBits.HasMissingType) == 0) { |
| problemReporter().superinterfaceMustBeAnInterface(sourceType, superInterfaceRef, superInterface); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| noProblems = false; |
| continue nextInterface; |
| } else if (superInterface.isAnnotationType()){ |
| problemReporter().annotationTypeUsedAsSuperinterface(sourceType, superInterfaceRef, superInterface); |
| } |
| if ((superInterface.tagBits & TagBits.HasDirectWildcard) != 0) { |
| problemReporter().superTypeCannotUseWildcard(sourceType, superInterfaceRef, superInterface); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| noProblems = false; |
| continue nextInterface; |
| } |
| if ((superInterface.tagBits & TagBits.HierarchyHasProblems) != 0 |
| || !superInterfaceRef.resolvedType.isValidBinding()) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; // propagate if missing supertype |
| noProblems &= superInterfaceRef.resolvedType.isValidBinding(); |
| } |
| // only want to reach here when no errors are reported |
| sourceType.typeBits |= (superInterface.typeBits & TypeIds.InheritableBits); |
| // further analysis against white lists for the unlikely case we are compiling java.util.stream.Stream: |
| if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) |
| sourceType.typeBits |= sourceType.applyCloseableInterfaceWhitelists(); |
| interfaceBindings[count++] = superInterface; |
| } |
| // hold onto all correctly resolved superinterfaces |
| if (count > 0) { |
| if (count != length) |
| System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count); |
| sourceType.setSuperInterfaces(interfaceBindings); |
| } |
| return noProblems; |
| } |
| |
| //{ObjectTeams: special entries for generated types. |
| /** |
| * connect hierarchy for a generate type. |
| * @param full should be do all steps of connectTypeHierarchy() or save descending for later? |
| */ |
| public void connectTypeHierarchyForGenerated(boolean full) { |
| if (full) |
| connectTypeHierarchy(); |
| else |
| connectTypeHierarchyWithoutMembers(); |
| } |
| |
| public void buildFieldsAndMethodsForLateRole(){ |
| assert ( this.referenceContext.isGenerated |
| || this.referenceContext.isPurelyCopied |
| || this.referenceContext.binding.isLocalType() |
| || this.referenceContext.isRoleFile()) : "Only applicable for late roles"; //$NON-NLS-1$ |
| buildFieldsAndMethods(); |
| } |
| //Markus Witte} |
| |
| void connectTypeHierarchy() { |
| //{ObjectTeams: |
| // already done? |
| if (StateHelper.hasState(this.referenceContext.binding, |
| ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY)) |
| return; |
| // signal proccessing: |
| if (!StateHelper.startProcessing(this.referenceContext, |
| ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY, |
| LookupEnvironment.CONNECT_TYPE_HIERARCHY)) |
| return; // catchup was blocked. |
| // SH} |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| CompilationUnitScope compilationUnitScope = compilationUnitScope(); |
| boolean wasAlreadyConnecting = compilationUnitScope.connectingHierarchy; |
| compilationUnitScope.connectingHierarchy = true; |
| try { |
| if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) == 0) { |
| sourceType.tagBits |= TagBits.BeginHierarchyCheck; |
| environment().typesBeingConnected.add(sourceType); |
| boolean noProblems = connectSuperclass(); |
| noProblems &= connectSuperInterfaces(); |
| environment().typesBeingConnected.remove(sourceType); |
| sourceType.tagBits |= TagBits.EndHierarchyCheck; |
| noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false); |
| sourceType.tagBits |= TagBits.TypeVariablesAreConnected; |
| if (noProblems && sourceType.isHierarchyInconsistent()) |
| problemReporter().hierarchyHasProblems(sourceType); |
| } |
| //{ObjectTeams: top level source super-team must be fully loaded/connected: |
| ReferenceBinding superType= sourceType.superclass; |
| if ( superType != null |
| && superType.isTeam()) |
| { |
| ReferenceBinding superOriginal = (ReferenceBinding) superType.original(); |
| if (!superOriginal.isBinaryBinding()) { |
| ClassScope superScope = ((SourceTypeBinding) superOriginal).scope; |
| if (superScope != null) |
| superScope.connectTypeHierarchy(); |
| } |
| } |
| // SH} |
| connectMemberTypes(); |
| } finally { |
| compilationUnitScope.connectingHierarchy = wasAlreadyConnecting; |
| } |
| LookupEnvironment env = environment(); |
| try { |
| env.missingClassFileLocation = this.referenceContext; |
| checkForInheritedMemberTypes(sourceType); |
| } catch (AbortCompilation e) { |
| e.updateContext(this.referenceContext, referenceCompilationUnit().compilationResult); |
| throw e; |
| } finally { |
| env.missingClassFileLocation = null; |
| } |
| } |
| |
| @Override |
| public boolean deferCheck(Runnable check) { |
| if (compilationUnitScope().connectingHierarchy) { |
| if (this.deferredBoundChecks == null) |
| this.deferredBoundChecks = new ArrayList<>(); |
| this.deferredBoundChecks.add(check); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| //{ObejctTeams: accessible from CopyInheritance: |
| /* orig: |
| private void connectTypeHierarchyWithoutMembers() { |
| :giro */ |
| public void connectTypeHierarchyWithoutMembers() { |
| // SH} |
| // must ensure the imports are resolved |
| //{ObjectTeams: RoFi? |
| if (this.referenceContext.isRoleFile()) |
| checkRoleFileImports(); |
| // SH} |
| if (this.parent instanceof CompilationUnitScope) { |
| if (((CompilationUnitScope) this.parent).imports == null) |
| ((CompilationUnitScope) this.parent).checkAndSetImports(); |
| } else if (this.parent instanceof ClassScope) { |
| // ensure that the enclosing type has already been checked |
| ((ClassScope) this.parent).connectTypeHierarchyWithoutMembers(); |
| } |
| |
| // double check that the hierarchy search has not already begun... |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) != 0) |
| return; |
| |
| CompilationUnitScope compilationUnitScope = compilationUnitScope(); |
| boolean wasAlreadyConnecting = compilationUnitScope.connectingHierarchy; |
| compilationUnitScope.connectingHierarchy = true; |
| try { |
| sourceType.tagBits |= TagBits.BeginHierarchyCheck; |
| environment().typesBeingConnected.add(sourceType); |
| boolean noProblems = connectSuperclass(); |
| noProblems &= connectSuperInterfaces(); |
| environment().typesBeingConnected.remove(sourceType); |
| sourceType.tagBits |= TagBits.EndHierarchyCheck; |
| noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false); |
| sourceType.tagBits |= TagBits.TypeVariablesAreConnected; |
| if (noProblems && sourceType.isHierarchyInconsistent()) |
| problemReporter().hierarchyHasProblems(sourceType); |
| } finally { |
| compilationUnitScope.connectingHierarchy = wasAlreadyConnecting; |
| } |
| } |
| |
| //{ObjectTeams: ROFI (to be overridden in OTClassScope) |
| protected void checkRoleFileImports() { |
| CompilationUnitScope cuScope= compilationUnitScope(); |
| if (cuScope.imports == null) |
| cuScope.checkAndSetImports(); |
| } |
| // SH} |
| |
| public boolean detectHierarchyCycle(TypeBinding superType, TypeReference reference) { |
| if (!(superType instanceof ReferenceBinding)) return false; |
| |
| if (reference == this.superTypeReference) { // see findSuperType() |
| if (superType.isTypeVariable()) |
| return false; // error case caught in resolveSuperType() |
| // abstract class X<K,V> implements java.util.Map<K,V> |
| // static abstract class M<K,V> implements Entry<K,V> |
| if (superType.isParameterizedType()) |
| superType = ((ParameterizedTypeBinding) superType).genericType(); |
| compilationUnitScope().recordSuperTypeReference(superType); // to record supertypes |
| return detectHierarchyCycle(this.referenceContext.binding, (ReferenceBinding) superType, reference); |
| } |
| // Reinstate the code deleted by the fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=205235 |
| // For details, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=294057. |
| if ((superType.tagBits & TagBits.BeginHierarchyCheck) == 0 && superType instanceof SourceTypeBinding) |
| // ensure if this is a source superclass that it has already been checked |
| ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers(); |
| |
| return false; |
| } |
| |
| // Answer whether a cycle was found between the sourceType & the superType |
| private boolean detectHierarchyCycle(SourceTypeBinding sourceType, ReferenceBinding superType, TypeReference reference) { |
| if (superType.isRawType()) |
| //{ObjectTeams: relax the cast to include half-raw dependent types: |
| /* orig: |
| superType = ((RawTypeBinding) superType).genericType(); |
| :giro */ |
| superType = ((ParameterizedTypeBinding) superType).genericType(); |
| // SH} |
| // by this point the superType must be a binary or source type |
| |
| if (TypeBinding.equalsEquals(sourceType, superType)) { |
| problemReporter().hierarchyCircularity(sourceType, superType, reference); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| return true; |
| } |
| |
| if (superType.isMemberType()) { |
| ReferenceBinding current = superType.enclosingType(); |
| do { |
| if (current.isHierarchyBeingActivelyConnected()) { |
| 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 |
| if (superType.problemId() != ProblemReasons.NotFound && (superType.tagBits & TagBits.HierarchyHasProblems) != 0) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| problemReporter().hierarchyHasProblems(sourceType); |
| return true; |
| } |
| boolean hasCycle = false; |
| ReferenceBinding parentType = superType.superclass(); |
| if (parentType != null) { |
| if (TypeBinding.equalsEquals(sourceType, parentType)) { |
| problemReporter().hierarchyCircularity(sourceType, superType, reference); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| superType.tagBits |= TagBits.HierarchyHasProblems; |
| return true; |
| } |
| if (parentType.isParameterizedType()) |
| parentType = ((ParameterizedTypeBinding) parentType).genericType(); |
| hasCycle |= detectHierarchyCycle(sourceType, parentType, reference); |
| if ((parentType.tagBits & TagBits.HierarchyHasProblems) != 0) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| parentType.tagBits |= TagBits.HierarchyHasProblems; // propagate down the hierarchy |
| } |
| } |
| |
| ReferenceBinding[] itsInterfaces = superType.superInterfaces(); |
| if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) { |
| for (int i = 0, length = itsInterfaces.length; i < length; i++) { |
| ReferenceBinding anInterface = itsInterfaces[i]; |
| if (TypeBinding.equalsEquals(sourceType, anInterface)) { |
| problemReporter().hierarchyCircularity(sourceType, superType, reference); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| superType.tagBits |= TagBits.HierarchyHasProblems; |
| return true; |
| } |
| if (anInterface.isParameterizedType()) |
| anInterface = ((ParameterizedTypeBinding) anInterface).genericType(); |
| hasCycle |= detectHierarchyCycle(sourceType, anInterface, reference); |
| if ((anInterface.tagBits & TagBits.HierarchyHasProblems) != 0) { |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| superType.tagBits |= TagBits.HierarchyHasProblems; |
| } |
| } |
| } |
| return hasCycle; |
| } |
| |
| if (superType.isHierarchyBeingActivelyConnected()) { |
| org.eclipse.jdt.internal.compiler.ast.TypeReference ref = ((SourceTypeBinding) superType).scope.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 s = (ReferenceBinding) ref.resolvedType; |
| do { |
| if (s.isHierarchyBeingActivelyConnected()) { |
| problemReporter().hierarchyCircularity(sourceType, superType, reference); |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| superType.tagBits |= TagBits.HierarchyHasProblems; |
| return true; |
| } |
| } while ((s = s.enclosingType()) != null); |
| } |
| if (ref != null && ref.resolvedType == null) { |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=319885 Don't cry foul prematurely. |
| // Check the edges traversed to see if there really is a cycle. |
| char [] referredName = ref.getLastToken(); |
| for (Iterator iter = environment().typesBeingConnected.iterator(); iter.hasNext();) { |
| SourceTypeBinding type = (SourceTypeBinding) iter.next(); |
| if (CharOperation.equals(referredName, type.sourceName())) { |
| 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 |
| if (superType.isValidBinding() && !superType.isUnresolvedType()) |
| ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers(); |
| } |
| if ((superType.tagBits & TagBits.HierarchyHasProblems) != 0) |
| sourceType.tagBits |= TagBits.HierarchyHasProblems; |
| return false; |
| } |
| |
| 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 |
| /* FIXME(SH): want to override parent.getTypeOrPackage(), call chain is: |
| * typeReference.resolveSuperType(Scope) |
| * TypeReference.getTypeBinding(Scope) |
| * Scope.getTypeOrPackage() -> loops over parents. |
| * Does OTClassScope need to override getTypeOrPackage/getPackage ?? |
| */ |
| unitScope.recordQualifiedReference(typeReference.getTypeName()); |
| this.superTypeReference = typeReference; |
| ReferenceBinding superType = (ReferenceBinding) typeReference.resolveSuperType(this); |
| //{ObjectTeams: anchor.R is not allowed in this position |
| if (superType != null && superType.isRoleType()) |
| { |
| RoleTypeBinding superRole = (RoleTypeBinding)superType; |
| if (superRole.hasExplicitAnchor()) { |
| typeReference.resolvedType = new ProblemReferenceBinding(typeReference.getTypeName(), superType, ProblemReasons.NotVisible); |
| problemReporter().externalizedRoleNotAllowedHere(typeReference, superRole); |
| return null; |
| } |
| } |
| // SH} |
| return superType; |
| } catch (AbortCompilation e) { |
| SourceTypeBinding sourceType = this.referenceContext.binding; |
| if (sourceType.superInterfaces == null) sourceType.setSuperInterfaces(Binding.NO_SUPERINTERFACES); // be more resilient for hierarchies (144976) |
| e.updateContext(typeReference, referenceCompilationUnit().compilationResult); |
| throw e; |
| } finally { |
| env.missingClassFileLocation = null; |
| this.superTypeReference = null; |
| } |
| } |
| |
| //{ObjectTeams: similar to findSupertype but for "playedBy" |
| private ReferenceBinding findBaseclass(TypeReference typeReference) { |
| CompilationUnitScope unitScope = compilationUnitScope(); |
| LookupEnvironment env = unitScope.environment; |
| try { |
| env.missingClassFileLocation = typeReference; |
| |
| // a problem be _returned_ in any case (selection may otherwise _throw_ a problem!) |
| /* orig: |
| typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes |
| :giro */ |
| // SH} |
| /* FIXME(SH): want to override parent.getTypeOrPackage(), call chain is: |
| * typeReference.resolveSuperType(Scope) |
| * TypeReference.getTypeBinding(Scope) |
| * Scope.getTypeOrPackage() -> loops over parents. |
| * Does OTClassScope need to override getTypeOrPackage/getPackage ?? |
| */ |
| unitScope.recordQualifiedReference(typeReference.getTypeName()); |
| //{ObjectTeams: preferably resolve using base import scope: |
| /* orig: |
| ReferenceBinding superType = (ReferenceBinding) typeReference.resolveSuperType(this); |
| */ |
| typeReference.deprecationProblemId = IProblem.DeprecatedBaseclass; |
| ReferenceBinding superType; |
| if (typeReference.checkResolveUsingBaseImportScope(this, 0, false) != null) { |
| superType = (ReferenceBinding)typeReference.resolvedType; |
| } else { |
| superType = (ReferenceBinding) typeReference.resolveSuperType(this); |
| if (isImportedType(typeReference)) { |
| problemReporter().regularlyImportedBaseclass(typeReference); |
| } else if ( typeReference instanceof QualifiedTypeReference // could mean several things: |
| && superType != null && superType.isValidBinding()) // (only investigate if valid) |
| { |
| if ( !RoleTypeBinding.isRoleWithExplicitAnchor(superType) // old style externalized still tolerated |
| && ((QualifiedTypeReference)typeReference).tokens.length > superType.depth()+1) // if lenght == depth+1: qualifiation by enclosing types only |
| { |
| problemReporter().qualifiedReferenceToBaseclass(typeReference); // qualified unimported base class is deprecated |
| } |
| } |
| } |
| return superType; |
| } catch (AbortCompilation e) { |
| e.updateContext(typeReference, referenceCompilationUnit().compilationResult); |
| throw e; |
| } finally { |
| env.missingClassFileLocation = null; |
| } |
| } |
| |
| private boolean isImportedType(TypeReference typeReference) |
| { |
| if (!(typeReference instanceof SingleTypeReference) || (typeReference instanceof IAlienScopeTypeReference)) |
| return false; |
| if (typeReference instanceof ParameterizedSingleTypeReference) { |
| ParameterizedSingleTypeReference paramType = (ParameterizedSingleTypeReference) typeReference; |
| if (paramType.typeAnchors != null && paramType.typeAnchors.length>0) |
| return false; // resolved via anchor not via import |
| } |
| TypeBinding type= typeReference.resolvedType; |
| if (type == null || !type.isValidBinding() || !(type instanceof ReferenceBinding)) |
| return false; |
| PackageBinding aPackage= ((ReferenceBinding)type).fPackage; |
| return aPackage != getCurrentPackage() |
| && !CharOperation.equals(aPackage.compoundName, TypeConstants.JAVA_LANG); |
| } |
| // SH} |
| |
| /* 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. |
| */ |
| @Override |
| public ProblemReporter problemReporter() { |
| MethodScope outerMethodScope; |
| if ((outerMethodScope = outerMostMethodScope()) == null) { |
| ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; |
| problemReporter.referenceContext = this.referenceContext; |
| return problemReporter; |
| } |
| return outerMethodScope.problemReporter(); |
| } |
| |
| /* Answer the reference type of this scope. |
| * It is the nearest enclosing type of this scope. |
| */ |
| @Override |
| public TypeDeclaration referenceType() { |
| return this.referenceContext; |
| } |
| |
| @Override |
| public boolean hasDefaultNullnessFor(int location, int sourceStart) { |
| int nonNullByDefaultValue = localNonNullByDefaultValue(sourceStart); |
| if (nonNullByDefaultValue != 0) { |
| return (nonNullByDefaultValue & location) != 0; |
| } |
| SourceTypeBinding binding = this.referenceContext.binding; |
| if (binding != null) { |
| int nullDefault = binding.getNullDefault(); |
| if (nullDefault != 0) { |
| return (nullDefault & location) != 0; |
| } |
| } |
| return this.parent.hasDefaultNullnessFor(location, sourceStart); |
| } |
| |
| @Override |
| public /* @Nullable */ Binding checkRedundantDefaultNullness(int nullBits, int sourceStart) { |
| Binding target = localCheckRedundantDefaultNullness(nullBits, sourceStart); |
| if (target != null) { |
| return target; |
| } |
| SourceTypeBinding binding = this.referenceContext.binding; |
| if (binding != null) { |
| int nullDefault = binding.getNullDefault(); |
| if (nullDefault != 0) { |
| return (nullDefault == nullBits) ? binding : null; |
| } |
| } |
| return this.parent.checkRedundantDefaultNullness(nullBits, sourceStart); |
| } |
| |
| @Override |
| public String toString() { |
| if (this.referenceContext != null) |
| return "--- Class Scope ---\n\n" //$NON-NLS-1$ |
| + this.referenceContext.binding.toString(); |
| return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$ |
| } |
| //{ObjectTeams: does this class's compulation unit have ignoreFurtherInvestigation set? |
| public boolean cuIgnoreFurtherInvestigation() { |
| return referenceCompilationUnit() == null || referenceCompilationUnit().ignoreFurtherInvestigation; |
| } |
| // SH} |
| } |