Added Run Tests Action in the popup menu for .php file
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / 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.phpeclipse.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
15 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
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
313         public void resolve(ClassScope upperScope) {
314
315                 if (binding == null) {
316                         ignoreFurtherInvestigation = true;
317                 }
318
319                 try {
320                         bindArguments(); 
321                         bindThrownExceptions();
322                         resolveStatements();
323                 } catch (AbortMethod e) {       // ========= abort on fatal error =============
324                         this.ignoreFurtherInvestigation = true;
325                 } 
326         }
327
328         public void resolveStatements() {
329
330                 if (statements != null) {
331                         int i = 0, length = statements.length;
332                         while (i < length)
333                                 statements[i++].resolve(scope);
334                 }
335         }
336
337         public String returnTypeToString(int tab) {
338
339                 return ""; //$NON-NLS-1$
340         }
341
342         public void tagAsHavingErrors() {
343
344                 ignoreFurtherInvestigation = true;
345         }
346
347         public String toString(int tab) {
348
349                 String s = tabString(tab);
350                 if (modifiers != AccDefault) {
351                         s += modifiersString(modifiers);
352                 }
353
354                 s += returnTypeToString(0);
355                 s += new String(selector) + "("; //$NON-NLS-1$
356                 if (arguments != null) {
357                         for (int i = 0; i < arguments.length; i++) {
358                                 s += arguments[i].toString(0);
359                                 if (i != (arguments.length - 1))
360                                         s = s + ", "; //$NON-NLS-1$
361                         };
362                 };
363                 s += ")"; //$NON-NLS-1$
364                 if (thrownExceptions != null) {
365                         s += " throws "; //$NON-NLS-1$
366                         for (int i = 0; i < thrownExceptions.length; i++) {
367                                 s += thrownExceptions[i].toString(0);
368                                 if (i != (thrownExceptions.length - 1))
369                                         s = s + ", "; //$NON-NLS-1$
370                         };
371                 };
372
373                 s += toStringStatements(tab + 1);
374                 return s;
375         }
376
377         public String toStringStatements(int tab) {
378
379                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
380                         return ";"; //$NON-NLS-1$
381
382                 String s = " {"; //$NON-NLS-1$
383                 if (statements != null) {
384                         for (int i = 0; i < statements.length; i++) {
385                                 s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$
386                                 if (!(statements[i] instanceof Block)) {
387                                         s += ";"; //$NON-NLS-1$
388                                 }
389                         }
390                 }
391                 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
392                 return s;
393         }
394
395         public void traverse(
396                 IAbstractSyntaxTreeVisitor visitor,
397                 ClassScope classScope) {
398         }
399 }