Fix #1475484 - code formatter: bad result for array() embedding func calls
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AbstractMethodDeclaration.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
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;
30
31 public abstract class AbstractMethodDeclaration extends ASTNode implements
32                 ProblemSeverities, ReferenceContext {
33
34         public MethodScope scope;
35
36         // it is not relevent for constructor but it helps to have the name of the
37         // constructor here
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;
41
42         public int declarationSourceStart;
43
44         public int declarationSourceEnd;
45
46         public int modifiers;
47
48         public int modifiersSourceStart;
49
50         public Argument[] arguments;
51
52         public TypeReference[] thrownExceptions;
53
54         public Statement[] statements;
55
56         public int explicitDeclarations;
57
58         public MethodBinding binding;
59
60         public boolean ignoreFurtherInvestigation = false;
61
62         public boolean needFreeReturn = false;
63
64         public int bodyStart;
65
66         public int bodyEnd = -1;
67
68         public CompilationResult compilationResult;
69
70         AbstractMethodDeclaration(CompilationResult compilationResult) {
71                 this.compilationResult = compilationResult;
72         }
73
74         /*
75          * We cause the compilation task to abort to a given extent.
76          */
77         public void abort(int abortLevel) {
78
79                 if (scope == null) {
80                         throw new AbortCompilation(); // cannot do better
81                 }
82
83                 CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult;
84
85                 switch (abortLevel) {
86                 case AbortCompilation:
87                         throw new AbortCompilation(compilationResult);
88                 case AbortCompilationUnit:
89                         throw new AbortCompilationUnit(compilationResult);
90                 case AbortType:
91                         throw new AbortType(compilationResult);
92                 default:
93                         throw new AbortMethod(compilationResult);
94                 }
95         }
96
97         public abstract void analyseCode(ClassScope scope,
98                         InitializationFlowContext initializationContext, FlowInfo info);
99
100         /**
101          * Bind and add argument's binding into the scope of the method
102          */
103         public void bindArguments() {
104
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();
110
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);
116                         }
117                 }
118         }
119
120         /**
121          * Record the thrown exception type bindings in the corresponding type
122          * references.
123          */
124         public void bindThrownExceptions() {
125
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];
133                                 }
134                         } else {
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
145                                                                 .getTypeName()[0];
146                                                 if (CharOperation.equals(thrownExceptionTypeName,
147                                                                 bindingCompoundName[lengthName - 1])) {
148                                                         thrownException.resolvedType = thrownExceptionBinding;
149                                                         bindingIndex++;
150                                                 }
151                                         } else {
152                                                 // qualified type reference
153                                                 if (CharOperation.equals(thrownException.getTypeName(),
154                                                                 bindingCompoundName)) {
155                                                         thrownException.resolvedType = thrownExceptionBinding;
156                                                         bindingIndex++;
157                                                 }
158                                         }
159                                 }
160                         }
161                 }
162         }
163
164         public CompilationResult compilationResult() {
165
166                 return this.compilationResult;
167         }
168
169         /**
170          * Bytecode generation for a method
171          */
172         // public void generateCode(ClassScope classScope, ClassFile classFile) {
173         //              
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);
186         // return;
187         // }
188         // // regular code generation
189         // try {
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.
197         // try {
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);
210         // }
211         // } else {
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);
219         // }
220         // }
221         // }
222         //
223         // private void generateCode(ClassFile classFile) {
224         //
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,
235         // codeStream);
236         //
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);
243         // }
244         // }
245         // if (statements != null) {
246         // for (int i = 0, max = statements.length; i < max; i++)
247         // statements[i].generateCode(scope, codeStream);
248         // }
249         // if (this.needFreeReturn) {
250         // codeStream.return_();
251         // }
252         // // local variable attributes
253         // codeStream.exitUserScope(scope);
254         // codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
255         // classFile.completeCodeAttribute(codeAttributeOffset);
256         // attributeNumber++;
257         // } else {
258         // checkArgumentsSize();
259         // }
260         // classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
261         //
262         // // if a problem got reported during code gen, then trigger problem method
263         // creation
264         // if (ignoreFurtherInvestigation) {
265         // throw new
266         // AbortMethod(scope.referenceCompilationUnit().compilationResult);
267         // }
268         // }
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) {
275         // size += 2;
276         // } else {
277         // size++;
278         // }
279         // if (size > 0xFF) {
280         // scope.problemReporter().noMoreAvailableSpaceForArgument(scope.locals[i],
281         // scope.locals[i].declaration);
282         // }
283         // }
284         // }
285         public boolean hasErrors() {
286                 return this.ignoreFurtherInvestigation;
287         }
288
289         public boolean isAbstract() {
290
291                 if (binding != null)
292                         return binding.isAbstract();
293                 return (modifiers & AccAbstract) != 0;
294         }
295
296         public boolean isClinit() {
297
298                 return false;
299         }
300
301         public boolean isConstructor() {
302
303                 return false;
304         }
305
306         public boolean isDefaultConstructor() {
307
308                 return false;
309         }
310
311         public boolean isInitializationMethod() {
312
313                 return false;
314         }
315
316         // public boolean isNative() {
317         //
318         // if (binding != null)
319         // return binding.isNative();
320         // return (modifiers & AccNative) != 0;
321         // }
322
323         public boolean isStatic() {
324
325                 if (binding != null)
326                         return binding.isStatic();
327                 return (modifiers & AccStatic) != 0;
328         }
329
330         /**
331          * Fill up the method body with statement
332          */
333         public abstract void parseStatements(UnitParser parser,
334                         CompilationUnitDeclaration unit);
335
336         public StringBuffer print(int tab, StringBuffer output) {
337
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++) {
343                                 if (i > 0)
344                                         output.append(", "); //$NON-NLS-1$
345                                 this.arguments[i].print(0, output);
346                         }
347                 }
348                 output.append(')');
349                 if (this.thrownExceptions != null) {
350                         output.append(" throws "); //$NON-NLS-1$
351                         for (int i = 0; i < this.thrownExceptions.length; i++) {
352                                 if (i > 0)
353                                         output.append(", "); //$NON-NLS-1$
354                                 this.thrownExceptions[i].print(0, output);
355                         }
356                 }
357                 printBody(tab + 1, output);
358                 return output;
359         }
360
361         public StringBuffer printBody(int indent, StringBuffer output) {
362
363                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
364                         return output.append(';');
365
366                 output.append(" {"); //$NON-NLS-1$
367                 if (this.statements != null) {
368                         for (int i = 0; i < this.statements.length; i++) {
369                                 output.append('\n');
370                                 this.statements[i].printStatement(indent, output);
371                         }
372                 }
373                 output.append('\n'); //$NON-NLS-1$
374                 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
375                 return output;
376         }
377
378         public StringBuffer printReturnType(int indent, StringBuffer output) {
379
380                 return output;
381         }
382
383         public void resolve(ClassScope upperScope) {
384
385                 if (binding == null) {
386                         ignoreFurtherInvestigation = true;
387                 }
388
389                 try {
390                         bindArguments();
391                         bindThrownExceptions();
392                         resolveStatements();
393                 } catch (AbortMethod e) { // ========= abort on fatal error
394                                                                         // =============
395                         this.ignoreFurtherInvestigation = true;
396                 }
397         }
398
399         public void resolveStatements() {
400
401                 if (statements != null) {
402                         int i = 0, length = statements.length;
403                         while (i < length)
404                                 statements[i++].resolve(scope);
405                 }
406         }
407
408         public String returnTypeToString(int tab) {
409
410                 return ""; //$NON-NLS-1$
411         }
412
413         public void tagAsHavingErrors() {
414
415                 ignoreFurtherInvestigation = true;
416         }
417
418         public String toString(int tab) {
419
420                 String s = tabString(tab);
421                 if (modifiers != AccDefault) {
422                         s += modifiersString(modifiers);
423                 }
424
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$
432                         }
433                         ;
434                 }
435                 ;
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$
443                         }
444                         ;
445                 }
446                 ;
447
448                 s += toStringStatements(tab + 1);
449                 return s;
450         }
451
452         public String toStringStatements(int tab) {
453
454                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
455                         return ";"; //$NON-NLS-1$
456
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$
463                                 }
464                         }
465                 }
466                 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
467                 return s;
468         }
469
470         public void traverse(ASTVisitor visitor, ClassScope classScope) {
471         }
472 }