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.phpdt.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;
31 public abstract class AbstractMethodDeclaration extends ASTNode implements
32 ProblemSeverities, ReferenceContext {
34 public MethodScope scope;
36 // it is not relevent for constructor but it helps to have the name of the
38 // which is always the name of the class.....parsing do extra work to fill
39 // it up while it do not have to....
40 public char[] selector;
42 public int declarationSourceStart;
44 public int declarationSourceEnd;
48 public int modifiersSourceStart;
50 public Argument[] arguments;
52 public TypeReference[] thrownExceptions;
54 public Statement[] statements;
56 public int explicitDeclarations;
58 public MethodBinding binding;
60 public boolean ignoreFurtherInvestigation = false;
62 public boolean needFreeReturn = false;
66 public int bodyEnd = -1;
68 public CompilationResult compilationResult;
70 AbstractMethodDeclaration(CompilationResult compilationResult) {
71 this.compilationResult = compilationResult;
75 * We cause the compilation task to abort to a given extent.
77 public void abort(int abortLevel) {
80 throw new AbortCompilation(); // cannot do better
83 CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult;
86 case AbortCompilation:
87 throw new AbortCompilation(compilationResult);
88 case AbortCompilationUnit:
89 throw new AbortCompilationUnit(compilationResult);
91 throw new AbortType(compilationResult);
93 throw new AbortMethod(compilationResult);
97 public abstract void analyseCode(ClassScope scope,
98 InitializationFlowContext initializationContext, FlowInfo info);
101 * Bind and add argument's binding into the scope of the method
103 public void bindArguments() {
105 if (arguments != null) {
106 // by default arguments in abstract/native methods are considered to
107 // be used (no complaint is expected)
108 boolean used = binding == null || binding.isAbstract();// ||
109 // binding.isNative();
111 int length = arguments.length;
112 for (int i = 0; i < length; i++) {
113 TypeBinding argType = binding == null ? null
114 : binding.parameters[i];
115 arguments[i].bind(scope, argType, used);
121 * Record the thrown exception type bindings in the corresponding type
124 public void bindThrownExceptions() {
126 if (this.thrownExceptions != null && this.binding != null
127 && this.binding.thrownExceptions != null) {
128 int thrownExceptionLength = this.thrownExceptions.length;
129 int length = this.binding.thrownExceptions.length;
130 if (length == thrownExceptionLength) {
131 for (int i = 0; i < length; i++) {
132 this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
135 int bindingIndex = 0;
136 for (int i = 0; i < thrownExceptionLength
137 && bindingIndex < length; i++) {
138 TypeReference thrownException = this.thrownExceptions[i];
139 ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
140 char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
141 if (thrownException instanceof SingleTypeReference) {
142 // single type reference
143 int lengthName = bindingCompoundName.length;
144 char[] thrownExceptionTypeName = thrownException
146 if (CharOperation.equals(thrownExceptionTypeName,
147 bindingCompoundName[lengthName - 1])) {
148 thrownException.resolvedType = thrownExceptionBinding;
152 // qualified type reference
153 if (CharOperation.equals(thrownException.getTypeName(),
154 bindingCompoundName)) {
155 thrownException.resolvedType = thrownExceptionBinding;
164 public CompilationResult compilationResult() {
166 return this.compilationResult;
170 * Bytecode generation for a method
172 // public void generateCode(ClassScope classScope, ClassFile classFile) {
174 // int problemResetPC = 0;
175 // classFile.codeStream.wideMode = false; // reset wideMode to false
176 // if (ignoreFurtherInvestigation) {
177 // // method is known to have errors, dump a problem method
178 // if (this.binding == null)
179 // return; // handle methods with invalid signature or duplicates
180 // int problemsLength;
181 // IProblem[] problems =
182 // scope.referenceCompilationUnit().compilationResult.getProblems();
183 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
184 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
185 // classFile.addProblemMethod(this, binding, problemsCopy);
188 // // regular code generation
190 // problemResetPC = classFile.contentsOffset;
191 // this.generateCode(classFile);
192 // } catch (AbortMethod e) {
193 // // a fatal error was detected during code generation, need to restart
194 // code gen if possible
195 // if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
196 // // a branch target required a goto_w, restart code gen in wide mode.
198 // this.traverse(new ResetStateForCodeGenerationVisitor(), classScope);
199 // classFile.contentsOffset = problemResetPC;
200 // classFile.methodCount--;
201 // classFile.codeStream.wideMode = true; // request wide mode
202 // this.generateCode(classFile); // restart method generation
203 // } catch (AbortMethod e2) {
204 // int problemsLength;
205 // IProblem[] problems =
206 // scope.referenceCompilationUnit().compilationResult.getAllProblems();
207 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
208 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
209 // classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC);
212 // // produce a problem method accounting for this fatal error
213 // int problemsLength;
214 // IProblem[] problems =
215 // scope.referenceCompilationUnit().compilationResult.getAllProblems();
216 // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
217 // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
218 // classFile.addProblemMethod(this, binding, problemsCopy, problemResetPC);
223 // private void generateCode(ClassFile classFile) {
225 // classFile.generateMethodInfoHeader(binding);
226 // int methodAttributeOffset = classFile.contentsOffset;
227 // int attributeNumber = classFile.generateMethodInfoAttribute(binding);
228 // if ((!binding.isNative()) && (!binding.isAbstract())) {
229 // int codeAttributeOffset = classFile.contentsOffset;
230 // classFile.generateCodeAttributeHeader();
231 // CodeStream codeStream = classFile.codeStream;
232 // codeStream.reset(this, classFile);
233 // // initialize local positions
234 // this.scope.computeLocalVariablePositions(binding.isStatic() ? 0 : 1,
237 // // arguments initialization for local variable debug attributes
238 // if (arguments != null) {
239 // for (int i = 0, max = arguments.length; i < max; i++) {
240 // LocalVariableBinding argBinding;
241 // codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
242 // argBinding.recordInitializationStartPC(0);
245 // if (statements != null) {
246 // for (int i = 0, max = statements.length; i < max; i++)
247 // statements[i].generateCode(scope, codeStream);
249 // if (this.needFreeReturn) {
250 // codeStream.return_();
252 // // local variable attributes
253 // codeStream.exitUserScope(scope);
254 // codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
255 // classFile.completeCodeAttribute(codeAttributeOffset);
256 // attributeNumber++;
258 // checkArgumentsSize();
260 // classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
262 // // if a problem got reported during code gen, then trigger problem method
264 // if (ignoreFurtherInvestigation) {
266 // AbortMethod(scope.referenceCompilationUnit().compilationResult);
269 // private void checkArgumentsSize() {
270 // TypeBinding[] parameters = binding.parameters;
271 // int size = 1; // an abstact method or a native method cannot be static
272 // for (int i = 0, max = parameters.length; i < max; i++) {
273 // TypeBinding parameter = parameters[i];
274 // if (parameter == LongBinding || parameter == DoubleBinding) {
279 // if (size > 0xFF) {
280 // scope.problemReporter().noMoreAvailableSpaceForArgument(scope.locals[i],
281 // scope.locals[i].declaration);
285 public boolean hasErrors() {
286 return this.ignoreFurtherInvestigation;
289 public boolean isAbstract() {
292 return binding.isAbstract();
293 return (modifiers & AccAbstract) != 0;
296 public boolean isClinit() {
301 public boolean isConstructor() {
306 public boolean isDefaultConstructor() {
311 public boolean isInitializationMethod() {
316 // public boolean isNative() {
318 // if (binding != null)
319 // return binding.isNative();
320 // return (modifiers & AccNative) != 0;
323 public boolean isStatic() {
326 return binding.isStatic();
327 return (modifiers & AccStatic) != 0;
331 * Fill up the method body with statement
333 public abstract void parseStatements(UnitParser parser,
334 CompilationUnitDeclaration unit);
336 public StringBuffer print(int tab, StringBuffer output) {
338 printIndent(tab, output);
339 printModifiers(this.modifiers, output);
340 printReturnType(0, output).append(this.selector).append('(');
341 if (this.arguments != null) {
342 for (int i = 0; i < this.arguments.length; i++) {
344 output.append(", "); //$NON-NLS-1$
345 this.arguments[i].print(0, output);
349 if (this.thrownExceptions != null) {
350 output.append(" throws "); //$NON-NLS-1$
351 for (int i = 0; i < this.thrownExceptions.length; i++) {
353 output.append(", "); //$NON-NLS-1$
354 this.thrownExceptions[i].print(0, output);
357 printBody(tab + 1, output);
361 public StringBuffer printBody(int indent, StringBuffer output) {
363 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
364 return output.append(';');
366 output.append(" {"); //$NON-NLS-1$
367 if (this.statements != null) {
368 for (int i = 0; i < this.statements.length; i++) {
370 this.statements[i].printStatement(indent, output);
373 output.append('\n'); //$NON-NLS-1$
374 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
378 public StringBuffer printReturnType(int indent, StringBuffer output) {
383 public void resolve(ClassScope upperScope) {
385 if (binding == null) {
386 ignoreFurtherInvestigation = true;
391 bindThrownExceptions();
393 } catch (AbortMethod e) { // ========= abort on fatal error
395 this.ignoreFurtherInvestigation = true;
399 public void resolveStatements() {
401 if (statements != null) {
402 int i = 0, length = statements.length;
404 statements[i++].resolve(scope);
408 public String returnTypeToString(int tab) {
410 return ""; //$NON-NLS-1$
413 public void tagAsHavingErrors() {
415 ignoreFurtherInvestigation = true;
418 public String toString(int tab) {
420 String s = tabString(tab);
421 if (modifiers != AccDefault) {
422 s += modifiersString(modifiers);
425 s += returnTypeToString(0);
426 s += new String(selector) + "("; //$NON-NLS-1$
427 if (arguments != null) {
428 for (int i = 0; i < arguments.length; i++) {
429 s += arguments[i].toString(0);
430 if (i != (arguments.length - 1))
431 s = s + ", "; //$NON-NLS-1$
436 s += ")"; //$NON-NLS-1$
437 if (thrownExceptions != null) {
438 s += " throws "; //$NON-NLS-1$
439 for (int i = 0; i < thrownExceptions.length; i++) {
440 s += thrownExceptions[i].toString(0);
441 if (i != (thrownExceptions.length - 1))
442 s = s + ", "; //$NON-NLS-1$
448 s += toStringStatements(tab + 1);
452 public String toStringStatements(int tab) {
454 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
455 return ";"; //$NON-NLS-1$
457 String s = " {"; //$NON-NLS-1$
458 if (statements != null) {
459 for (int i = 0; i < statements.length; i++) {
460 s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$
461 if (!(statements[i] instanceof Block)) {
462 s += ";"; //$NON-NLS-1$
466 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
470 public void traverse(ASTVisitor visitor, ClassScope classScope) {