bugfix 1412408
[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
32 public abstract class AbstractMethodDeclaration
33         extends ASTNode
34         implements ProblemSeverities, ReferenceContext {
35                 
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;
42         public int modifiers;
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;
51         
52         public int bodyStart;
53         public int bodyEnd = -1;
54         public CompilationResult compilationResult;
55         
56         AbstractMethodDeclaration(CompilationResult compilationResult){
57                 this.compilationResult = compilationResult;
58         }
59         
60         /*
61          *      We cause the compilation task to abort to a given extent.
62          */
63         public void abort(int abortLevel) {
64
65                 if (scope == null) {
66                         throw new AbortCompilation(); // cannot do better
67                 }
68
69                 CompilationResult compilationResult =
70                         scope.referenceCompilationUnit().compilationResult;
71
72                 switch (abortLevel) {
73                         case AbortCompilation :
74                                 throw new AbortCompilation(compilationResult);
75                         case AbortCompilationUnit :
76                                 throw new AbortCompilationUnit(compilationResult);
77                         case AbortType :
78                                 throw new AbortType(compilationResult);
79                         default :
80                                 throw new AbortMethod(compilationResult);
81                 }
82         }
83
84         public abstract void analyseCode(ClassScope scope, InitializationFlowContext initializationContext, FlowInfo info);
85
86                 /**
87          * Bind and add argument's binding into the scope of the method
88          */
89         public void bindArguments() {
90
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();
94
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);
99                         }
100                 }
101         }
102
103         /**
104          * Record the thrown exception type bindings in the corresponding type references.
105          */
106         public void bindThrownExceptions() {
107
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];
116                                 }
117                         } else {
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;
129                                                         bindingIndex++;
130                                                 }
131                                         } else {
132                                                 // qualified type reference
133                                                 if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
134                                                         thrownException.resolvedType = thrownExceptionBinding;
135                                                         bindingIndex++;
136                                                 }                                               
137                                         }
138                                 }
139                         }
140                 }
141         }
142
143         public CompilationResult compilationResult() {
144                 
145                 return this.compilationResult;
146         }
147         
148         /**
149          * Bytecode generation for a method
150          */
151 //      public void generateCode(ClassScope classScope, ClassFile classFile) {
152 //              
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);
165 //                      return;
166 //              }
167 //              // regular code generation
168 //              try {
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.
175 //                              try {
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);
188 //                              }
189 //                      } else {
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);
197 //                      }
198 //              }
199 //      }
200 //
201 //      private void generateCode(ClassFile classFile) {
202 //
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);
213 //
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);
220 //                              }
221 //                      }
222 //                      if (statements != null) {
223 //                              for (int i = 0, max = statements.length; i < max; i++)
224 //                                      statements[i].generateCode(scope, codeStream);
225 //                      }
226 //                      if (this.needFreeReturn) {
227 //                              codeStream.return_();
228 //                      }
229 //                      // local variable attributes
230 //                      codeStream.exitUserScope(scope);
231 //                      codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
232 //                      classFile.completeCodeAttribute(codeAttributeOffset);
233 //                      attributeNumber++;
234 //              } else {
235 //                      checkArgumentsSize();
236 //              }
237 //              classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
238 //
239 //              // if a problem got reported during code gen, then trigger problem method creation
240 //              if (ignoreFurtherInvestigation) {
241 //                      throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
242 //              }
243 //      }
244
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) {
251 //                              size += 2;
252 //                      } else {
253 //                              size++;
254 //                      }
255 //                      if (size > 0xFF) {
256 //                              scope.problemReporter().noMoreAvailableSpaceForArgument(scope.locals[i], scope.locals[i].declaration);
257 //                      }
258 //              }
259 //      }
260         
261         public boolean hasErrors() {
262                 return this.ignoreFurtherInvestigation;
263         }
264
265         public boolean isAbstract() {
266
267                 if (binding != null)
268                         return binding.isAbstract();
269                 return (modifiers & AccAbstract) != 0;
270         }
271
272         public boolean isClinit() {
273
274                 return false;
275         }
276
277         public boolean isConstructor() {
278
279                 return false;
280         }
281
282         public boolean isDefaultConstructor() {
283
284                 return false;
285         }
286
287         public boolean isInitializationMethod() {
288
289                 return false;
290         }
291
292 //      public boolean isNative() {
293 //
294 //              if (binding != null)
295 //                      return binding.isNative(); 
296 //              return (modifiers & AccNative) != 0;
297 //      }
298
299         public boolean isStatic() {
300
301                 if (binding != null)
302                         return binding.isStatic();
303                 return (modifiers & AccStatic) != 0;
304         }
305
306         /**
307          * Fill up the method body with statement
308          */
309         public abstract void parseStatements(
310                 UnitParser parser,
311                 CompilationUnitDeclaration unit);
312         public StringBuffer print(int tab, StringBuffer output) {
313
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);
321                         }
322                 }
323                 output.append(')');
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);
329                         }
330                 }
331                 printBody(tab + 1, output);
332                 return output;
333         }
334
335         public StringBuffer printBody(int indent, StringBuffer output) {
336
337                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0) 
338                         return output.append(';');
339
340                 output.append(" {"); //$NON-NLS-1$
341                 if (this.statements != null) {
342                         for (int i = 0; i < this.statements.length; i++) {
343                                 output.append('\n');
344                                 this.statements[i].printStatement(indent, output); 
345                         }
346                 }
347                 output.append('\n'); //$NON-NLS-1$
348                 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
349                 return output;
350         }
351
352         public StringBuffer printReturnType(int indent, StringBuffer output) {
353                 
354                 return output;
355         }
356         public void resolve(ClassScope upperScope) {
357
358                 if (binding == null) {
359                         ignoreFurtherInvestigation = true;
360                 }
361
362                 try {
363                         bindArguments(); 
364                         bindThrownExceptions();
365                         resolveStatements();
366                 } catch (AbortMethod e) {       // ========= abort on fatal error =============
367                         this.ignoreFurtherInvestigation = true;
368                 } 
369         }
370
371         public void resolveStatements() {
372
373                 if (statements != null) {
374                         int i = 0, length = statements.length;
375                         while (i < length)
376                                 statements[i++].resolve(scope);
377                 }
378         }
379
380         public String returnTypeToString(int tab) {
381
382                 return ""; //$NON-NLS-1$
383         }
384
385         public void tagAsHavingErrors() {
386
387                 ignoreFurtherInvestigation = true;
388         }
389
390         public String toString(int tab) {
391
392                 String s = tabString(tab);
393                 if (modifiers != AccDefault) {
394                         s += modifiersString(modifiers);
395                 }
396
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$
404                         };
405                 };
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$
413                         };
414                 };
415
416                 s += toStringStatements(tab + 1);
417                 return s;
418         }
419
420         public String toStringStatements(int tab) {
421
422                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
423                         return ";"; //$NON-NLS-1$
424
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$
431                                 }
432                         }
433                 }
434                 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
435                 return s;
436         }
437
438         public void traverse(
439             ASTVisitor visitor,
440                 ClassScope classScope) {
441         }
442 }