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