package org.eclipse.jdt.internal.compiler.ast;
import java.util.List;
import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.Util;
@SuppressWarnings("rawtypes")
public class FieldDeclaration extends AbstractVariableDeclaration {
public FieldBinding binding;
public Javadoc javadoc;
public int endPart1Position;
public int endPart2Position;
public FieldDeclaration() {
}
public FieldDeclaration( char[] name, int sourceStart, int sourceEnd) {
this.name = name;
this.sourceStart = sourceStart;
this.sourceEnd = sourceEnd;
}
public FlowInfo analyseCode(MethodScope initializationScope, FlowContext flowContext, FlowInfo flowInfo) {
if (this.binding != null && !this.binding.isUsed() && this.binding.isOrEnclosedByPrivateType()) {
if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
initializationScope.problemReporter().unusedPrivateField(this);
}
}
if (this.binding != null
&& this.binding.isValidBinding()
&& this.binding.isStatic()
&& this.binding.constant(initializationScope) == Constant.NotAConstant
&& this.binding.declaringClass.isNestedType()
&& !this.binding.declaringClass.isStatic()) {
initializationScope.problemReporter().unexpectedStaticModifierForField(
(SourceTypeBinding) this.binding.declaringClass,
this);
}
if (this.initialization != null) {
flowInfo =
this.initialization
.analyseCode(initializationScope, flowContext, flowInfo)
.unconditionalInits();
flowInfo.markAsDefinitelyAssigned(this.binding);
}
if (this.initialization != null && this.binding != null) {
CompilerOptions options = initializationScope.compilerOptions();
if (options.isAnnotationBasedNullAnalysisEnabled) {
if (this.binding.isNonNull() || options.sourceLevel >= ClassFileConstants.JDK1_8) {
int nullStatus = this.initialization.nullStatus(flowInfo, flowContext);
NullAnnotationMatching.checkAssignment(initializationScope, flowContext, this.binding, flowInfo, nullStatus, this.initialization, this.initialization.resolvedType);
}
}
this.initialization.checkNPEbyUnboxing(initializationScope, flowContext, flowInfo);
}
return flowInfo;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((this.bits & IsReachable) == 0) {
return;
}
int pc = codeStream.position;
boolean isStatic;
if (this.initialization != null
&& !((isStatic = this.binding.isStatic()) && this.binding.constant() != Constant.NotAConstant)) {
if (!isStatic)
codeStream.aload_0();
this.initialization.generateCode(currentScope, codeStream, true);
if (isStatic) {
codeStream.fieldAccess(Opcodes.OPC_putstatic, this.binding, null );
} else {
codeStream.fieldAccess(Opcodes.OPC_putfield, this.binding, null );
}
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) {
AnnotationCollector collector = new AnnotationCollector(this.type, targetType, allAnnotationContexts);
for (int i = 0, max = this.annotations.length; i < max; i++) {
Annotation annotation = this.annotations[i];
annotation.traverse(collector, (BlockScope) null);
}
}
@Override
public int getKind() {
return this.type == null ? ENUM_CONSTANT : FIELD;
}
public boolean isStatic() {
if (this.binding != null)
return this.binding.isStatic();
return (this.modifiers & ClassFileConstants.AccStatic) != 0;
}
public boolean isFinal() {
if (this.binding != null)
return this.binding.isFinal();
return (this.modifiers & ClassFileConstants.AccFinal) != 0;
}
@Override
public StringBuffer printStatement(int indent, StringBuffer output) {
if (this.javadoc != null) {
this.javadoc.print(indent, output);
}
return super.printStatement(indent, output);
}
public void resolve(MethodScope initializationScope) {
if ((this.bits & ASTNode.HasBeenResolved) != 0) return;
if (this.binding == null || !this.binding.isValidBinding()) return;
this.bits |= ASTNode.HasBeenResolved;
ClassScope classScope = initializationScope.enclosingClassScope();
if (classScope != null) {
checkHiding: {
SourceTypeBinding declaringType = classScope.enclosingSourceType();
checkHidingSuperField: {
if (declaringType.superclass == null) break checkHidingSuperField;
FieldBinding existingVariable = classScope.findField(declaringType.superclass, this.name, this, false , true );
if (existingVariable == null) break checkHidingSuperField;
if (!existingVariable.isValidBinding()) break checkHidingSuperField;
if (existingVariable.original() == this.binding) break checkHidingSuperField;
if (!existingVariable.canBeSeenBy(declaringType, this, initializationScope)) break checkHidingSuperField;
initializationScope.problemReporter().fieldHiding(this, existingVariable);
break checkHiding;
}
Scope outerScope = classScope.parent;
if (outerScope.kind == Scope.COMPILATION_UNIT_SCOPE) break checkHiding;
Binding existingVariable = outerScope.getBinding(this.name, Binding.VARIABLE, this, false );
if (existingVariable == null) break checkHiding;
if (!existingVariable.isValidBinding()) break checkHiding;
if (existingVariable == this.binding) break checkHiding;
if (existingVariable instanceof FieldBinding) {
FieldBinding existingField = (FieldBinding) existingVariable;
if (existingField.original() == this.binding) break checkHiding;
if (!existingField.isStatic() && declaringType.isStatic()) break checkHiding;
}
initializationScope.problemReporter().fieldHiding(this, existingVariable);
}
}
if (this.type != null ) {
this.type.resolvedType = this.binding.type;
}
FieldBinding previousField = initializationScope.initializedField;
int previousFieldID = initializationScope.lastVisibleFieldID;
try {
initializationScope.initializedField = this.binding;
initializationScope.lastVisibleFieldID = this.binding.id;
resolveAnnotations(initializationScope, this.annotations, this.binding);
if (this.annotations != null) {
for (int i = 0, max = this.annotations.length; i < max; i++) {
TypeBinding resolvedAnnotationType = this.annotations[i].resolvedType;
if (resolvedAnnotationType != null && (resolvedAnnotationType.getAnnotationTagBits() & TagBits.AnnotationForTypeUse) != 0) {
this.bits |= ASTNode.HasTypeAnnotations;
break;
}
}
}
if ((this.binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0
&& (this.binding.modifiers & ClassFileConstants.AccDeprecated) != 0
&& initializationScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
initializationScope.problemReporter().missingDeprecatedAnnotationForField(this);
}
if (this.initialization == null) {
this.binding.setConstant(Constant.NotAConstant);
} else {
this.binding.setConstant(Constant.NotAConstant);
TypeBinding fieldType = this.binding.type;
TypeBinding initializationType;
this.initialization.setExpressionContext(ASSIGNMENT_CONTEXT);
this.initialization.setExpectedType(fieldType);
if (this.initialization instanceof ArrayInitializer) {
if ((initializationType = this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) {
((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType;
this.initialization.computeConversion(initializationScope, fieldType, initializationType);
}
} else if ((initializationType = this.initialization.resolveType(initializationScope)) != null) {
if (TypeBinding.notEquals(fieldType, initializationType))
initializationScope.compilationUnitScope().recordTypeConversion(fieldType, initializationType);
if (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, fieldType)
|| initializationType.isCompatibleWith(fieldType, classScope)) {
this.initialization.computeConversion(initializationScope, fieldType, initializationType);
if (initializationType.needsUncheckedConversion(fieldType)) {
initializationScope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, fieldType);
}
if (this.initialization instanceof CastExpression
&& (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) {
CastExpression.checkNeedForAssignedCast(initializationScope, fieldType, (CastExpression) this.initialization);
}
} else if (isBoxingCompatible(initializationType, fieldType, this.initialization, initializationScope)) {
this.initialization.computeConversion(initializationScope, fieldType, initializationType);
if (this.initialization instanceof CastExpression
&& (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) {
CastExpression.checkNeedForAssignedCast(initializationScope, fieldType, (CastExpression) this.initialization);
}
} else {
if (((fieldType.tagBits | initializationType.tagBits) & TagBits.HasMissingType) == 0) {
initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this.initialization, null);
}
}
if (this.binding.isFinal()){
this.binding.setConstant(this.initialization.constant.castTo((this.binding.type.id << 4) + this.initialization.constant.typeID()));
}
} else {
this.binding.setConstant(Constant.NotAConstant);
}
if (this.binding == Expression.getDirectBinding(this.initialization)) {
initializationScope.problemReporter().assignmentHasNoEffect(this, this.name);
}
}
} finally {
initializationScope.initializedField = previousField;
initializationScope.lastVisibleFieldID = previousFieldID;
if (this.binding.constant(initializationScope) == null)
this.binding.setConstant(Constant.NotAConstant);
}
}
public void resolveJavadoc(MethodScope initializationScope) {
if (this.javadoc != null) {
FieldBinding previousField = initializationScope.initializedField;
int previousFieldID = initializationScope.lastVisibleFieldID;
try {
initializationScope.initializedField = this.binding;
if (this.binding != null)
initializationScope.lastVisibleFieldID = this.binding.id;
this.javadoc.resolve(initializationScope);
} finally {
initializationScope.initializedField = previousField;
initializationScope.lastVisibleFieldID = previousFieldID;
}
} else if (this.binding != null && this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
int javadocVisibility = this.binding.modifiers & ExtraCompilerModifiers.AccVisibilityMASK;
ProblemReporter reporter = initializationScope.problemReporter();
int severity = reporter.computeSeverity(IProblem.JavadocMissing);
if (severity != ProblemSeverities.Ignore) {
ClassScope classScope = initializationScope.enclosingClassScope();
if (classScope != null) {
javadocVisibility = Util.computeOuterMostVisibility(classScope.referenceType(), javadocVisibility);
}
int javadocModifiers = (this.binding.modifiers & ~ExtraCompilerModifiers.AccVisibilityMASK) | javadocVisibility;
reporter.javadocMissing(this.sourceStart, this.sourceEnd, severity, javadocModifiers);
}
}
}
public void traverse(ASTVisitor visitor, MethodScope scope) {
if (visitor.visit(this, scope)) {
if (this.javadoc != null) {
this.javadoc.traverse(visitor, scope);
}
if (this.annotations != null) {
int annotationsLength = this.annotations.length;
for (int i = 0; i < annotationsLength; i++)
this.annotations[i].traverse(visitor, scope);
}
if (this.type != null) {
this.type.traverse(visitor, scope);
}
if (this.initialization != null)
this.initialization.traverse(visitor, scope);
}
visitor.endVisit(this, scope);
}
}