Fixed bug #1404228: Crash on <?php // comment ?>
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / MethodDeclaration.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.ExceptionHandlingFlowContext;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
22 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
23
24 public class MethodDeclaration extends AbstractMethodDeclaration {
25
26   public TypeReference returnType;
27   public static final int FUNCTION_DEFINITION = 1;
28   public static final int METHOD_DEFINITION = 2;
29   public int type;
30
31   /**
32    * MethodDeclaration constructor comment.
33    */
34   public MethodDeclaration(CompilationResult compilationResult) {
35     super(compilationResult);
36   }
37
38   public void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo flowInfo) {
39
40     // starting of the code analysis for methods
41     if (ignoreFurtherInvestigation)
42       return;
43     try {
44       if (binding == null)
45         return;
46
47       if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
48         if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
49           scope.problemReporter().unusedPrivateMethod(this);
50         }
51       }
52
53       // may be in a non necessary <clinit> for innerclass with static final constant fields
54       if (binding.isAbstract()) // || binding.isNative())
55         return;
56
57       ExceptionHandlingFlowContext methodContext =
58         new ExceptionHandlingFlowContext(initializationContext, this, binding.thrownExceptions, scope, FlowInfo.DEAD_END);
59
60       // propagate to statements
61       if (statements != null) {
62         boolean didAlreadyComplain = false;
63         for (int i = 0, count = statements.length; i < count; i++) {
64           Statement stat;
65           if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope, didAlreadyComplain)) {
66             flowInfo = stat.analyseCode(scope, methodContext, flowInfo);
67           } else {
68             didAlreadyComplain = true;
69           }
70         }
71       }
72       // check for missing returning path
73       TypeBinding returnType = binding.returnType;
74       if ((returnType == VoidBinding) || isAbstract()) {
75         this.needFreeReturn = flowInfo.isReachable();
76       } else {
77         if (flowInfo != FlowInfo.DEAD_END) {
78           scope.problemReporter().shouldReturn(returnType, this);
79         }
80       }
81     } catch (AbortMethod e) {
82       this.ignoreFurtherInvestigation = true;
83     }
84   }
85
86   public void parseStatements(UnitParser parser, CompilationUnitDeclaration unit) {
87
88     //fill up the method body with statement
89     if (ignoreFurtherInvestigation)
90       return;
91     parser.parse(this, unit);
92   }
93
94   public void resolveStatements() {
95
96     // ========= abort on fatal error =============
97     if (this.returnType != null && this.binding != null) {
98       this.returnType.resolvedType = this.binding.returnType;
99       // record the return type binding
100     }
101     // look if the name of the method is correct
102     if (binding != null && isTypeUseDeprecated(binding.returnType, scope))
103       scope.problemReporter().deprecatedType(binding.returnType, returnType);
104
105     if (scope != null) {
106       if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector))
107         scope.problemReporter().methodWithConstructorName(this);
108
109       // by grammatical construction, interface methods are always abstract
110       if (!scope.enclosingSourceType().isInterface()) {
111
112         // if a method has an semicolon body and is not declared as abstract==>error
113         // native methods may have a semicolon body 
114         //                      if ((modifiers & AccSemicolonBody) != 0) {
115         //                              if ((modifiers & AccNative) == 0)
116         //                                      if ((modifiers & AccAbstract) == 0)
117         //                                              scope.problemReporter().methodNeedingAbstractModifier(this);
118         //                      } else {
119         //                              // the method HAS a body --> abstract native modifiers are forbiden
120         //                              if (((modifiers & AccNative) != 0) || ((modifiers & AccAbstract) != 0))
121         //                                      scope.problemReporter().methodNeedingNoBody(this);
122         //                      }
123       }
124     }
125     super.resolveStatements();
126   }
127
128   public String returnTypeToString(int tab) {
129
130     if (returnType == null)
131       return ""; //$NON-NLS-1$
132     return returnType.toString(tab) + " "; //$NON-NLS-1$
133   }
134
135   public void traverse(ASTVisitor visitor, ClassScope classScope) {
136
137     if (visitor.visit(this, classScope)) {
138       if (returnType != null)
139         returnType.traverse(visitor, scope);
140       if (arguments != null) {
141         int argumentLength = arguments.length;
142         for (int i = 0; i < argumentLength; i++)
143           arguments[i].traverse(visitor, scope);
144       }
145       if (thrownExceptions != null) {
146         int thrownExceptionsLength = thrownExceptions.length;
147         for (int i = 0; i < thrownExceptionsLength; i++)
148           thrownExceptions[i].traverse(visitor, scope);
149       }
150       if (statements != null) {
151         int statementsLength = statements.length;
152         for (int i = 0; i < statementsLength; i++)
153           statements[i].traverse(visitor, scope);
154       }
155     }
156     visitor.endVisit(this, classScope);
157   }
158 }