blob: 4a630bebe1aa38d340bf39f9f535cad2de4f7080 [file] [log] [blame]
/*******************************************************************************
* 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 - Contributions for
* bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding
* Bug 420894 - ClassCastException in DefaultBindingResolver.resolveType(Type)
* bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
* Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
* Bug 434600 - Incorrect null analysis error reporting on type parameters
* Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E"
* Bug 456508 - Unexpected RHS PolyTypeBinding for: <code-snippet>
* Bug 466713 - Null Annotations: NullPointerException using <int @Nullable []> as Type Param
* Andy Clement - Contributions for
* Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference;
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.lookup.DependentTypeBinding;
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.ProblemAnchorBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer;
/**
* OTDT changes:
* What: support baseclass decapsulation
*
* What: support value parameters
*
* Syntactic representation of a reference to a generic type.
* Note that it might also have a dimension.
*/
public class ParameterizedSingleTypeReference extends ArrayTypeReference {
public static final TypeBinding[] DIAMOND_TYPE_ARGUMENTS = new TypeBinding[0];
public TypeReference[] typeArguments;
//{ObjectTeams: anchor(s):
public TypeAnchorReference[] typeAnchors;
// decapsulation:
@Override
public void setBaseclassDecapsulation(DecapsulationState state) {
super.setBaseclassDecapsulation(state);
if (this.typeArguments != null)
for (TypeReference argument : this.typeArguments)
if (argument != null)
argument.setBaseclassDecapsulation(state);
}
// SH}
public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos){
super(name, dim, pos);
this.originalSourceEnd = this.sourceEnd;
this.typeArguments = typeArguments;
for (int i = 0, max = typeArguments.length; i < max; i++) {
if ((typeArguments[i].bits & ASTNode.HasTypeAnnotations) != 0) {
this.bits |= ASTNode.HasTypeAnnotations;
break;
}
}
}
public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long pos) {
this(name, typeArguments, dim, pos);
setAnnotationsOnDimensions(annotationsOnDimensions);
if (annotationsOnDimensions != null) {
this.bits |= ASTNode.HasTypeAnnotations;
}
}
@Override
public void checkBounds(Scope scope) {
if (this.resolvedType == null) return;
if (this.resolvedType.leafComponentType() instanceof ParameterizedTypeBinding) {
ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) this.resolvedType.leafComponentType();
TypeBinding[] argTypes = parameterizedType.arguments;
if (argTypes != null) { // may be null in error cases
parameterizedType.boundCheck(scope, this.typeArguments);
}
}
}
@Override
public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) {
int totalDimensions = this.dimensions() + additionalDimensions;
Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations);
ParameterizedSingleTypeReference parameterizedSingleTypeReference = new ParameterizedSingleTypeReference(this.token, this.typeArguments, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd);
parameterizedSingleTypeReference.annotations = this.annotations;
parameterizedSingleTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations);
if (!isVarargs)
parameterizedSingleTypeReference.extendedDimensions = additionalDimensions;
return parameterizedSingleTypeReference;
}
/**
* @return char[][]
*/
@Override
public char [][] getParameterizedTypeName(){
StringBuffer buffer = new StringBuffer(5);
buffer.append(this.token).append('<');
//{ObjectTeams: type anchors?
boolean haveOne = false;
if (this.typeAnchors != null) {
for (int i = 0, length = this.typeAnchors.length; i < length; i++) {
if (i > 0) buffer.append(',');
buffer.append(CharOperation.concatWith(this.typeAnchors[i].getParameterizedTypeName(), '.'));
haveOne = true;
}
}
// SH}
for (int i = 0, length = this.typeArguments.length; i < length; i++) {
//{ObjectTeams:
if (haveOne)
buffer.append(',');
else
// SH}
if (i > 0) buffer.append(',');
buffer.append(CharOperation.concatWith(this.typeArguments[i].getParameterizedTypeName(), '.'));
}
buffer.append('>');
int nameLength = buffer.length();
char[] name = new char[nameLength];
buffer.getChars(0, nameLength, name, 0);
int dim = this.dimensions;
if (dim > 0) {
char[] dimChars = new char[dim*2];
for (int i = 0; i < dim; i++) {
int index = i*2;
dimChars[index] = '[';
dimChars[index+1] = ']';
}
name = CharOperation.concat(name, dimChars);
}
return new char[][]{ name };
}
@Override
public TypeReference[][] getTypeArguments() {
return new TypeReference[][] { this.typeArguments };
}
/**
* @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
*/
@Override
protected TypeBinding getTypeBinding(Scope scope) {
return null; // not supported here - combined with resolveType(...)
}
@Override
public boolean isParameterizedTypeReference() {
return true;
}
@Override
public boolean hasNullTypeAnnotation(AnnotationPosition position) {
if (super.hasNullTypeAnnotation(position))
return true;
if (position == AnnotationPosition.ANY) {
if (this.resolvedType != null && !this.resolvedType.hasNullTypeAnnotations())
return false; // shortcut
if (this.typeArguments != null) {
for (int i = 0; i < this.typeArguments.length; i++) {
if (this.typeArguments[i].hasNullTypeAnnotation(position))
return true;
}
}
}
return false;
}
/*
* No need to check for reference to raw type per construction
*/
private TypeBinding internalResolveType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds, int location) {
// handle the error here
this.constant = Constant.NotAConstant;
if ((this.bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved
if (this.resolvedType != null) { // is a shared type reference which was already resolved
if (this.resolvedType.isValidBinding()) {
return this.resolvedType;
} else {
switch (this.resolvedType.problemId()) {
case ProblemReasons.NotFound :
case ProblemReasons.NotVisible :
case ProblemReasons.InheritedNameHidesEnclosingName :
TypeBinding type = this.resolvedType.closestMatch();
return type;
default :
return null;
}
}
}
}
this.bits |= ASTNode.DidResolve;
//{ObjectTeams: check team anchor first:
for (int typeParamPos=0; typeParamPos<this.typeArguments.length; typeParamPos++) {
if (this.typeArguments[typeParamPos] instanceof TypeAnchorReference)
{
TypeAnchorReference typeAnchorReference = (TypeAnchorReference)this.typeArguments[typeParamPos];
ITeamAnchor anchor = typeAnchorReference.resolveAnchor(scope);
if (!ProblemAnchorBinding.checkAnchor(scope, typeAnchorReference, anchor, this.token)) {
int problemId = anchor != null ? anchor.problemId() : ProblemReasons.AnchorNotFound;
return this.resolvedType = new ProblemReferenceBinding(anchor, typeAnchorReference.getLastToken(), null, problemId);
}
for (ITeamAnchor seg : anchor.getBestNamePath())
if (!seg.isFinal())
scope.problemReporter().anchorPathNotFinal(typeAnchorReference, seg, this.token);
// proceed to possibly report more errors
// try member type (role) of anchor's type (team):
this.resolvedType = anchor.resolveRoleType(this.token, this.dimensions); // FIXME(SH): although contained in a loop only one anchor can win
if (this.resolvedType == null) {
// not a role type try type with explicit value anchor:
this.resolvedType = scope.getType(this.token); // resolve raw type (premature, see below).
if (this.resolvedType.isTypeVariable()) {
ITeamAnchor[] declaredAnchors = ((TypeVariableBinding)this.resolvedType).anchors;
if (declaredAnchors != null && typeParamPos < declaredAnchors.length && declaredAnchors[typeParamPos].isValidBinding())
if (!declaredAnchors[typeParamPos].hasSameBestNameAs(anchor))
scope.problemReporter().rebindingTypeVariableAnchor(this, typeAnchorReference, declaredAnchors[typeParamPos]);
}
this.resolvedType = typeAnchorReference.createDependentTypeBinding(scope, this, typeParamPos);
if (this.resolvedType == null) {
this.resolvedType = new ProblemReferenceBinding(anchor, this.token, null, ProblemReasons.NotFound);
return this.resolvedType;
}
}
if (this.resolvedType != null && this.resolvedType.isValidBinding() && this.resolvedType instanceof ReferenceBinding) {
if (!checkParameterizedRoleVisibility(scope, anchor, (ReferenceBinding) this.resolvedType))
return this.resolvedType;
}
if ( shouldAnalyzeRoleReference()
&& isIllegalQualifiedUseOfProtectedRole(scope))
return this.resolvedType; // problem binding may be in this.resolvedType
// consume first arg:
int len = 0;
if (this.typeAnchors != null) {
len = this.typeAnchors.length;
System.arraycopy(this.typeAnchors, 0,
this.typeAnchors = new TypeAnchorReference[len+1], 0, len);
} else {
this.typeAnchors = new TypeAnchorReference[1];
}
this.typeAnchors[len] = typeAnchorReference;
len = this.typeArguments.length-1;
System.arraycopy(this.typeArguments, 1,
this.typeArguments = new TypeReference[len], 0, len); // FIXME(SH): reducing this array conflicts with loop condition
// note: handling of arrays differs for role and regular types
if (len == 0) {
resolveAnnotations(scope, location);
return this.resolvedType; // we're done
}
// proceed with a word of warning:
scope.problemReporter().experimentalFeature(this, "Implementation for mixed type and value parameters is experimental.");
}
}
// find a base import scope if that's allowed:
CompilationUnitScope importScope = null;
if (getBaseclassDecapsulation().isAllowed()) {
Scope currentScope = scope;
while (currentScope != null) {
if (currentScope instanceof OTClassScope) {
importScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
if (importScope != null)
break;
}
currentScope = currentScope.parent;
}
}
TypeBinding type = internalResolveLeafType(importScope, scope, enclosingType, checkBounds);
/* orig:
TypeBinding type = internalResolveLeafType(scope, enclosingType, checkBounds);
:giro */
if (importScope != null)
importScope.originalScope = null;
// SH}
// handle three different outcomes:
if (type == null) {
this.resolvedType = createArrayType(scope, this.resolvedType);
resolveAnnotations(scope, 0); // no defaultNullness for buggy type
return null; // (1) no useful type, but still captured dimensions into this.resolvedType
} else {
type = createArrayType(scope, type);
if (!this.resolvedType.isValidBinding() && this.resolvedType.dimensions() == type.dimensions()) {
resolveAnnotations(scope, 0); // no defaultNullness for buggy type
return type; // (2) found some error, but could recover useful type (like closestMatch)
} else {
this.resolvedType = type; // (3) no complaint, keep fully resolved type (incl. dimensions)
resolveAnnotations(scope, location);
if(this.dimensions > 0) {
this.resolvedType = ArrayTypeReference.maybeMarkArrayContentsNonNull(scope, this.resolvedType, this.sourceStart, this.dimensions,
leafType -> this.leafComponentTypeWithoutDefaultNullness = leafType);
}
return this.resolvedType; // pick up any annotated type.
}
}
}
//{ObjectTeams: consider two scopes (base imports, regular):
private TypeBinding internalResolveLeafType(Scope importScope, Scope scope, ReferenceBinding enclosingType, boolean checkBounds) {
/* orig:
private TypeBinding internalResolveLeafType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds) {
*/
ReferenceBinding currentType;
if (enclosingType == null) {
//:giro
if (importScope != null)
this.resolvedType = importScope.getType(this.token);
if (this.resolvedType == null || this.resolvedType.problemId() == ProblemReasons.NotFound)
// SH}
this.resolvedType = scope.getType(this.token);
if (this.resolvedType.isValidBinding()) {
currentType = (ReferenceBinding) this.resolvedType;
} else {
reportInvalidType(scope);
switch (this.resolvedType.problemId()) {
case ProblemReasons.NotFound :
case ProblemReasons.NotVisible :
case ProblemReasons.InheritedNameHidesEnclosingName :
TypeBinding type = this.resolvedType.closestMatch();
if (type instanceof ReferenceBinding) {
currentType = (ReferenceBinding) type;
break;
}
//$FALL-THROUGH$ - unable to complete type binding, but still resolve type arguments
default :
boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
int argLength = this.typeArguments.length;
for (int i = 0; i < argLength; i++) {
TypeReference typeArgument = this.typeArguments[i];
if (isClassScope) {
typeArgument.resolveType((ClassScope) scope);
} else {
typeArgument.resolveType((BlockScope) scope, checkBounds);
}
}
return null;
}
// be resilient, still attempt resolving arguments
}
enclosingType = currentType.enclosingType(); // if member type
if (enclosingType != null && currentType.hasEnclosingInstanceContext()) {
enclosingType = scope.environment().convertToParameterizedType(enclosingType);
}
} else { // resolving member type (relatively to enclosingType)
this.resolvedType = currentType = scope.getMemberType(this.token, enclosingType);
if (!this.resolvedType.isValidBinding()) {
scope.problemReporter().invalidEnclosingType(this, currentType, enclosingType);
return null;
}
if (isTypeUseDeprecated(currentType, scope))
scope.problemReporter().deprecatedType(currentType, this);
ReferenceBinding currentEnclosing = currentType.enclosingType();
if (currentEnclosing != null && TypeBinding.notEquals(currentEnclosing.erasure(), enclosingType.erasure())) {
enclosingType = currentEnclosing; // inherited member type, leave it associated with its enclosing rather than subtype
}
}
// check generic and arity
boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
TypeReference keep = null;
if (isClassScope) {
keep = ((ClassScope) scope).superTypeReference;
((ClassScope) scope).superTypeReference = null;
}
final boolean isDiamond = (this.bits & ASTNode.IsDiamond) != 0;
int argLength = this.typeArguments.length;
TypeBinding[] argTypes = new TypeBinding[argLength];
boolean argHasError = false;
ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original();
for (int i = 0; i < argLength; i++) {
TypeReference typeArgument = this.typeArguments[i];
//{ObjectTeams: limitation (value parameter other than 1st position).
if (typeArgument instanceof TypeAnchorReference) {
scope.problemReporter().incompleteDependentTypesImplementation(typeArgument,
"type value parameter must be in 1st position"); //$NON-NLS-1$
argHasError = true;
continue;
}
// SH}
TypeBinding argType = isClassScope
? typeArgument.resolveTypeArgument((ClassScope) scope, currentOriginal, i)
: typeArgument.resolveTypeArgument((BlockScope) scope, currentOriginal, i);
this.bits |= (typeArgument.bits & ASTNode.HasTypeAnnotations);
if (argType == null) {
argHasError = true;
} else {
//{ObjectTeams:
argType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, argType, typeArgument);
// SH}
argTypes[i] = argType;
}
}
if (argHasError) {
return null;
}
if (isClassScope) {
((ClassScope) scope).superTypeReference = keep;
if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this))
return null;
}
TypeVariableBinding[] typeVariables = currentOriginal.typeVariables();
if (typeVariables == Binding.NO_TYPE_VARIABLES) { // non generic invoked with arguments
boolean isCompliant15 = scope.compilerOptions().originalSourceLevel >= ClassFileConstants.JDK1_5;
if ((currentOriginal.tagBits & TagBits.HasMissingType) == 0) {
if (isCompliant15) { // below 1.5, already reported as syntax error
this.resolvedType = currentType;
scope.problemReporter().nonGenericTypeCannotBeParameterized(0, this, currentType, argTypes);
return null;
}
}
// resilience do not rebuild a parameterized type unless compliance is allowing it
if (!isCompliant15) {
if (!this.resolvedType.isValidBinding())
return currentType;
return this.resolvedType = currentType;
}
// if missing generic type, and compliance >= 1.5, then will rebuild a parameterized binding
} else if (argLength != typeVariables.length) {
if (!isDiamond) { // check arity, IsDiamond never set for 1.6-
scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
return null;
}
} else if (!currentType.isStatic()) {
ReferenceBinding actualEnclosing = currentType.enclosingType();
if (actualEnclosing != null && actualEnclosing.isRawType()){
scope.problemReporter().rawMemberTypeCannotBeParameterized(
this, scope.environment().createRawType(currentOriginal, actualEnclosing), argTypes);
return null;
}
}
//{ObjectTeams: already done?
if (!isDiamond && argLength == 0)
return this.resolvedType;
// feed more parameters into createParameterizedType:
AnnotationBinding[] currentAnnotations = currentType.getTypeAnnotations();
ITeamAnchor anchor = null;
int valParPos = -1;
if (currentType instanceof DependentTypeBinding) {
anchor = ((DependentTypeBinding)currentType)._teamAnchor;
valParPos = ((DependentTypeBinding)currentType)._valueParamPosition;
}
ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, anchor, valParPos, enclosingType, currentAnnotations);
/* orig:
ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, enclosingType);
:giro */
// SH}
// check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference.
if (!isDiamond) {
if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
parameterizedType.boundCheck(scope, this.typeArguments);
else
scope.deferBoundCheck(this);
} else {
parameterizedType.arguments = DIAMOND_TYPE_ARGUMENTS;
}
if (isTypeUseDeprecated(parameterizedType, scope))
reportDeprecatedType(parameterizedType, scope);
checkIllegalNullAnnotations(scope, this.typeArguments);
if (!this.resolvedType.isValidBinding()) {
return parameterizedType;
}
return this.resolvedType = parameterizedType;
}
private TypeBinding createArrayType(Scope scope, TypeBinding type) {
if (this.dimensions > 0) {
if (this.dimensions > 255)
scope.problemReporter().tooManyDimensions(this);
return scope.createArrayType(type, this.dimensions);
}
return type;
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output){
if (this.annotations != null && this.annotations[0] != null) {
printAnnotations(this.annotations[0], output);
output.append(' ');
}
output.append(this.token);
output.append("<"); //$NON-NLS-1$
int length = this.typeArguments.length;
//{ObjectTeams: value parameters:
if (this.typeAnchors != null) {
int anchorLen = this.typeAnchors.length;
for (int i = 0; i < anchorLen; i++) {
this.typeAnchors[i].print(0, output);
if (i+1 < anchorLen || length > 0)
output.append(", "); //$NON-NLS-1$
}
}
// SH}
if (length > 0) {
int max = length - 1;
for (int i= 0; i < max; i++) {
this.typeArguments[i].print(0, output);
output.append(", ");//$NON-NLS-1$
}
this.typeArguments[max].print(0, output);
}
output.append(">"); //$NON-NLS-1$
Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions();
if ((this.bits & IsVarArgs) != 0) {
for (int i= 0 ; i < this.dimensions - 1; i++) {
if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
output.append(" "); //$NON-NLS-1$
printAnnotations(annotationsOnDimensions[i], output);
output.append(" "); //$NON-NLS-1$
}
output.append("[]"); //$NON-NLS-1$
}
if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) {
output.append(" "); //$NON-NLS-1$
printAnnotations(annotationsOnDimensions[this.dimensions - 1], output);
output.append(" "); //$NON-NLS-1$
}
output.append("..."); //$NON-NLS-1$
} else {
for (int i= 0 ; i < this.dimensions; i++) {
if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
output.append(" "); //$NON-NLS-1$
printAnnotations(annotationsOnDimensions[i], output);
output.append(" "); //$NON-NLS-1$
}
output.append("[]"); //$NON-NLS-1$
}
}
return output;
}
@Override
public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) {
return internalResolveType(scope, null, checkBounds, location);
}
@Override
public TypeBinding resolveType(ClassScope scope, int location) {
return internalResolveType(scope, null, false /*no bounds check in classScope*/, location);
}
@Override
public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) {
return internalResolveType(scope, enclosingType, true/*check bounds*/, 0);
}
//{ObjectTeams: resolve helpers
// for base-imported types (only single is supported):
@Override
public TypeBinding checkResolveUsingBaseImportScope(Scope scope, int location, boolean tolerate) {
// same as in SingleTypeReference:
if ( this.getBaseclassDecapsulation().isAllowed()
|| tolerate
|| scope.isBaseGuard())
{
TypeBinding problem = this.resolvedType;
this.resolvedType = null; // force re-computation in getTypeBinding()
Scope currentScope = scope;
while (currentScope != null) {
if (currentScope instanceof OTClassScope) {
CompilationUnitScope baseImportScope = ((OTClassScope)currentScope).getBaseImportScope(scope);
if (baseImportScope != null) {
try {
this.resolvedType = getTypeBinding(baseImportScope);
if (this.resolvedType != null && this.resolvedType.isValidBinding())
return this.resolvedType = checkResolvedType(this.resolvedType, baseImportScope, location, false);
} finally {
baseImportScope.originalScope = null;
}
}
}
currentScope = currentScope.parent;
}
this.resolvedType = problem;
}
return null;
}
// check for externalized role's visibility
boolean checkParameterizedRoleVisibility(Scope scope, ITeamAnchor anchor, ReferenceBinding type) {
if (!type.isPublic()) {
Dependencies.ensureBindingState(type, ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY);
if (RoleTypeBinding.isRoleWithExplicitAnchor(type)) {
if (TypeAnalyzer.isConfined(type)) {
// confined has highest priority for reporting / doesn't allow decapsulation
scope.problemReporter().decapsulatingConfined(this, (ReferenceBinding)this.resolvedType);
setBaseclassDecapsulation(DecapsulationState.CONFINED);
this.resolvedType = new ProblemReferenceBinding(anchor, this.token, type, ProblemReasons.NotVisible);
return false;
} else {
// externalized non-public role
switch (getBaseclassDecapsulation()) {
case ALLOWED:
scope.problemReporter().decapsulation(this, type);
setBaseclassDecapsulation(DecapsulationState.REPORTED);
//$FALL-THROUGH$
case REPORTED:
case TOLERATED:
return true;
case NONE:
this.resolvedType = new ProblemReferenceBinding(anchor, this.token, type, ProblemReasons.NotVisible);
scope.problemReporter().qualifiedProtectedRole(this, type);
return false;
case CONFINED:
return false;
}
}
} else if (!type.canBeSeenBy(scope)) {
// other invisible types
this.resolvedType = new ProblemReferenceBinding(anchor, this.token, type, ProblemReasons.NotVisible);
reportInvalidType(scope);
return false;
}
}
return true;
}
// SH}
@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
if (this.annotations != null) {
Annotation [] typeAnnotations = this.annotations[0];
for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) {
typeAnnotations[i].traverse(visitor, scope);
}
}
Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
if (annotationsOnDimensions != null) {
for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
Annotation[] annotations2 = annotationsOnDimensions[i];
if (annotations2 != null) {
for (int j = 0, max2 = annotations2.length; j < max2; j++) {
Annotation annotation = annotations2[j];
annotation.traverse(visitor, scope);
}
}
}
}
for (int i = 0, max = this.typeArguments.length; i < max; i++) {
this.typeArguments[i].traverse(visitor, scope);
}
}
visitor.endVisit(this, scope);
}
@Override
public void traverse(ASTVisitor visitor, ClassScope scope) {
if (visitor.visit(this, scope)) {
if (this.annotations != null) {
Annotation [] typeAnnotations = this.annotations[0];
for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) {
typeAnnotations[i].traverse(visitor, scope);
}
}
Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
if (annotationsOnDimensions != null) {
for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
Annotation[] annotations2 = annotationsOnDimensions[i];
for (int j = 0, max2 = annotations2.length; j < max2; j++) {
Annotation annotation = annotations2[j];
annotation.traverse(visitor, scope);
}
}
}
for (int i = 0, max = this.typeArguments.length; i < max; i++) {
this.typeArguments[i].traverse(visitor, scope);
}
}
visitor.endVisit(this, scope);
}
//{ObjectTeams: API for OT-Model:
/**
* API for OT-Model:
* If typeReference is an anchored type, return the qualified name of the type anchor.
*/
public static char[][] getTypeAnchor(TypeReference typeReference) {
if (typeReference instanceof ParameterizedSingleTypeReference) {
ParameterizedSingleTypeReference type= (ParameterizedSingleTypeReference)typeReference;
if (type.resolvedType != null) {
// after resolve use typeAnchors:
TypeAnchorReference[] anchors= type.typeAnchors;
if (anchors != null && anchors.length == 1)
return beautifyTypeAnchor(anchors[0].getTypeName());
} else {
if (type.typeArguments != null && type.typeArguments.length > 0) {
TypeReference first= type.typeArguments[0];
if (first instanceof TypeAnchorReference) {
char[][] anchorName= first.getTypeName();
anchorName[0] = CharOperation.subarray(anchorName[0], 1, -1); // chop off '@'
return beautifyTypeAnchor(anchorName);
}
}
}
}
return null;
}
private static char[][] beautifyTypeAnchor(char[][] orig) {
int len= orig.length;
if (!CharOperation.equals(orig[len-1], IOTConstants._OT_BASE))
return orig;
char[][] result= new char[len][];
System.arraycopy(orig, 0, result, 0, len-1);
result[len-1]= IOTConstants.BASE;
return result;
}
// SH}
}