added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / AbstractMethodDeclaration.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.*;
15 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
16 import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
17 import org.eclipse.jdt.internal.compiler.impl.*;
18 import org.eclipse.jdt.internal.compiler.codegen.*;
19 import org.eclipse.jdt.internal.compiler.lookup.*;
20 import org.eclipse.jdt.internal.compiler.problem.*;
21 import org.eclipse.jdt.internal.compiler.parser.*;
22
23 public abstract class AbstractMethodDeclaration
24         extends ASTNode
25         implements ProblemSeverities, ReferenceContext {
26                 
27         public MethodScope scope;
28         //it is not relevent for constructor but it helps to have the name of the constructor here 
29         //which is always the name of the class.....parsing do extra work to fill it up while it do not have to....
30         public char[] selector;
31         public int declarationSourceStart;
32         public int declarationSourceEnd;
33         public int modifiers;
34         public int modifiersSourceStart;
35         public Annotation[] annotations;
36         public Argument[] arguments;
37         public TypeReference[] thrownExceptions;
38         public Statement[] statements;
39         public int explicitDeclarations;
40         public MethodBinding binding;
41         public boolean ignoreFurtherInvestigation = false;
42         public boolean needFreeReturn = false;
43         
44         public Javadoc javadoc;
45         
46         public int bodyStart;
47         public int bodyEnd = -1;
48         public CompilationResult compilationResult;
49         
50         public boolean errorInSignature = false; 
51         
52         AbstractMethodDeclaration(CompilationResult compilationResult){
53                 this.compilationResult = compilationResult;
54         }
55         
56         /*
57          *      We cause the compilation task to abort to a given extent.
58          */
59         public void abort(int abortLevel, IProblem problem) {
60
61                 switch (abortLevel) {
62                         case AbortCompilation :
63                                 throw new AbortCompilation(this.compilationResult, problem);
64                         case AbortCompilationUnit :
65                                 throw new AbortCompilationUnit(this.compilationResult, problem);
66                         case AbortType :
67                                 throw new AbortType(this.compilationResult, problem);
68                         default :
69                                 throw new AbortMethod(this.compilationResult, problem);
70                 }
71         }
72
73         public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info);
74
75                 /**
76          * Bind and add argument's binding into the scope of the method
77          */
78         public void bindArguments() {
79
80                 if (this.arguments != null) {
81                         // by default arguments in abstract/native methods are considered to be used (no complaint is expected)
82                         boolean used = this.binding == null || this.binding.isAbstract() || this.binding.isNative();
83
84                         int length = this.arguments.length;
85                         for (int i = 0; i < length; i++) {
86                                 TypeBinding argType = this.binding == null ? null : this.binding.parameters[i];
87                                 Argument argument = this.arguments[i];
88                                 argument.bind(this.scope, argType, used);
89                                 if (argument.annotations != null) {
90                                         this.binding.tagBits |= TagBits.HasParameterAnnotations;
91                                 }
92                         }
93                 }
94         }
95
96         /**
97          * Record the thrown exception type bindings in the corresponding type references.
98          */
99         public void bindThrownExceptions() {
100
101                 if (this.thrownExceptions != null
102                         && this.binding != null
103                         && this.binding.thrownExceptions != null) {
104                         int thrownExceptionLength = this.thrownExceptions.length;
105                         int length = this.binding.thrownExceptions.length;
106                         if (length == thrownExceptionLength) {
107                                 for (int i = 0; i < length; i++) {
108                                         this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
109                                 }
110                         } else {
111                                 int bindingIndex = 0;
112                                 for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) {
113                                         TypeReference thrownException = this.thrownExceptions[i];
114                                         ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
115                                         char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
116                                         if (thrownException instanceof SingleTypeReference) {
117                                                 // single type reference
118                                                 int lengthName = bindingCompoundName.length;
119                                                 char[] thrownExceptionTypeName = thrownException.getTypeName()[0];
120                                                 if (CharOperation.equals(thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) {
121                                                         thrownException.resolvedType = thrownExceptionBinding;
122                                                         bindingIndex++;
123                                                 }
124                                         } else {
125                                                 // qualified type reference
126                                                 if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
127                                                         thrownException.resolvedType = thrownExceptionBinding;
128                                                         bindingIndex++;
129                                                 }                                               
130                                         }
131                                 }
132                         }
133                 }
134         }
135
136         public CompilationResult compilationResult() {
137                 
138                 return this.compilationResult;
139         }
140         
141         /**
142          * Bytecode generation for a method
143          * @param classScope
144          * @param classFile
145          */
146         public void generateCode(ClassScope classScope, ClassFile classFile) {
147                 
148                 int problemResetPC = 0;
149                 classFile.codeStream.wideMode = false; // reset wideMode to false
150                 if (this.ignoreFurtherInvestigation) {
151                         // method is known to have errors, dump a problem method
152                         if (this.binding == null)
153                                 return; // handle methods with invalid signature or duplicates
154                         int problemsLength;
155                         IProblem[] problems =
156                                 this.scope.referenceCompilationUnit().compilationResult.getProblems();
157                         IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
158                         System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
159                         classFile.addProblemMethod(this, this.binding, problemsCopy);
160                         return;
161                 }
162                 // regular code generation
163                 try {
164                         problemResetPC = classFile.contentsOffset;
165                         this.generateCode(classFile);
166                 } catch (AbortMethod e) {
167                         // a fatal error was detected during code generation, need to restart code gen if possible
168                         if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
169                                 // a branch target required a goto_w, restart code gen in wide mode.
170                                 try {
171                                         classFile.contentsOffset = problemResetPC;
172                                         classFile.methodCount--;
173                                         classFile.codeStream.wideMode = true; // request wide mode 
174                                         this.generateCode(classFile); // restart method generation
175                                 } catch (AbortMethod e2) {
176                                         int problemsLength;
177                                         IProblem[] problems =
178                                                 this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
179                                         IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
180                                         System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
181                                         classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC);
182                                 }
183                         } else {
184                                 // produce a problem method accounting for this fatal error
185                                 int problemsLength;
186                                 IProblem[] problems =
187                                         this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
188                                 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
189                                 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
190                                 classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC);
191                         }
192                 }
193         }
194
195         public void generateCode(ClassFile classFile) {
196
197                 classFile.generateMethodInfoHeader(this.binding);
198                 int methodAttributeOffset = classFile.contentsOffset;
199                 int attributeNumber = classFile.generateMethodInfoAttribute(this.binding);
200                 if ((!this.binding.isNative()) && (!this.binding.isAbstract())) {
201                         int codeAttributeOffset = classFile.contentsOffset;
202                         classFile.generateCodeAttributeHeader();
203                         CodeStream codeStream = classFile.codeStream;
204                         codeStream.reset(this, classFile);
205                         // initialize local positions
206                         this.scope.computeLocalVariablePositions(this.binding.isStatic() ? 0 : 1, codeStream);
207
208                         // arguments initialization for local variable debug attributes
209                         if (this.arguments != null) {
210                                 for (int i = 0, max = this.arguments.length; i < max; i++) {
211                                         LocalVariableBinding argBinding;
212                                         codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding);
213                                         argBinding.recordInitializationStartPC(0);
214                                 }
215                         }
216                         if (this.statements != null) {
217                                 for (int i = 0, max = this.statements.length; i < max; i++)
218                                         this.statements[i].generateCode(this.scope, codeStream);
219                         }
220                         if (this.needFreeReturn) {
221                                 codeStream.return_();
222                         }
223                         // local variable attributes
224                         codeStream.exitUserScope(this.scope);
225                         codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
226                         classFile.completeCodeAttribute(codeAttributeOffset);
227                         attributeNumber++;
228                 } else {
229                         checkArgumentsSize();
230                 }
231                 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
232
233                 // if a problem got reported during code gen, then trigger problem method creation
234                 if (this.ignoreFurtherInvestigation) {
235                         throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
236                 }
237         }
238
239         private void checkArgumentsSize() {
240                 TypeBinding[] parameters = this.binding.parameters;
241                 int size = 1; // an abstact method or a native method cannot be static
242                 for (int i = 0, max = parameters.length; i < max; i++) {
243                         TypeBinding parameter = parameters[i];
244                         if (parameter == LongBinding || parameter == DoubleBinding) {
245                                 size += 2;
246                         } else {
247                                 size++;
248                         }
249                         if (size > 0xFF) {
250                                 this.scope.problemReporter().noMoreAvailableSpaceForArgument(this.scope.locals[i], this.scope.locals[i].declaration);
251                         }
252                 }
253         }
254         
255         public boolean hasErrors() {
256                 return this.ignoreFurtherInvestigation;
257         }
258
259         public boolean isAbstract() {
260
261                 if (this.binding != null)
262                         return this.binding.isAbstract();
263                 return (this.modifiers & AccAbstract) != 0;
264         }
265
266         public boolean isAnnotationMethod() {
267
268                 return false;
269         }
270         
271         public boolean isClinit() {
272
273                 return false;
274         }
275
276         public boolean isConstructor() {
277
278                 return false;
279         }
280
281         public boolean isDefaultConstructor() {
282
283                 return false;
284         }
285
286         public boolean isInitializationMethod() {
287
288                 return false;
289         }
290
291         public boolean isMethod() {
292
293                 return false;
294         }
295
296         public boolean isNative() {
297
298                 if (this.binding != null)
299                         return this.binding.isNative();
300                 return (this.modifiers & AccNative) != 0;
301         }
302
303         public boolean isStatic() {
304
305                 if (this.binding != null)
306                         return this.binding.isStatic();
307                 return (this.modifiers & AccStatic) != 0;
308         }
309
310         /**
311          * Fill up the method body with statement
312          * @param parser
313          * @param unit
314          */
315         public abstract void parseStatements(
316                 Parser parser,
317                 CompilationUnitDeclaration unit);
318
319         public StringBuffer print(int tab, StringBuffer output) {
320
321                 printIndent(tab, output);
322                 printModifiers(this.modifiers, output);
323                 if (this.annotations != null) printAnnotations(this.annotations, output);
324                 
325                 TypeParameter[] typeParams = typeParameters();
326                 if (typeParams != null) {
327                         output.append('<');//$NON-NLS-1$
328                         int max = typeParams.length - 1;
329                         for (int j = 0; j < max; j++) {
330                                 typeParams[j].print(0, output);
331                                 output.append(", ");//$NON-NLS-1$
332                         }
333                         typeParams[max].print(0, output);
334                         output.append('>');
335                 }
336                 
337                 printReturnType(0, output).append(this.selector).append('(');
338                 if (this.arguments != null) {
339                         for (int i = 0; i < this.arguments.length; i++) {
340                                 if (i > 0) output.append(", "); //$NON-NLS-1$
341                                 this.arguments[i].print(0, output);
342                         }
343                 }
344                 output.append(')');
345                 if (this.thrownExceptions != null) {
346                         output.append(" throws "); //$NON-NLS-1$
347                         for (int i = 0; i < this.thrownExceptions.length; i++) {
348                                 if (i > 0) output.append(", "); //$NON-NLS-1$
349                                 this.thrownExceptions[i].print(0, output);
350                         }
351                 }
352                 printBody(tab + 1, output);
353                 return output;
354         }
355
356         public StringBuffer printBody(int indent, StringBuffer output) {
357
358                 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0) 
359                         return output.append(';');
360
361                 output.append(" {"); //$NON-NLS-1$
362                 if (this.statements != null) {
363                         for (int i = 0; i < this.statements.length; i++) {
364                                 output.append('\n');
365                                 this.statements[i].printStatement(indent, output); 
366                         }
367                 }
368                 output.append('\n'); //$NON-NLS-1$
369                 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
370                 return output;
371         }
372
373         public StringBuffer printReturnType(int indent, StringBuffer output) {
374                 
375                 return output;
376         }
377
378         public void resolve(ClassScope upperScope) {
379
380                 if (this.binding == null) {
381                         this.ignoreFurtherInvestigation = true;
382                 }
383
384                 try {
385                         bindArguments(); 
386                         bindThrownExceptions();
387                         resolveJavadoc();
388                         resolveAnnotations(scope, this.annotations, this.binding);
389                         resolveStatements();
390                 } catch (AbortMethod e) {       // ========= abort on fatal error =============
391                         this.ignoreFurtherInvestigation = true;
392                 } 
393         }
394
395         public void resolveJavadoc() {
396                 
397                 if (this.binding == null) return;
398                 if (this.javadoc != null) {
399                         this.javadoc.resolve(this.scope);
400                         return;
401                 }
402                 if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
403                         this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
404                 }
405         }
406
407         public void resolveStatements() {
408
409                 if (this.statements != null) {
410                         for (int i = 0, length = this.statements.length; i < length; i++) {
411                                 this.statements[i].resolve(this.scope);
412                         }
413                 } else if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
414                         this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1);
415                 }
416         }
417
418         public void tagAsHavingErrors() {
419
420                 this.ignoreFurtherInvestigation = true;
421         }
422
423         public void traverse(
424                 ASTVisitor visitor,
425                 ClassScope classScope) {
426                 // default implementation: subclass will define it
427         }
428         
429         public TypeParameter[] typeParameters() {
430             return null;
431         }
432 }