added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / MethodDeclaration.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.core.compiler.*;
14 import org.eclipse.jdt.internal.compiler.CompilationResult;
15 import org.eclipse.jdt.internal.compiler.ASTVisitor;
16 import org.eclipse.jdt.internal.compiler.env.IGenericType;
17 import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
18 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
19 import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
20 import org.eclipse.jdt.internal.compiler.lookup.*;
21 import org.eclipse.jdt.internal.compiler.parser.*;
22 import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
23
24 public class MethodDeclaration extends AbstractMethodDeclaration {
25         
26         public TypeReference returnType;
27         public TypeParameter[] typeParameters;
28         
29         /**
30          * MethodDeclaration constructor comment.
31          */
32         public MethodDeclaration(CompilationResult compilationResult) {
33                 super(compilationResult);
34         }
35
36         public void analyseCode(
37                 ClassScope classScope,
38                 InitializationFlowContext initializationContext,
39                 FlowInfo flowInfo) {
40
41                 // starting of the code analysis for methods
42                 if (ignoreFurtherInvestigation)
43                         return;
44                 try {
45                         if (binding == null)
46                                 return;
47                                 
48                         if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
49                                 if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
50                                         scope.problemReporter().unusedPrivateMethod(this);
51                                 }
52                         }
53                                 
54                         // skip enum implicit methods
55                         if (binding.declaringClass.isEnum() && (this.selector == TypeConstants.VALUES || this.selector == TypeConstants.VALUEOF))
56                                 return;
57
58                         // may be in a non necessary <clinit> for innerclass with static final constant fields
59                         if (binding.isAbstract() || binding.isNative())
60                                 return;
61                         
62                         ExceptionHandlingFlowContext methodContext =
63                                 new ExceptionHandlingFlowContext(
64                                         initializationContext,
65                                         this,
66                                         binding.thrownExceptions,
67                                         scope,
68                                         FlowInfo.DEAD_END);
69
70                         // tag parameters as being set
71                         if (this.arguments != null) {
72                                 for (int i = 0, count = this.arguments.length; i < count; i++) {
73                                         flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding);
74                                 }
75                         }
76                         // propagate to statements
77                         if (statements != null) {
78                                 boolean didAlreadyComplain = false;
79                                 for (int i = 0, count = statements.length; i < count; i++) {
80                                         Statement stat = statements[i];
81                                         if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) {
82                                                 flowInfo = stat.analyseCode(scope, methodContext, flowInfo);
83                                         } else {
84                                                 didAlreadyComplain = true;
85                                         }
86                                 }
87                         }
88                         // check for missing returning path
89                         TypeBinding returnTypeBinding = binding.returnType;
90                         if ((returnTypeBinding == VoidBinding) || isAbstract()) {
91                                 this.needFreeReturn = flowInfo.isReachable();
92                         } else {
93                                 if (flowInfo != FlowInfo.DEAD_END) { 
94                                         scope.problemReporter().shouldReturn(returnTypeBinding, this);
95                                 }
96                         }
97                         // check unreachable catch blocks
98                         methodContext.complainIfUnusedExceptionHandlers(this);
99                 } catch (AbortMethod e) {
100                         this.ignoreFurtherInvestigation = true;
101                 }
102         }
103
104         public boolean isMethod() {
105
106                 return true;
107         }
108
109         public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
110
111                 //fill up the method body with statement
112                 if (ignoreFurtherInvestigation)
113                         return;
114                 parser.parse(this, unit);
115         }
116
117         public StringBuffer printReturnType(int indent, StringBuffer output) {
118
119                 if (returnType == null) return output;
120                 return returnType.printExpression(0, output).append(' ');
121         }
122
123         public void resolveStatements() {
124
125                 // ========= abort on fatal error =============
126                 if (this.returnType != null && this.binding != null) {
127                         this.returnType.resolvedType = this.binding.returnType;
128                         // record the return type binding
129                 }
130                 // check if method with constructor name
131                 if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector)) {
132                         scope.problemReporter().methodWithConstructorName(this);
133                 }
134                 
135                 // check @Override annotation
136                 if (this.binding != null 
137                                 && (this.binding.tagBits & TagBits.AnnotationOverride) != 0
138                                 && (this.binding.modifiers & AccOverriding) == 0) {
139                         scope.problemReporter().methodMustOverride(this);
140                 }
141                                 
142                 // by grammatical construction, interface methods are always abstract
143                 switch (scope.referenceType().kind()) {
144                         case IGenericType.ENUM_DECL :
145                                 if (this.selector == TypeConstants.VALUES) break;
146                                 if (this.selector == TypeConstants.VALUEOF) break;
147                         case IGenericType.CLASS_DECL :
148                                 // if a method has an semicolon body and is not declared as abstract==>error
149                                 // native methods may have a semicolon body 
150                                 if ((modifiers & AccSemicolonBody) != 0) {
151                                         if ((modifiers & AccNative) == 0)
152                                                 if ((modifiers & AccAbstract) == 0)
153                                                         scope.problemReporter().methodNeedBody(this);
154                                 } else {
155                                         // the method HAS a body --> abstract native modifiers are forbiden
156                                         if (((modifiers & AccNative) != 0) || ((modifiers & AccAbstract) != 0))
157                                                 scope.problemReporter().methodNeedingNoBody(this);
158                                 }
159                 }
160                 super.resolveStatements(); 
161         }
162
163         public void traverse(
164                 ASTVisitor visitor,
165                 ClassScope classScope) {
166
167                 if (visitor.visit(this, classScope)) {
168                         if (this.annotations != null) {
169                                 int annotationsLength = this.annotations.length;
170                                 for (int i = 0; i < annotationsLength; i++)
171                                         this.annotations[i].traverse(visitor, scope);
172                         }
173                         if (this.typeParameters != null) {
174                                 int typeParametersLength = this.typeParameters.length;
175                                 for (int i = 0; i < typeParametersLength; i++) {
176                                         this.typeParameters[i].traverse(visitor, scope);
177                                 }
178                         }                       
179                         if (returnType != null)
180                                 returnType.traverse(visitor, scope);
181                         if (arguments != null) {
182                                 int argumentLength = arguments.length;
183                                 for (int i = 0; i < argumentLength; i++)
184                                         arguments[i].traverse(visitor, scope);
185                         }
186                         if (thrownExceptions != null) {
187                                 int thrownExceptionsLength = thrownExceptions.length;
188                                 for (int i = 0; i < thrownExceptionsLength; i++)
189                                         thrownExceptions[i].traverse(visitor, scope);
190                         }
191                         if (statements != null) {
192                                 int statementsLength = statements.length;
193                                 for (int i = 0; i < statementsLength; i++)
194                                         statements[i].traverse(visitor, scope);
195                         }
196                 }
197                 visitor.endVisit(this, classScope);
198         }
199         public TypeParameter[] typeParameters() {
200             return this.typeParameters;
201         }               
202 }