blob: 97bb12728f75d380707e7bfe015969e9af2b83b7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2012 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 - Contribution for
* Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.OTClassScope;
/**
* OTDT changes:
*
* What: Support decapsulation.
*
* What: Support resolve using base import scope.
*/
public class SingleTypeReference extends TypeReference {
public char[] token;
public SingleTypeReference(char[] source, long pos) {
this.token = source;
this.sourceStart = (int) (pos>>>32) ;
this.sourceEnd = (int) (pos & 0x00000000FFFFFFFFL) ;
}
@Override
public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) {
int totalDimensions = this.dimensions() + additionalDimensions;
Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations);
ArrayTypeReference arrayTypeReference = new ArrayTypeReference(this.token, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd);
arrayTypeReference.annotations = this.annotations;
arrayTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations);
if (!isVarargs)
arrayTypeReference.extendedDimensions = additionalDimensions;
return arrayTypeReference;
}
@Override
public char[] getLastToken() {
return this.token;
}
@Override
protected TypeBinding getTypeBinding(Scope scope) {
if (this.resolvedType != null)
return this.resolvedType;
this.resolvedType = scope.getType(this.token);
if (this.resolvedType instanceof TypeVariableBinding) {
TypeVariableBinding typeVariable = (TypeVariableBinding) this.resolvedType;
if (typeVariable.declaringElement instanceof SourceTypeBinding) {
scope.tagAsAccessingEnclosingInstanceStateOf((ReferenceBinding) typeVariable.declaringElement, true /* type variable access */);
}
} else if (this.resolvedType instanceof LocalTypeBinding) {
LocalTypeBinding localType = (LocalTypeBinding) this.resolvedType;
MethodScope methodScope = scope.methodScope();
if (methodScope != null && !methodScope.isStatic) {
methodScope.tagAsAccessingEnclosingInstanceStateOf(localType, false /* ! type variable access */);
}
}
if (scope.kind == Scope.CLASS_SCOPE && this.resolvedType.isValidBinding())
if (((ClassScope) scope).detectHierarchyCycle(this.resolvedType, this))
return null;
return this.resolvedType;
}
@Override
public char [][] getTypeName() {
return new char[][] { this.token };
}
@Override
public boolean isBaseTypeReference() {
return this.token == BYTE ||
this.token == SHORT ||
this.token == INT ||
this.token == LONG ||
this.token == FLOAT ||
this.token == DOUBLE ||
this.token == CHAR ||
this.token == BOOLEAN ||
this.token == NULL ||
this.token == VOID;
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output){
if (this.annotations != null && this.annotations[0] != null) {
printAnnotations(this.annotations[0], output);
output.append(' ');
}
return output.append(this.token);
}
public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) {
this.resolvedType = scope.getMemberType(this.token, enclosingType);
//{ObjectTeams: decapsulation:
if (this.resolvedType.problemId() == ProblemReasons.NotVisible) {
switch(this.getBaseclassDecapsulation()) {
case ALLOWED:
scope.problemReporter().decapsulation(this);
//$FALL-THROUGH$
case REPORTED:
this.resolvedType= ((ProblemReferenceBinding)this.resolvedType).closestMatch();
}
}
// SH}
boolean hasError = false;
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=391500
resolveAnnotations(scope, 0); // defaultNullness not relevant, the only caller within the compiler: QAE
TypeBinding memberType = this.resolvedType; // load after possible update in resolveAnnotations()
if (!memberType.isValidBinding()) {
hasError = true;
scope.problemReporter().invalidEnclosingType(this, memberType, enclosingType);
memberType = ((ReferenceBinding)memberType).closestMatch();
if (memberType == null) {
return null;
}
}
if (isTypeUseDeprecated(memberType, scope))
reportDeprecatedType(memberType, scope);
memberType = scope.environment().convertToRawType(memberType, false /*do not force conversion of enclosing types*/);
if (memberType.isRawType()
&& (this.bits & IgnoreRawTypeCheck) == 0
&& scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){
scope.problemReporter().rawTypeReference(this, memberType);
}
if (hasError) {
// do not store the computed type, keep the problem type instead
return memberType;
}
return this.resolvedType = memberType;
}
//{ObjectTeams: for base-imported types (only single is supported):
@Override
public TypeBinding checkResolveUsingBaseImportScope(Scope scope, int location, boolean tolerate) {
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;
}
// 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);
}
}
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);
}
}
visitor.endVisit(this, scope);
}
}