X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Flookup%2FMethodScope.java;fp=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Flookup%2FMethodScope.java;h=92b806bf202b984a77b09ec8b549fab944694748;hb=6f0cd02d46e011bd5599e1b7fefc6159cb811135;hp=0000000000000000000000000000000000000000;hpb=622d0e5a4b1b35b6918a516a79a0cc22272a919e;p=org.ibex.tool.git diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java new file mode 100644 index 0000000..92b806b --- /dev/null +++ b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java @@ -0,0 +1,492 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; + +/** + * Particular block scope used for methods, constructors or clinits, representing + * its outermost blockscope. Note also that such a scope will be provided to enclose + * field initializers subscopes as well. + */ +public class MethodScope extends BlockScope { + + public ReferenceContext referenceContext; + public boolean isStatic; // method modifier or initializer one + + //fields used during name resolution + public boolean isConstructorCall = false; + public FieldBinding initializedField; // the field being initialized + public int lastVisibleFieldID = -1; // the ID of the last field which got declared + // note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers. + + // flow analysis + public int analysisIndex; // for setting flow-analysis id + public boolean isPropagatingInnerClassEmulation; + + // for local variables table attributes + public int lastIndex = 0; + public long[] definiteInits = new long[4]; + public long[][] extraDefiniteInits = new long[4][]; + + // inner-emulation + public SyntheticArgumentBinding[] extraSyntheticArguments; + + public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) { + + super(METHOD_SCOPE, parent); + locals = new LocalVariableBinding[5]; + this.referenceContext = context; + this.isStatic = isStatic; + this.startIndex = 0; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) { + if (methodBinding.declaringClass.isPublic()) + modifiers |= AccPublic; + else if (methodBinding.declaringClass.isProtected()) + modifiers |= AccProtected; + } + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // check for abnormal modifiers + int unexpectedModifiers = + ~(AccPublic | AccPrivate | AccProtected | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + else if ( + (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0) + // must check the parse node explicitly + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation) + if (methodBinding.declaringClass.isPrivate()) + if ((modifiers & AccPrivate) != 0) + modifiers ^= AccPrivate; + + methodBinding.modifiers = modifiers; + } + + /* Spec : 8.4.3 & 9.4 + */ + private void checkAndSetModifiersForMethod(MethodBinding methodBinding) { + + int modifiers = methodBinding.modifiers; + if ((modifiers & AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & AccJustFlag; + + // set the requested modifiers for a method in an interface + if (methodBinding.declaringClass.isInterface()) { + if ((realModifiers & ~(AccPublic | AccAbstract)) != 0) + problemReporter().illegalModifierForInterfaceMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + return; + } + + // check for abnormal modifiers + int unexpectedModifiers = + ~( + AccPublic + | AccPrivate + | AccProtected + | AccAbstract + | AccStatic + | AccFinal + | AccSynchronized + | AccNative + | AccStrictfp); + if ((realModifiers & unexpectedModifiers) != 0) + problemReporter().illegalModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive + if ((accessorBits & AccPublic) != 0) { + if ((accessorBits & AccProtected) != 0) + modifiers ^= AccProtected; + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + if ((accessorBits & AccProtected) != 0) + if ((accessorBits & AccPrivate) != 0) + modifiers ^= AccPrivate; + } + + // check for modifiers incompatible with abstract modifier + if ((modifiers & AccAbstract) != 0) { + int incompatibleWithAbstract = + AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp; + if ((modifiers & incompatibleWithAbstract) != 0) + problemReporter().illegalAbstractModifierCombinationForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + if (!methodBinding.declaringClass.isAbstract()) + problemReporter().abstractMethodInAbstractClass( + (SourceTypeBinding) methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + } + + /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) + // methods from a final class are final : 8.4.3.3 + if (methodBinding.declaringClass.isFinal()) + modifiers |= AccFinal; + */ + // native methods cannot also be tagged as strictfp + if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0) + problemReporter().nativeMethodsCannotBeStrictfp( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + // static members are only authorized in a static member or top level type + if (((realModifiers & AccStatic) != 0) + && methodBinding.declaringClass.isNestedType() + && !methodBinding.declaringClass.isStatic()) + problemReporter().unexpectedStaticModifierForMethod( + methodBinding.declaringClass, + (AbstractMethodDeclaration) referenceContext); + + methodBinding.modifiers = modifiers; + } + + /* Compute variable positions in scopes given an initial position offset + * ignoring unused local variables. + * + * Deal with arguments here, locals and subscopes are processed in BlockScope method + */ + public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) { + + boolean isReportingUnusedArgument = false; + + if (referenceContext instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext; + MethodBinding method = methodDecl.binding; + CompilerOptions options = compilationUnitScope().environment.options; + if (!(method.isAbstract() + || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract) + || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete) + || method.isMain())) { + isReportingUnusedArgument = true; + } + } + this.offset = initOffset; + this.maxOffset = initOffset; + + // manage arguments + int ilocal = 0, maxLocals = this.localIndex; + while (ilocal < maxLocals) { + LocalVariableBinding local = locals[ilocal]; + if (local == null || !local.isArgument) break; // done with arguments + + // do not report fake used variable + if (isReportingUnusedArgument + && local.useFlag == LocalVariableBinding.UNUSED + && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable + this.problemReporter().unusedArgument(local.declaration); + } + + // record user-defined argument for attribute generation + codeStream.record(local); + + // assign variable position + local.resolvedPosition = this.offset; + + if ((local.type == LongBinding) || (local.type == DoubleBinding)) { + this.offset += 2; + } else { + this.offset++; + } + // check for too many arguments/local variables + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration); + } + ilocal++; + } + + // sneak in extra argument before other local variables + if (extraSyntheticArguments != null) { + for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){ + SyntheticArgumentBinding argument = extraSyntheticArguments[iarg]; + argument.resolvedPosition = this.offset; + if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){ + this.offset += 2; + } else { + this.offset++; + } + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); + } + } + } + this.computeLocalVariablePositions(ilocal, this.offset, codeStream); + } + + /* Error management: + * keep null for all the errors that prevent the method to be created + * otherwise return a correct method binding (but without the element + * that caused the problem) : ie : Incorrect thrown exception + */ + MethodBinding createMethod(AbstractMethodDeclaration method) { + + // is necessary to ensure error reporting + this.referenceContext = method; + method.scope = this; + SourceTypeBinding declaringClass = referenceType().binding; + int modifiers = method.modifiers | AccUnresolved; + if (method.isConstructor()) { + if (method.isDefaultConstructor()) { + modifiers |= AccIsDefaultConstructor; + } + method.binding = new MethodBinding(modifiers, null, null, declaringClass); + checkAndSetModifiersForConstructor(method.binding); + } else { + if (declaringClass.isInterface()) + modifiers |= AccPublic | AccAbstract; + method.binding = + new MethodBinding(modifiers, method.selector, null, null, null, declaringClass); + checkAndSetModifiersForMethod(method.binding); + } + this.isStatic = method.binding.isStatic(); + return method.binding; + } + + /* Overridden to detect the error case inside an explicit constructor call: + + class X { + int i; + X myX; + X(X x) { + this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors + } + } + */ + public FieldBinding findField( + TypeBinding receiverType, + char[] fieldName, + InvocationSite invocationSite, + boolean needResolve) { + + FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve); + if (field == null) + return null; + if (!field.isValidBinding()) + return field; // answer the error field + if (field.isStatic()) + return field; // static fields are always accessible + + if (!isConstructorCall || receiverType != enclosingSourceType()) + return field; + + if (invocationSite instanceof SingleNameReference) + return new ProblemFieldBinding( + field, // closest match + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + if (invocationSite instanceof QualifiedNameReference) { + // look to see if the field is the first binding + QualifiedNameReference name = (QualifiedNameReference) invocationSite; + if (name.binding == null) + // only true when the field is the fieldbinding at the beginning of name's tokens + return new ProblemFieldBinding( + field, // closest match + field.declaringClass, + fieldName, + NonStaticReferenceInConstructorInvocation); + } + return field; + } + + public boolean isInsideConstructor() { + + return (referenceContext instanceof ConstructorDeclaration); + } + + public boolean isInsideInitializer() { + + return (referenceContext instanceof TypeDeclaration); + } + + public boolean isInsideInitializerOrConstructor() { + + return (referenceContext instanceof TypeDeclaration) + || (referenceContext instanceof ConstructorDeclaration); + } + + /* 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. + */ + public ProblemReporter problemReporter() { + + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == this) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; + } + return outerMethodScope.problemReporter(); + } + + public final int recordInitializationStates(FlowInfo flowInfo) { + + if (!flowInfo.isReachable()) return -1; + + UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits(); + long[] extraInits = unconditionalFlowInfo.extraDefiniteInits; + long inits = unconditionalFlowInfo.definiteInits; + checkNextEntry : for (int i = lastIndex; --i >= 0;) { + if (definiteInits[i] == inits) { + long[] otherInits = extraDefiniteInits[i]; + if ((extraInits != null) && (otherInits != null)) { + if (extraInits.length == otherInits.length) { + int j, max; + for (j = 0, max = extraInits.length; j < max; j++) { + if (extraInits[j] != otherInits[j]) { + continue checkNextEntry; + } + } + return i; + } + } else { + if ((extraInits == null) && (otherInits == null)) { + return i; + } + } + } + } + + // add a new entry + if (definiteInits.length == lastIndex) { + // need a resize + System.arraycopy( + definiteInits, + 0, + (definiteInits = new long[lastIndex + 20]), + 0, + lastIndex); + System.arraycopy( + extraDefiniteInits, + 0, + (extraDefiniteInits = new long[lastIndex + 20][]), + 0, + lastIndex); + } + definiteInits[lastIndex] = inits; + if (extraInits != null) { + extraDefiniteInits[lastIndex] = new long[extraInits.length]; + System.arraycopy( + extraInits, + 0, + extraDefiniteInits[lastIndex], + 0, + extraInits.length); + } + return lastIndex++; + } + + /* Answer the reference method of this scope, or null if initialization scoope. + */ + public AbstractMethodDeclaration referenceMethod() { + + if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext; + return null; + } + + /* Answer the reference type of this scope. + * + * It is the nearest enclosing type of this scope. + */ + public TypeDeclaration referenceType() { + + return ((ClassScope) parent).referenceContext; + } + + String basicToString(int tab) { + + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$ + s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$ + s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$ + s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$ + return s; + } + +}