package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@SuppressWarnings({"rawtypes", "unchecked"})
public class BlockScope extends Scope {
public LocalVariableBinding[] locals;
public int localIndex;
public int startIndex;
public int offset;
public int maxOffset;
public BlockScope[] shiftScopes;
public Scope[] subscopes = new Scope[1];
public int subscopeCount = 0;
public CaseStatement enclosingCase;
public final static VariableBinding[] EmulationPathToImplicitThis = {};
public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {};
public final static VariableBinding[] NoEnclosingInstanceInStaticContext = {};
public boolean insideTypeAnnotation = false;
public Statement blockStatement;
public BlockScope(BlockScope parent) {
this(parent, true);
}
public BlockScope(BlockScope parent, boolean addToParentScope) {
this(Scope.BLOCK_SCOPE, parent);
this.locals = new LocalVariableBinding[5];
if (addToParentScope) parent.addSubscope(this);
this.startIndex = parent.localIndex;
}
public BlockScope(BlockScope parent, int variableCount) {
this(Scope.BLOCK_SCOPE, parent);
this.locals = new LocalVariableBinding[variableCount];
parent.addSubscope(this);
this.startIndex = parent.localIndex;
}
protected BlockScope(int kind, Scope parent) {
super(kind, parent);
}
public final void addAnonymousType(TypeDeclaration anonymousType, ReferenceBinding superBinding) {
ClassScope anonymousClassScope = new ClassScope(this, anonymousType);
anonymousClassScope.buildAnonymousTypeBinding(
enclosingSourceType(),
superBinding);
MethodScope methodScope = methodScope();
while (methodScope != null && methodScope.referenceContext instanceof LambdaExpression) {
LambdaExpression lambda = (LambdaExpression) methodScope.referenceContext;
if (!lambda.scope.isStatic && !lambda.scope.isConstructorCall) {
lambda.shouldCaptureInstance = true;
}
methodScope = methodScope.enclosingMethodScope();
}
}
public final void addLocalType(TypeDeclaration localType) {
ClassScope localTypeScope = new ClassScope(this, localType);
addSubscope(localTypeScope);
localTypeScope.buildLocalTypeBinding(enclosingSourceType());
MethodScope methodScope = methodScope();
while (methodScope != null && methodScope.referenceContext instanceof LambdaExpression) {
LambdaExpression lambda = (LambdaExpression) methodScope.referenceContext;
if (!lambda.scope.isStatic && !lambda.scope.isConstructorCall) {
lambda.shouldCaptureInstance = true;
}
methodScope = methodScope.enclosingMethodScope();
}
}
public final void addLocalVariable(LocalVariableBinding binding) {
checkAndSetModifiersForVariable(binding);
if (this.localIndex == this.locals.length)
System.arraycopy(
this.locals,
0,
(this.locals = new LocalVariableBinding[this.localIndex * 2]),
0,
this.localIndex);
this.locals[this.localIndex++] = binding;
binding.declaringScope = this;
binding.id = outerMostMethodScope().analysisIndex++;
}
public void addSubscope(Scope childScope) {
if (this.subscopeCount == this.subscopes.length)
System.arraycopy(
this.subscopes,
0,
(this.subscopes = new Scope[this.subscopeCount * 2]),
0,
this.subscopeCount);
this.subscopes[this.subscopeCount++] = childScope;
}
public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) {
if (TypeBinding.notEquals(enclosingReceiverType(), binding.declaringClass))
return false;
MethodScope methodScope = methodScope();
if (methodScope.isStatic != binding.isStatic())
return false;
if (methodScope.isLambdaScope())
return false;
return methodScope.isInsideInitializer()
|| ((AbstractMethodDeclaration) methodScope.referenceContext).isInitializationMethod();
}
String basicToString(int tab) {
String newLine = "\n";
for (int i = tab; --i >= 0;)
newLine += "\t";
String s = newLine + "--- Block Scope ---";
newLine += "\t";
s += newLine + "locals:";
for (int i = 0; i < this.localIndex; i++)
s += newLine + "\t" + this.locals[i].toString();
s += newLine + "startIndex = " + this.startIndex;
return s;
}
private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) {
int modifiers = varBinding.modifiers;
if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0 && varBinding.declaration != null){
problemReporter().duplicateModifierForVariable(varBinding.declaration, this instanceof MethodScope);
}
int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag;
int unexpectedModifiers = ~ClassFileConstants.AccFinal;
if ((realModifiers & unexpectedModifiers) != 0 && varBinding.declaration != null){
problemReporter().illegalModifierForVariable(varBinding.declaration, this instanceof MethodScope);
}
varBinding.modifiers = modifiers;
}
void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream codeStream) {
this.offset = initOffset;
this.maxOffset = initOffset;
int maxLocals = this.localIndex;
boolean hasMoreVariables = ilocal < maxLocals;
int iscope = 0, maxScopes = this.subscopeCount;
boolean hasMoreScopes = maxScopes > 0;
while (hasMoreVariables || hasMoreScopes) {
if (hasMoreScopes
&& (!hasMoreVariables || (this.subscopes[iscope].startIndex() <= ilocal))) {
if (this.subscopes[iscope] instanceof BlockScope) {
BlockScope subscope = (BlockScope) this.subscopes[iscope];
int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset();
subscope.computeLocalVariablePositions(0, subOffset, codeStream);
if (subscope.maxOffset > this.maxOffset)
this.maxOffset = subscope.maxOffset;
}
hasMoreScopes = ++iscope < maxScopes;
} else {
LocalVariableBinding local = this.locals[ilocal];
boolean generateCurrentLocalVar = (local.useFlag > LocalVariableBinding.UNUSED && local.constant() == Constant.NotAConstant);
if (local.useFlag == LocalVariableBinding.UNUSED
&& (local.declaration != null)
&& ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) {
if (local.isCatchParameter()) {
problemReporter().unusedExceptionParameter(local.declaration);
}
else {
problemReporter().unusedLocalVariable(local.declaration);
}
}
if (!generateCurrentLocalVar) {
if (local.declaration != null && compilerOptions().preserveAllLocalVariables) {
generateCurrentLocalVar = true;
if (local.useFlag == LocalVariableBinding.UNUSED)
local.useFlag = LocalVariableBinding.USED;
}
}
if (generateCurrentLocalVar) {
if (local.declaration != null) {
codeStream.record(local);
}
local.resolvedPosition = this.offset;
if ((TypeBinding.equalsEquals(local.type, TypeBinding.LONG)) || (TypeBinding.equalsEquals(local.type, TypeBinding.DOUBLE))) {
this.offset += 2;
} else {
this.offset++;
}
if (this.offset > 0xFFFF) {
problemReporter().noMoreAvailableSpaceForLocal(
local,
local.declaration == null ? (ASTNode)methodScope().referenceContext : local.declaration);
}
} else {
local.resolvedPosition = -1;
}
hasMoreVariables = ++ilocal < maxLocals;
}
}
if (this.offset > this.maxOffset)
this.maxOffset = this.offset;
}
public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) {
BlockScope outerVariableScope = outerLocalVariable.declaringScope;
if (outerVariableScope == null)
return;
int depth = 0;
Scope scope = this;
while (outerVariableScope != scope) {
switch(scope.kind) {
case CLASS_SCOPE:
depth++;
break;
case METHOD_SCOPE:
if (scope.isLambdaScope()) {
LambdaExpression lambdaExpression = (LambdaExpression) scope.referenceContext();
lambdaExpression.addSyntheticArgument(outerLocalVariable);
}
break;
}
scope = scope.parent;
}
if (depth == 0)
return;
MethodScope currentMethodScope = methodScope();
if (outerVariableScope.methodScope() != currentMethodScope) {
NestedTypeBinding currentType = (NestedTypeBinding) enclosingSourceType();
if (!currentType.isLocalType()) {
return;
}
if (!currentMethodScope.isInsideInitializerOrConstructor()) {
currentType.addSyntheticArgumentAndField(outerLocalVariable);
} else {
currentType.addSyntheticArgument(outerLocalVariable);
}
}
}
public final ReferenceBinding findLocalType(char[] name) {
long compliance = compilerOptions().complianceLevel;
for (int i = this.subscopeCount-1; i >= 0; i--) {
if (this.subscopes[i] instanceof ClassScope) {
LocalTypeBinding sourceType = (LocalTypeBinding)((ClassScope) this.subscopes[i]).referenceContext.binding;
if (compliance >= ClassFileConstants.JDK1_4 && sourceType.enclosingCase != null) {
if (!isInsideCase(sourceType.enclosingCase)) {
continue;
}
}
if (CharOperation.equals(sourceType.sourceName(), name))
return sourceType;
}
}
return null;
}
public LocalDeclaration[] findLocalVariableDeclarations(int position) {
int ilocal = 0, maxLocals = this.localIndex;
boolean hasMoreVariables = maxLocals > 0;
LocalDeclaration[] localDeclarations = null;
int declPtr = 0;
int iscope = 0, maxScopes = this.subscopeCount;
boolean hasMoreScopes = maxScopes > 0;
while (hasMoreVariables || hasMoreScopes) {
if (hasMoreScopes
&& (!hasMoreVariables || (this.subscopes[iscope].startIndex() <= ilocal))) {
Scope subscope = this.subscopes[iscope];
if (subscope.kind == Scope.BLOCK_SCOPE) {
localDeclarations = ((BlockScope)subscope).findLocalVariableDeclarations(position);
if (localDeclarations != null) {
return localDeclarations;
}
}
hasMoreScopes = ++iscope < maxScopes;
} else {
LocalVariableBinding local = this.locals[ilocal];
if (local != null) {
LocalDeclaration localDecl = local.declaration;
if (localDecl != null) {
if (localDecl.declarationSourceStart <= position) {
if (position <= localDecl.declarationSourceEnd) {
if (localDeclarations == null) {
localDeclarations = new LocalDeclaration[maxLocals];
}
localDeclarations[declPtr++] = localDecl;
}
} else {
return localDeclarations;
}
}
}
hasMoreVariables = ++ilocal < maxLocals;
if (!hasMoreVariables && localDeclarations != null) {
return localDeclarations;
}
}
}
return null;
}
@Override
public LocalVariableBinding findVariable(char[] variableName) {
int varLength = variableName.length;
for (int i = this.localIndex-1; i >= 0; i--) {
LocalVariableBinding local;
char[] localName;
if ((localName = (local = this.locals[i]).name).length == varLength && CharOperation.equals(localName, variableName))
return local;
}
return null;
}
public Binding getBinding(char[][] compoundName, int mask, InvocationSite invocationSite, boolean needResolve) {
Binding binding = getBinding(compoundName[0], mask | Binding.TYPE | Binding.PACKAGE, invocationSite, needResolve);
invocationSite.setFieldIndex(1);
if (binding instanceof VariableBinding) return binding;
CompilationUnitScope unitScope = compilationUnitScope();
unitScope.recordQualifiedReference(compoundName);
if (!binding.isValidBinding()) return binding;
int length = compoundName.length;
int currentIndex = 1;
foundType : if (binding instanceof PackageBinding) {
PackageBinding packageBinding = (PackageBinding) binding;
while (currentIndex < length) {
unitScope.recordReference(packageBinding.compoundName, compoundName[currentIndex]);
binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++], module(), currentIndex<length);
invocationSite.setFieldIndex(currentIndex);
if (binding == null) {
if (currentIndex == length) {
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
null,
ProblemReasons.NotFound);
}
return new ProblemBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
ProblemReasons.NotFound);
}
if (binding instanceof ReferenceBinding) {
if (!binding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding)((ReferenceBinding)binding).closestMatch(),
binding.problemId());
if (!((ReferenceBinding) binding).canBeSeenBy(this))
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding) binding,
ProblemReasons.NotVisible);
break foundType;
}
packageBinding = (PackageBinding) binding;
}
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
null,
ProblemReasons.NotFound);
}
ReferenceBinding referenceBinding = (ReferenceBinding) binding;
binding = environment().convertToRawType(referenceBinding, false );
if (invocationSite instanceof ASTNode) {
ASTNode invocationNode = (ASTNode) invocationSite;
if (invocationNode.isTypeUseDeprecated(referenceBinding, this)) {
problemReporter().deprecatedType(referenceBinding, invocationNode);
}
}
Binding problemFieldBinding = null;
while (currentIndex < length) {
referenceBinding = (ReferenceBinding) binding;
char[] nextName = compoundName[currentIndex++];
invocationSite.setFieldIndex(currentIndex);
invocationSite.setActualReceiverType(referenceBinding);
if ((mask & Binding.FIELD) != 0 && (binding = findField(referenceBinding, nextName, invocationSite, true )) != null) {
if (binding.isValidBinding()) {
break;
}
problemFieldBinding = new ProblemFieldBinding(
((ProblemFieldBinding)binding).closestMatch,
((ProblemFieldBinding)binding).declaringClass,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
binding.problemId());
if (binding.problemId() != ProblemReasons.NotVisible) {
return problemFieldBinding;
}
}
if ((binding = findMemberType(nextName, referenceBinding)) == null) {
if (problemFieldBinding != null) {
return problemFieldBinding;
}
if ((mask & Binding.FIELD) != 0) {
return new ProblemFieldBinding(
null,
referenceBinding,
nextName,
ProblemReasons.NotFound);
} else if ((mask & Binding.VARIABLE) != 0) {
return new ProblemBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
referenceBinding,
ProblemReasons.NotFound);
}
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
referenceBinding,
ProblemReasons.NotFound);
}
if (!binding.isValidBinding()) {
if (problemFieldBinding != null) {
return problemFieldBinding;
}
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding)((ReferenceBinding)binding).closestMatch(),
binding.problemId());
}
if (invocationSite instanceof ASTNode) {
referenceBinding = (ReferenceBinding) binding;
ASTNode invocationNode = (ASTNode) invocationSite;
if (invocationNode.isTypeUseDeprecated(referenceBinding, this)) {
problemReporter().deprecatedType(referenceBinding, invocationNode);
}
}
}
if ((mask & Binding.FIELD) != 0 && (binding instanceof FieldBinding)) {
FieldBinding field = (FieldBinding) binding;
if (!field.isStatic())
return new ProblemFieldBinding(
field,
field.declaringClass,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
ProblemReasons.NonStaticReferenceInStaticContext);
return binding;
}
if ((mask & Binding.TYPE) != 0 && (binding instanceof ReferenceBinding)) {
return binding;
}
return new ProblemBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
ProblemReasons.NotFound);
}
public final Binding getBinding(char[][] compoundName, InvocationSite invocationSite) {
int currentIndex = 0;
int length = compoundName.length;
Binding binding =
getBinding(
compoundName[currentIndex++],
Binding.VARIABLE | Binding.TYPE | Binding.PACKAGE,
invocationSite,
true );
if (!binding.isValidBinding())
return binding;
foundType : if (binding instanceof PackageBinding) {
while (currentIndex < length) {
PackageBinding packageBinding = (PackageBinding) binding;
binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++], module(), currentIndex<length);
if (binding == null) {
if (currentIndex == length) {
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
null,
ProblemReasons.NotFound);
}
return new ProblemBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
ProblemReasons.NotFound);
}
if (binding instanceof ReferenceBinding) {
if (!binding.isValidBinding())
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding)((ReferenceBinding)binding).closestMatch(),
binding.problemId());
if (!((ReferenceBinding) binding).canBeSeenBy(this))
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding) binding,
ProblemReasons.NotVisible);
break foundType;
}
}
return binding;
}
foundField : if (binding instanceof ReferenceBinding) {
while (currentIndex < length) {
ReferenceBinding typeBinding = (ReferenceBinding) binding;
char[] nextName = compoundName[currentIndex++];
TypeBinding receiverType = typeBinding.capture(this, invocationSite.sourceStart(), invocationSite.sourceEnd());
if ((binding = findField(receiverType, nextName, invocationSite, true )) != null) {
if (!binding.isValidBinding()) {
return new ProblemFieldBinding(
(FieldBinding) binding,
((FieldBinding) binding).declaringClass,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
binding.problemId());
}
if (!((FieldBinding) binding).isStatic())
return new ProblemFieldBinding(
(FieldBinding) binding,
((FieldBinding) binding).declaringClass,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
ProblemReasons.NonStaticReferenceInStaticContext);
break foundField;
}
if ((binding = findMemberType(nextName, typeBinding)) == null) {
return new ProblemBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
typeBinding,
ProblemReasons.NotFound);
}
if (!binding.isValidBinding()) {
return new ProblemReferenceBinding(
CharOperation.subarray(compoundName, 0, currentIndex),
(ReferenceBinding)((ReferenceBinding)binding).closestMatch(),
binding.problemId());
}
}
return binding;
}
VariableBinding variableBinding = (VariableBinding) binding;
while (currentIndex < length) {
TypeBinding typeBinding = variableBinding.type;
if (typeBinding == null) {
return new ProblemFieldBinding(
null,
null,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
ProblemReasons.NotFound);
}
TypeBinding receiverType = typeBinding.capture(this, invocationSite.sourceStart(), invocationSite.sourceEnd());
variableBinding = findField(receiverType, compoundName[currentIndex++], invocationSite, true );
if (variableBinding == null) {
return new ProblemFieldBinding(
null,
receiverType instanceof ReferenceBinding ? (ReferenceBinding) receiverType : null,
CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
ProblemReasons.NotFound);
}
if (!variableBinding.isValidBinding())
return variableBinding;
}
return variableBinding;
}
public VariableBinding[] getEmulationPath(LocalVariableBinding outerLocalVariable) {
MethodScope currentMethodScope = methodScope();
SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
BlockScope variableScope = outerLocalVariable.declaringScope;
if (variableScope == null || currentMethodScope == variableScope.methodScope()) {
return new VariableBinding[] { outerLocalVariable };
}
if (currentMethodScope.isLambdaScope()) {
LambdaExpression lambda = (LambdaExpression) currentMethodScope.referenceContext;
SyntheticArgumentBinding syntheticArgument;
if ((syntheticArgument = lambda.getSyntheticArgument(outerLocalVariable)) != null) {
return new VariableBinding[] { syntheticArgument };
}
}
if (currentMethodScope.isInsideInitializerOrConstructor()
&& (sourceType.isNestedType())) {
SyntheticArgumentBinding syntheticArg;
if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(outerLocalVariable)) != null) {
return new VariableBinding[] { syntheticArg };
}
}
if (!currentMethodScope.isStatic) {
FieldBinding syntheticField;
if ((syntheticField = sourceType.getSyntheticField(outerLocalVariable)) != null) {
return new VariableBinding[] { syntheticField };
}
}
return null;
}
public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean denyEnclosingArgInConstructorCall) {
MethodScope currentMethodScope = methodScope();
SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
if (!currentMethodScope.isStatic && !currentMethodScope.isConstructorCall) {
if (TypeBinding.equalsEquals(sourceType, targetEnclosingType) || (!onlyExactMatch && sourceType.findSuperTypeOriginatingFrom(targetEnclosingType) != null)) {
return BlockScope.EmulationPathToImplicitThis;
}
}
if (!sourceType.isNestedType() || sourceType.isStatic()) {
if (currentMethodScope.isConstructorCall) {
return BlockScope.NoEnclosingInstanceInConstructorCall;
} else if (currentMethodScope.isStatic){
return BlockScope.NoEnclosingInstanceInStaticContext;
}
return null;
}
boolean insideConstructor = currentMethodScope.isInsideInitializerOrConstructor();
if (insideConstructor) {
SyntheticArgumentBinding syntheticArg;
if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch, currentMethodScope.isConstructorCall)) != null) {
boolean isAnonymousAndHasEnclosing = sourceType.isAnonymousType()
&& sourceType.scope.referenceContext.allocation.enclosingInstance != null;
if (denyEnclosingArgInConstructorCall
&& !isAnonymousAndHasEnclosing
&& (TypeBinding.equalsEquals(sourceType, targetEnclosingType) || (!onlyExactMatch && sourceType.findSuperTypeOriginatingFrom(targetEnclosingType) != null))) {
return BlockScope.NoEnclosingInstanceInConstructorCall;
}
return new Object[] { syntheticArg };
}
}
if (currentMethodScope.isStatic) {
return BlockScope.NoEnclosingInstanceInStaticContext;
}
if (sourceType.isAnonymousType()) {
ReferenceBinding enclosingType = sourceType.enclosingType();
if (enclosingType.isNestedType()) {
NestedTypeBinding nestedEnclosingType = (NestedTypeBinding) enclosingType;
SyntheticArgumentBinding enclosingArgument = nestedEnclosingType.getSyntheticArgument(nestedEnclosingType.enclosingType(), onlyExactMatch, currentMethodScope.isConstructorCall);
if (enclosingArgument != null) {
FieldBinding syntheticField = sourceType.getSyntheticField(enclosingArgument);
if (syntheticField != null) {
if (TypeBinding.equalsEquals(syntheticField.type, targetEnclosingType) || (!onlyExactMatch && ((ReferenceBinding)syntheticField.type).findSuperTypeOriginatingFrom(targetEnclosingType) != null))
return new Object[] { syntheticField };
}
}
}
}
FieldBinding syntheticField = sourceType.getSyntheticField(targetEnclosingType, onlyExactMatch);
if (syntheticField != null) {
if (currentMethodScope.isConstructorCall){
return BlockScope.NoEnclosingInstanceInConstructorCall;
}
return new Object[] { syntheticField };
}
Object[] path = new Object[2];
ReferenceBinding currentType = sourceType.enclosingType();
if (insideConstructor) {
path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument(currentType, onlyExactMatch, currentMethodScope.isConstructorCall);
} else {
if (currentMethodScope.isConstructorCall){
return BlockScope.NoEnclosingInstanceInConstructorCall;
}
path[0] = sourceType.getSyntheticField(currentType, onlyExactMatch);
}
if (path[0] != null) {
int count = 1;
ReferenceBinding currentEnclosingType;
while ((currentEnclosingType = currentType.enclosingType()) != null) {
if (TypeBinding.equalsEquals(currentType, targetEnclosingType)
|| (!onlyExactMatch && currentType.findSuperTypeOriginatingFrom(targetEnclosingType) != null)) break;
if (currentMethodScope != null) {
currentMethodScope = currentMethodScope.enclosingMethodScope();
if (currentMethodScope != null && currentMethodScope.isConstructorCall){
return BlockScope.NoEnclosingInstanceInConstructorCall;
}
if (currentMethodScope != null && currentMethodScope.isStatic){
return BlockScope.NoEnclosingInstanceInStaticContext;
}
}
syntheticField = ((NestedTypeBinding) currentType).getSyntheticField(currentEnclosingType, onlyExactMatch);
if (syntheticField == null) break;
if (count == path.length) {
System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
}
path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true, false );
currentType = currentEnclosingType;
}
if (TypeBinding.equalsEquals(currentType, targetEnclosingType)
|| (!onlyExactMatch && currentType.findSuperTypeOriginatingFrom(targetEnclosingType) != null)) {
return path;
}
}
return null;
}
public final boolean isDuplicateLocalVariable(char[] name) {
BlockScope current = this;
while (true) {
for (int i = 0; i < this.localIndex; i++) {
if (CharOperation.equals(name, current.locals[i].name))
return true;
}
if (current.kind != Scope.BLOCK_SCOPE) return false;
current = (BlockScope)current.parent;
}
}
public int maxShiftedOffset() {
int max = -1;
if (this.shiftScopes != null){
for (int i = 0, length = this.shiftScopes.length; i < length; i++){
if (this.shiftScopes[i] != null) {
int subMaxOffset = this.shiftScopes[i].maxOffset;
if (subMaxOffset > max) max = subMaxOffset;
}
}
}
return max;
}
public final boolean needBlankFinalFieldInitializationCheck(FieldBinding binding) {
boolean isStatic = binding.isStatic();
ReferenceBinding fieldDeclaringClass = binding.declaringClass;
MethodScope methodScope = namedMethodScope();
while (methodScope != null) {
if (methodScope.isStatic != isStatic)
return false;
if (!methodScope.isInsideInitializer()
&& !((AbstractMethodDeclaration) methodScope.referenceContext).isInitializationMethod()) {
return false;
}
ReferenceBinding enclosingType = methodScope.enclosingReceiverType();
if (TypeBinding.equalsEquals(enclosingType, fieldDeclaringClass)) {
return true;
}
if (!enclosingType.erasure().isAnonymousType()) {
return false;
}
methodScope = methodScope.enclosingMethodScope().namedMethodScope();
}
return false;
}
@Override
public ProblemReporter problemReporter() {
return methodScope().problemReporter();
}
public void propagateInnerEmulation(ReferenceBinding targetType, boolean isEnclosingInstanceSupplied) {
SyntheticArgumentBinding[] syntheticArguments;
if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) {
for (int i = 0, max = syntheticArguments.length; i < max; i++) {
SyntheticArgumentBinding syntheticArg = syntheticArguments[i];
if (!(isEnclosingInstanceSupplied
&& (TypeBinding.equalsEquals(syntheticArg.type, targetType.enclosingType())))) {
emulateOuterAccess(syntheticArg.actualOuterLocalVariable);
}
}
}
}
public TypeDeclaration referenceType() {
return methodScope().referenceType();
}
public int scopeIndex() {
if (this instanceof MethodScope) return -1;
BlockScope parentScope = (BlockScope)this.parent;
Scope[] parentSubscopes = parentScope.subscopes;
for (int i = 0, max = parentScope.subscopeCount; i < max; i++) {
if (parentSubscopes[i] == this) return i;
}
return -1;
}
@Override
int startIndex() {
return this.startIndex;
}
@Override
public String toString() {
return toString(0);
}
public String toString(int tab) {
String s = basicToString(tab);
for (int i = 0; i < this.subscopeCount; i++)
if (this.subscopes[i] instanceof BlockScope)
s += ((BlockScope) this.subscopes[i]).toString(tab + 1) + "\n";
return s;
}
private List trackingVariables;
public FlowInfo finallyInfo;
public int registerTrackingVariable(FakedTrackingVariable fakedTrackingVariable) {
if (this.trackingVariables == null)
this.trackingVariables = new ArrayList(3);
this.trackingVariables.add(fakedTrackingVariable);
MethodScope outerMethodScope = outerMostMethodScope();
return outerMethodScope.analysisIndex++;
}
public void removeTrackingVar(FakedTrackingVariable trackingVariable) {
if (trackingVariable.innerTracker != null) {
trackingVariable.innerTracker.withdraw();
trackingVariable.innerTracker = null;
}
if (this.trackingVariables != null)
if (this.trackingVariables.remove(trackingVariable))
return;
if (this.parent instanceof BlockScope)
((BlockScope)this.parent).removeTrackingVar(trackingVariable);
}
public void pruneWrapperTrackingVar(FakedTrackingVariable trackingVariable) {
this.trackingVariables.remove(trackingVariable);
}
public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, ASTNode location, BlockScope locationScope) {
if (!compilerOptions().analyseResourceLeaks) return;
if (this.trackingVariables == null) {
if (location != null && this.parent instanceof BlockScope && !isLambdaScope())
((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, flowContext, location, locationScope);
return;
}
if (location != null && flowInfo.reachMode() != 0) return;
FakedTrackingVariable returnVar = (location instanceof ReturnStatement) ?
FakedTrackingVariable.getCloseTrackingVariable(((ReturnStatement)location).expression, flowInfo, flowContext) : null;
Iterator<FakedTrackingVariable> iterator = new FakedTrackingVariable.IteratorForReporting(this.trackingVariables, this, location != null);
while (iterator.hasNext()) {
FakedTrackingVariable trackingVar = iterator.next();
if (returnVar != null && trackingVar.isResourceBeingReturned(returnVar)) {
continue;
}
if (location != null && trackingVar.hasDefinitelyNoResource(flowInfo)) {
continue;
}
if (location != null && flowContext != null && flowContext.recordExitAgainstResource(this, flowInfo, trackingVar, location)) {
continue;
}
int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope);
if (status == FlowInfo.NULL) {
reportResourceLeak(trackingVar, location, status);
continue;
}
if (location == null)
{
if (trackingVar.reportRecordedErrors(this, status, flowInfo.reachMode() != FlowInfo.REACHABLE))
continue;
}
if (status == FlowInfo.POTENTIALLY_NULL) {
reportResourceLeak(trackingVar, location, status);
} else if (status == FlowInfo.NON_NULL) {
if (environment().globalOptions.complianceLevel >= ClassFileConstants.JDK1_7)
trackingVar.reportExplicitClosing(problemReporter());
}
}
if (location == null) {
for (int i=0; i<this.localIndex; i++)
this.locals[i].closeTracker = null;
this.trackingVariables = null;
}
}
private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) {
if (location != null)
trackingVar.recordErrorLocation(location, nullStatus);
else
trackingVar.reportError(problemReporter(), null, nullStatus);
}
public void correlateTrackingVarsIfElse(FlowInfo thenFlowInfo, FlowInfo elseFlowInfo) {
if (this.trackingVariables != null) {
int trackVarCount = this.trackingVariables.size();
for (int i=0; i<trackVarCount; i++) {
FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
if (trackingVar.originalBinding == null)
continue;
if ( thenFlowInfo.isDefinitelyNonNull(trackingVar.binding)
&& elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding))
{
elseFlowInfo.markAsDefinitelyNonNull(trackingVar.binding);
}
else if ( elseFlowInfo.isDefinitelyNonNull(trackingVar.binding)
&& thenFlowInfo.isDefinitelyNull(trackingVar.originalBinding))
{
thenFlowInfo.markAsDefinitelyNonNull(trackingVar.binding);
}
else {
if (thenFlowInfo == FlowInfo.DEAD_END || elseFlowInfo == FlowInfo.DEAD_END)
continue;
for (int j=i+1; j<trackVarCount; j++) {
FakedTrackingVariable var2 = ((FakedTrackingVariable) this.trackingVariables.get(j));
if (trackingVar.originalBinding == var2.originalBinding) {
boolean var1SeenInThen = thenFlowInfo.hasNullInfoFor(trackingVar.binding);
boolean var1SeenInElse = elseFlowInfo.hasNullInfoFor(trackingVar.binding);
boolean var2SeenInThen = thenFlowInfo.hasNullInfoFor(var2.binding);
boolean var2SeenInElse = elseFlowInfo.hasNullInfoFor(var2.binding);
int newStatus;
if (!var1SeenInThen && var1SeenInElse && var2SeenInThen && !var2SeenInElse) {
newStatus = FlowInfo.mergeNullStatus(thenFlowInfo.nullStatus(var2.binding), elseFlowInfo.nullStatus(trackingVar.binding));
} else if (var1SeenInThen && !var1SeenInElse && !var2SeenInThen && var2SeenInElse) {
newStatus = FlowInfo.mergeNullStatus(thenFlowInfo.nullStatus(trackingVar.binding), elseFlowInfo.nullStatus(var2.binding));
} else {
continue;
}
thenFlowInfo.markNullStatus(trackingVar.binding, newStatus);
elseFlowInfo.markNullStatus(trackingVar.binding, newStatus);
trackingVar.originalBinding.closeTracker = trackingVar;
thenFlowInfo.markNullStatus(var2.binding, FlowInfo.NON_NULL);
elseFlowInfo.markNullStatus(var2.binding, FlowInfo.NON_NULL);
}
}
}
}
}
if (this.parent instanceof BlockScope)
((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo);
}
public void checkAppropriateMethodAgainstSupers(char[] selector, MethodBinding compileTimeMethod,
TypeBinding[] parameters, InvocationSite site)
{
ReferenceBinding enclosingType = enclosingReceiverType();
MethodBinding otherMethod = getMethod(enclosingType.superclass(), selector, parameters, site);
if (checkAppropriate(compileTimeMethod, otherMethod, site)) {
ReferenceBinding[] superInterfaces = enclosingType.superInterfaces();
if (superInterfaces != null) {
for (int i = 0; i < superInterfaces.length; i++) {
otherMethod = getMethod(superInterfaces[i], selector, parameters, site);
if (!checkAppropriate(compileTimeMethod, otherMethod, site))
break;
}
}
}
}
private boolean checkAppropriate(MethodBinding compileTimeDeclaration, MethodBinding otherMethod, InvocationSite location) {
if (otherMethod == null || !otherMethod.isValidBinding() || otherMethod.original() == compileTimeDeclaration.original())
return true;
if (MethodVerifier.doesMethodOverride(otherMethod, compileTimeDeclaration, this.environment())) {
problemReporter().illegalSuperCallBypassingOverride(location, compileTimeDeclaration, otherMethod.declaringClass);
return false;
}
return true;
}
}