1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
15 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
18 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
25 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
26 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit;
27 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
28 import net.sourceforge.phpdt.internal.compiler.problem.AbortType;
29 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
32 public abstract class AbstractMethodDeclaration
34 implements ProblemSeverities, ReferenceContext {
36 public MethodScope scope;
37 //it is not relevent for constructor but it helps to have the name of the constructor here
38 //which is always the name of the class.....parsing do extra work to fill it up while it do not have to....
39 public char[] selector;
40 public int declarationSourceStart;
41 public int declarationSourceEnd;
43 public int modifiersSourceStart;
44 public Argument[] arguments;
45 public TypeReference[] thrownExceptions;
46 public Statement[] statements;
47 public int explicitDeclarations;
48 public MethodBinding binding;
49 public boolean ignoreFurtherInvestigation = false;
50 public boolean needFreeReturn = false;
53 public int bodyEnd = -1;
54 public CompilationResult compilationResult;
56 AbstractMethodDeclaration(CompilationResult compilationResult){
57 this.compilationResult = compilationResult;
61 * We cause the compilation task to abort to a given extent.
63 public void abort(int abortLevel) {
66 throw new AbortCompilation(); // cannot do better
69 CompilationResult compilationResult =
70 scope.referenceCompilationUnit().compilationResult;
73 case AbortCompilation :
74 throw new AbortCompilation(compilationResult);
75 case AbortCompilationUnit :
76 throw new AbortCompilationUnit(compilationResult);
78 throw new AbortType(compilationResult);
80 throw new AbortMethod(compilationResult);
84 public abstract void analyseCode(ClassScope scope, InitializationFlowContext initializationContext, FlowInfo info);
87 * Bind and add argument's binding into the scope of the method
89 public void bindArguments() {
91 if (arguments != null) {
92 // by default arguments in abstract/native methods are considered to be used (no complaint is expected)
93 boolean used = binding == null || binding.isAbstract();// || binding.isNative();
95 int length = arguments.length;
96 for (int i = 0; i < length; i++) {
97 TypeBinding argType = binding == null ? null : binding.parameters[i];
98 arguments[i].bind(scope, argType, used);
104 * Record the thrown exception type bindings in the corresponding type references.
106 public void bindThrownExceptions() {
108 if (this.thrownExceptions != null
109 && this.binding != null
110 && this.binding.thrownExceptions != null) {
111 int thrownExceptionLength = this.thrownExceptions.length;
112 int length = this.binding.thrownExceptions.length;
113 if (length == thrownExceptionLength) {
114 for (int i = 0; i < length; i++) {
115 this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
118 int bindingIndex = 0;
119 for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) {
120 TypeReference thrownException = this.thrownExceptions[i];
121 ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
122 char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
123 if (thrownException instanceof SingleTypeReference) {
124 // single type reference
125 int lengthName = bindingCompoundName.length;
126 char[] thrownExceptionTypeName = thrownException.getTypeName()[0];
127 if (CharOperation.equals(thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) {
128 thrownException.resolvedType = thrownExceptionBinding;
132 // qualified type reference
133 if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
134 thrownException.resolvedType = thrownExceptionBinding;
143 public CompilationResult compilationResult() {
145 return this.compilationResult;
149 * Bytecode generation for a method
151 // public void generateCode(ClassScope classScope, ClassFile classFile) {
153 // int problemResetPC = 0;
154 // classFile.codeStream.wideMode = false; // reset wideMode to false
155 // if (ignoreFurtherInvestigation) {
156 // // method is known to have errors, dump a problem method
157 // if (this.binding == null)
158 // return; // handle methods with invalid signature or duplicates
159 // int problemsLength;
160 // IProblem[] problems =
161 // scope.referenceCompilationUnit().compilationResult.getProblems();
162 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
163 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
164 // classFile.addProblemMethod(this, binding, problemsCopy);
167 // // regular code generation
169 // problemResetPC = classFile.contentsOffset;
170 // this.generateCode(classFile);
171 // } catch (AbortMethod e) {
172 // // a fatal error was detected during code generation, need to restart code gen if possible
173 // if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
174 // // a branch target required a goto_w, restart code gen in wide mode.
176 // this.traverse(new ResetStateForCodeGenerationVisitor(), classScope);
177 // classFile.contentsOffset = problemResetPC;
178 // classFile.methodCount--;
179 // classFile.codeStream.wideMode = true; // request wide mode
180 // this.generateCode(classFile); // restart method generation
181 // } catch (AbortMethod e2) {
182 // int problemsLength;
183 // IProblem[] problems =
184 // scope.referenceCompilationUnit().compilationResult.getAllProblems();
185 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
186 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
187 // classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC);
190 // // produce a problem method accounting for this fatal error
191 // int problemsLength;
192 // IProblem[] problems =
193 // scope.referenceCompilationUnit().compilationResult.getAllProblems();
194 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
195 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
196 // classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC);
201 // private void generateCode(ClassFile classFile) {
203 // classFile.generateMethodInfoHeader(binding);
204 // int methodAttributeOffset = classFile.contentsOffset;
205 // int attributeNumber = classFile.generateMethodInfoAttribute(binding);
206 // if ((!binding.isNative()) && (!binding.isAbstract())) {
207 // int codeAttributeOffset = classFile.contentsOffset;
208 // classFile.generateCodeAttributeHeader();
209 // CodeStream codeStream = classFile.codeStream;
210 // codeStream.reset(this, classFile);
211 // // initialize local positions
212 // this.scope.computeLocalVariablePositions(binding.isStatic() ? 0 : 1, codeStream);
214 // // arguments initialization for local variable debug attributes
215 // if (arguments != null) {
216 // for (int i = 0, max = arguments.length; i < max; i++) {
217 // LocalVariableBinding argBinding;
218 // codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
219 // argBinding.recordInitializationStartPC(0);
222 // if (statements != null) {
223 // for (int i = 0, max = statements.length; i < max; i++)
224 // statements[i].generateCode(scope, codeStream);
226 // if (this.needFreeReturn) {
227 // codeStream.return_();
229 // // local variable attributes
230 // codeStream.exitUserScope(scope);
231 // codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
232 // classFile.completeCodeAttribute(codeAttributeOffset);
233 // attributeNumber++;
235 // checkArgumentsSize();
237 // classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
239 // // if a problem got reported during code gen, then trigger problem method creation
240 // if (ignoreFurtherInvestigation) {
241 // throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
245 // private void checkArgumentsSize() {
246 // TypeBinding[] parameters = binding.parameters;
247 // int size = 1; // an abstact method or a native method cannot be static
248 // for (int i = 0, max = parameters.length; i < max; i++) {
249 // TypeBinding parameter = parameters[i];
250 // if (parameter == LongBinding || parameter == DoubleBinding) {
255 // if (size > 0xFF) {
256 // scope.problemReporter().noMoreAvailableSpaceForArgument(scope.locals[i], scope.locals[i].declaration);
261 public boolean hasErrors() {
262 return this.ignoreFurtherInvestigation;
265 public boolean isAbstract() {
268 return binding.isAbstract();
269 return (modifiers & AccAbstract) != 0;
272 public boolean isClinit() {
277 public boolean isConstructor() {
282 public boolean isDefaultConstructor() {
287 public boolean isInitializationMethod() {
292 // public boolean isNative() {
294 // if (binding != null)
295 // return binding.isNative();
296 // return (modifiers & AccNative) != 0;
299 public boolean isStatic() {
302 return binding.isStatic();
303 return (modifiers & AccStatic) != 0;
307 * Fill up the method body with statement
309 public abstract void parseStatements(
311 CompilationUnitDeclaration unit);
312 public StringBuffer print(int tab, StringBuffer output) {
314 printIndent(tab, output);
315 printModifiers(this.modifiers, output);
316 printReturnType(0, output).append(this.selector).append('(');
317 if (this.arguments != null) {
318 for (int i = 0; i < this.arguments.length; i++) {
319 if (i > 0) output.append(", "); //$NON-NLS-1$
320 this.arguments[i].print(0, output);
324 if (this.thrownExceptions != null) {
325 output.append(" throws "); //$NON-NLS-1$
326 for (int i = 0; i < this.thrownExceptions.length; i++) {
327 if (i > 0) output.append(", "); //$NON-NLS-1$
328 this.thrownExceptions[i].print(0, output);
331 printBody(tab + 1, output);
335 public StringBuffer printBody(int indent, StringBuffer output) {
337 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
338 return output.append(';');
340 output.append(" {"); //$NON-NLS-1$
341 if (this.statements != null) {
342 for (int i = 0; i < this.statements.length; i++) {
344 this.statements[i].printStatement(indent, output);
347 output.append('\n'); //$NON-NLS-1$
348 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
352 public StringBuffer printReturnType(int indent, StringBuffer output) {
356 public void resolve(ClassScope upperScope) {
358 if (binding == null) {
359 ignoreFurtherInvestigation = true;
364 bindThrownExceptions();
366 } catch (AbortMethod e) { // ========= abort on fatal error =============
367 this.ignoreFurtherInvestigation = true;
371 public void resolveStatements() {
373 if (statements != null) {
374 int i = 0, length = statements.length;
376 statements[i++].resolve(scope);
380 public String returnTypeToString(int tab) {
382 return ""; //$NON-NLS-1$
385 public void tagAsHavingErrors() {
387 ignoreFurtherInvestigation = true;
390 public String toString(int tab) {
392 String s = tabString(tab);
393 if (modifiers != AccDefault) {
394 s += modifiersString(modifiers);
397 s += returnTypeToString(0);
398 s += new String(selector) + "("; //$NON-NLS-1$
399 if (arguments != null) {
400 for (int i = 0; i < arguments.length; i++) {
401 s += arguments[i].toString(0);
402 if (i != (arguments.length - 1))
403 s = s + ", "; //$NON-NLS-1$
406 s += ")"; //$NON-NLS-1$
407 if (thrownExceptions != null) {
408 s += " throws "; //$NON-NLS-1$
409 for (int i = 0; i < thrownExceptions.length; i++) {
410 s += thrownExceptions[i].toString(0);
411 if (i != (thrownExceptions.length - 1))
412 s = s + ", "; //$NON-NLS-1$
416 s += toStringStatements(tab + 1);
420 public String toStringStatements(int tab) {
422 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
423 return ";"; //$NON-NLS-1$
425 String s = " {"; //$NON-NLS-1$
426 if (statements != null) {
427 for (int i = 0; i < statements.length; i++) {
428 s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$
429 if (!(statements[i] instanceof Block)) {
430 s += ";"; //$NON-NLS-1$
434 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
438 public void traverse(
440 ClassScope classScope) {