/******************************************************************************* * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.ast; import net.sourceforge.phpdt.internal.compiler.CompilationResult; import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor; import net.sourceforge.phpdt.internal.compiler.flow.ExceptionHandlingFlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext; import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod; public class Clinit extends AbstractMethodDeclaration { public final static char[] ConstantPoolName = "".toCharArray(); //$NON-NLS-1$ private FieldBinding assertionSyntheticFieldBinding = null; private FieldBinding classLiteralSyntheticField = null; public Clinit(CompilationResult compilationResult) { super(compilationResult); modifiers = 0; selector = ConstantPoolName; } public void analyseCode(ClassScope classScope, InitializationFlowContext staticInitializerFlowContext, FlowInfo flowInfo) { if (ignoreFurtherInvestigation) return; try { ExceptionHandlingFlowContext clinitContext = new ExceptionHandlingFlowContext( staticInitializerFlowContext.parent, this, NoExceptions, scope, FlowInfo.DEAD_END); // check for missing returning path this.needFreeReturn = flowInfo.isReachable(); // check missing blank final field initializations flowInfo = flowInfo .mergedWith(staticInitializerFlowContext.initsOnReturn); FieldBinding[] fields = scope.enclosingSourceType().fields(); for (int i = 0, count = fields.length; i < count; i++) { FieldBinding field; if ((field = fields[i]).isStatic() && field.isFinal() && (!flowInfo.isDefinitelyAssigned(fields[i]))) { scope.problemReporter().uninitializedBlankFinalField(field, scope.referenceType().declarationOf(field)); // can complain against the field decl, since only one // } } // check static initializers thrown exceptions staticInitializerFlowContext.checkInitializerExceptions(scope, clinitContext, flowInfo); } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } } /** * Bytecode generation for a method * * @param classScope * net.sourceforge.phpdt.internal.compiler.lookup.ClassScope * @param classFile * net.sourceforge.phpdt.internal.compiler.codegen.ClassFile */ // public void generateCode(ClassScope classScope, ClassFile classFile) { // // int clinitOffset = 0; // if (ignoreFurtherInvestigation) { // // should never have to add any problem method // return; // } // try { // clinitOffset = classFile.contentsOffset; // this.generateCode(classScope, classFile, clinitOffset); // } catch (AbortMethod e) { // // should never occur // // the clinit referenceContext is the type declaration // // All clinit problems will be reported against the type: AbortType // instead of AbortMethod // // reset the contentsOffset to the value before generating the clinit // code // // decrement the number of method info as well. // // This is done in the addProblemMethod and addProblemConstructor for // other // // cases. // if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { // // a branch target required a goto_w, restart code gen in wide mode. // try { // if (statements != null) { // for (int i = 0, max = statements.length; i < max; i++) // statements[i].resetStateForCodeGeneration(); // } // classFile.contentsOffset = clinitOffset; // classFile.methodCount--; // classFile.codeStream.wideMode = true; // request wide mode // this.generateCode(classScope, classFile, clinitOffset); // // restart method generation // } catch (AbortMethod e2) { // classFile.contentsOffset = clinitOffset; // classFile.methodCount--; // } // } else { // // produce a problem method accounting for this fatal error // classFile.contentsOffset = clinitOffset; // classFile.methodCount--; // } // } // } /** * Bytecode generation for a method * * @param classScope * net.sourceforge.phpdt.internal.compiler.lookup.ClassScope * @param classFile * net.sourceforge.phpdt.internal.compiler.codegen.ClassFile */ // private void generateCode( // ClassScope classScope, // ClassFile classFile, // int clinitOffset) { // // ConstantPool constantPool = classFile.constantPool; // int constantPoolOffset = constantPool.currentOffset; // int constantPoolIndex = constantPool.currentIndex; // classFile.generateMethodInfoHeaderForClinit(); // int codeAttributeOffset = classFile.contentsOffset; // classFile.generateCodeAttributeHeader(); // CodeStream codeStream = classFile.codeStream; // this.resolve(classScope); // // codeStream.reset(this, classFile); // TypeDeclaration declaringType = classScope.referenceContext; // // // initialize local positions - including initializer scope. // MethodScope staticInitializerScope = // declaringType.staticInitializerScope; // staticInitializerScope.computeLocalVariablePositions(0, codeStream); // // // 1.4 feature // // This has to be done before any other initialization // if (this.assertionSyntheticFieldBinding != null) { // // generate code related to the activation of assertion for this class // codeStream.generateClassLiteralAccessForType( // classScope.enclosingSourceType(), // classLiteralSyntheticField); // codeStream.invokeJavaLangClassDesiredAssertionStatus(); // Label falseLabel = new Label(codeStream); // codeStream.ifne(falseLabel); // codeStream.iconst_1(); // Label jumpLabel = new Label(codeStream); // codeStream.goto_(jumpLabel); // falseLabel.place(); // codeStream.iconst_0(); // jumpLabel.place(); // codeStream.putstatic(this.assertionSyntheticFieldBinding); // } // // generate initializers // if (declaringType.fields != null) { // for (int i = 0, max = declaringType.fields.length; i < max; i++) { // FieldDeclaration fieldDecl; // if ((fieldDecl = declaringType.fields[i]).isStatic()) { // fieldDecl.generateCode(staticInitializerScope, codeStream); // } // } // } // if (codeStream.position == 0) { // // do not need to output a Clinit if no bytecodes // // so we reset the offset inside the byte array contents. // classFile.contentsOffset = clinitOffset; // // like we don't addd a method we need to undo the increment on the // method count // classFile.methodCount--; // // reset the constant pool to its state before the clinit // constantPool.resetForClinit(constantPoolIndex, constantPoolOffset); // } else { // if (this.needFreeReturn) { // int oldPosition = codeStream.position; // codeStream.return_(); // codeStream.updateLocalVariablesAttribute(oldPosition); // } // // Record the end of the clinit: point to the declaration of the class // codeStream.recordPositionsFrom(0, declaringType.sourceStart); // classFile.completeCodeAttributeForClinit(codeAttributeOffset); // } // } public boolean isClinit() { return true; } public boolean isInitializationMethod() { return true; } public boolean isStatic() { return true; } public void parseStatements(UnitParser parser, CompilationUnitDeclaration unit) { // the clinit is filled by hand .... } public StringBuffer print(int tab, StringBuffer output) { printIndent(tab, output).append("()"); //$NON-NLS-1$ printBody(tab + 1, output); return output; } public void resolve(ClassScope scope) { this.scope = new MethodScope(scope, scope.referenceContext, true); } public String toString(int tab) { String s = ""; //$NON-NLS-1$ s = s + tabString(tab); s = s + "()"; //$NON-NLS-1$ s = s + toStringStatements(tab + 1); return s; } public void traverse(IAbstractSyntaxTreeVisitor visitor, ClassScope classScope) { visitor.visit(this, classScope); visitor.endVisit(this, classScope); } // 1.4 feature public void addSupportForAssertion( FieldBinding assertionSyntheticFieldBinding) { this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding; // we need to add the field right now, because the field infos are // generated before the methods SourceTypeBinding sourceType = this.scope.outerMostMethodScope() .enclosingSourceType(); this.classLiteralSyntheticField = sourceType.addSyntheticField( sourceType, scope); } }