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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
23 public abstract class AbstractMethodDeclaration
25 implements ProblemSeverities, ReferenceContext {
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;
34 public int modifiersSourceStart;
35 public Argument[] arguments;
36 public TypeReference[] thrownExceptions;
37 public Statement[] statements;
38 public int explicitDeclarations;
39 public MethodBinding binding;
40 public boolean ignoreFurtherInvestigation = false;
41 public boolean needFreeReturn = false;
43 public Javadoc javadoc;
46 public int bodyEnd = -1;
47 public CompilationResult compilationResult;
49 public boolean errorInSignature = false;
51 AbstractMethodDeclaration(CompilationResult compilationResult){
52 this.compilationResult = compilationResult;
56 * We cause the compilation task to abort to a given extent.
58 public void abort(int abortLevel, IProblem problem) {
61 case AbortCompilation :
62 throw new AbortCompilation(this.compilationResult, problem);
63 case AbortCompilationUnit :
64 throw new AbortCompilationUnit(this.compilationResult, problem);
66 throw new AbortType(this.compilationResult, problem);
68 throw new AbortMethod(this.compilationResult, problem);
72 public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info);
75 * Bind and add argument's binding into the scope of the method
77 public void bindArguments() {
79 if (this.arguments != null) {
80 // by default arguments in abstract/native methods are considered to be used (no complaint is expected)
81 boolean used = this.binding == null || this.binding.isAbstract() || this.binding.isNative();
83 int length = this.arguments.length;
84 for (int i = 0; i < length; i++) {
85 TypeBinding argType = this.binding == null ? null : this.binding.parameters[i];
86 this.arguments[i].bind(this.scope, argType, used);
92 * Record the thrown exception type bindings in the corresponding type references.
94 public void bindThrownExceptions() {
96 if (this.thrownExceptions != null
97 && this.binding != null
98 && this.binding.thrownExceptions != null) {
99 int thrownExceptionLength = this.thrownExceptions.length;
100 int length = this.binding.thrownExceptions.length;
101 if (length == thrownExceptionLength) {
102 for (int i = 0; i < length; i++) {
103 this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
106 int bindingIndex = 0;
107 for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) {
108 TypeReference thrownException = this.thrownExceptions[i];
109 ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
110 char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
111 if (thrownException instanceof SingleTypeReference) {
112 // single type reference
113 int lengthName = bindingCompoundName.length;
114 char[] thrownExceptionTypeName = thrownException.getTypeName()[0];
115 if (CharOperation.equals(thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) {
116 thrownException.resolvedType = thrownExceptionBinding;
120 // qualified type reference
121 if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
122 thrownException.resolvedType = thrownExceptionBinding;
131 public CompilationResult compilationResult() {
133 return this.compilationResult;
137 * Bytecode generation for a method
141 public void generateCode(ClassScope classScope, ClassFile classFile) {
143 int problemResetPC = 0;
144 classFile.codeStream.wideMode = false; // reset wideMode to false
145 if (this.ignoreFurtherInvestigation) {
146 // method is known to have errors, dump a problem method
147 if (this.binding == null)
148 return; // handle methods with invalid signature or duplicates
150 IProblem[] problems =
151 this.scope.referenceCompilationUnit().compilationResult.getProblems();
152 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
153 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
154 classFile.addProblemMethod(this, this.binding, problemsCopy);
157 // regular code generation
159 problemResetPC = classFile.contentsOffset;
160 this.generateCode(classFile);
161 } catch (AbortMethod e) {
162 // a fatal error was detected during code generation, need to restart code gen if possible
163 if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
164 // a branch target required a goto_w, restart code gen in wide mode.
166 classFile.contentsOffset = problemResetPC;
167 classFile.methodCount--;
168 classFile.codeStream.wideMode = true; // request wide mode
169 this.generateCode(classFile); // restart method generation
170 } catch (AbortMethod e2) {
172 IProblem[] problems =
173 this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
174 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
175 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
176 classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC);
179 // produce a problem method accounting for this fatal error
181 IProblem[] problems =
182 this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
183 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
184 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
185 classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC);
190 private void generateCode(ClassFile classFile) {
192 classFile.generateMethodInfoHeader(this.binding);
193 int methodAttributeOffset = classFile.contentsOffset;
194 int attributeNumber = classFile.generateMethodInfoAttribute(this.binding);
195 if ((!this.binding.isNative()) && (!this.binding.isAbstract())) {
196 int codeAttributeOffset = classFile.contentsOffset;
197 classFile.generateCodeAttributeHeader();
198 CodeStream codeStream = classFile.codeStream;
199 codeStream.reset(this, classFile);
200 // initialize local positions
201 this.scope.computeLocalVariablePositions(this.binding.isStatic() ? 0 : 1, codeStream);
203 // arguments initialization for local variable debug attributes
204 if (this.arguments != null) {
205 for (int i = 0, max = this.arguments.length; i < max; i++) {
206 LocalVariableBinding argBinding;
207 codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding);
208 argBinding.recordInitializationStartPC(0);
211 if (this.statements != null) {
212 for (int i = 0, max = this.statements.length; i < max; i++)
213 this.statements[i].generateCode(this.scope, codeStream);
215 if (this.needFreeReturn) {
216 codeStream.return_();
218 // local variable attributes
219 codeStream.exitUserScope(this.scope);
220 codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
221 classFile.completeCodeAttribute(codeAttributeOffset);
224 checkArgumentsSize();
226 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
228 // if a problem got reported during code gen, then trigger problem method creation
229 if (this.ignoreFurtherInvestigation) {
230 throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
234 private void checkArgumentsSize() {
235 TypeBinding[] parameters = this.binding.parameters;
236 int size = 1; // an abstact method or a native method cannot be static
237 for (int i = 0, max = parameters.length; i < max; i++) {
238 TypeBinding parameter = parameters[i];
239 if (parameter == LongBinding || parameter == DoubleBinding) {
245 this.scope.problemReporter().noMoreAvailableSpaceForArgument(this.scope.locals[i], this.scope.locals[i].declaration);
250 public boolean hasErrors() {
251 return this.ignoreFurtherInvestigation;
254 public boolean isAbstract() {
256 if (this.binding != null)
257 return this.binding.isAbstract();
258 return (this.modifiers & AccAbstract) != 0;
261 public boolean isClinit() {
266 public boolean isConstructor() {
271 public boolean isDefaultConstructor() {
276 public boolean isInitializationMethod() {
281 public boolean isNative() {
283 if (this.binding != null)
284 return this.binding.isNative();
285 return (this.modifiers & AccNative) != 0;
288 public boolean isStatic() {
290 if (this.binding != null)
291 return this.binding.isStatic();
292 return (this.modifiers & AccStatic) != 0;
296 * Fill up the method body with statement
300 public abstract void parseStatements(
302 CompilationUnitDeclaration unit);
304 public StringBuffer print(int tab, StringBuffer output) {
306 printIndent(tab, output);
307 printModifiers(this.modifiers, output);
308 printReturnType(0, output).append(this.selector).append('(');
309 if (this.arguments != null) {
310 for (int i = 0; i < this.arguments.length; i++) {
311 if (i > 0) output.append(", "); //$NON-NLS-1$
312 this.arguments[i].print(0, output);
316 if (this.thrownExceptions != null) {
317 output.append(" throws "); //$NON-NLS-1$
318 for (int i = 0; i < this.thrownExceptions.length; i++) {
319 if (i > 0) output.append(", "); //$NON-NLS-1$
320 this.thrownExceptions[i].print(0, output);
323 printBody(tab + 1, output);
327 public StringBuffer printBody(int indent, StringBuffer output) {
329 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
330 return output.append(';');
332 output.append(" {"); //$NON-NLS-1$
333 if (this.statements != null) {
334 for (int i = 0; i < this.statements.length; i++) {
336 this.statements[i].printStatement(indent, output);
339 output.append('\n'); //$NON-NLS-1$
340 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
344 public StringBuffer printReturnType(int indent, StringBuffer output) {
349 public void resolve(ClassScope upperScope) {
351 if (this.binding == null) {
352 this.ignoreFurtherInvestigation = true;
357 bindThrownExceptions();
360 } catch (AbortMethod e) { // ========= abort on fatal error =============
361 this.ignoreFurtherInvestigation = true;
365 public void resolveJavadoc() {
367 if (this.binding == null) return;
368 if (this.javadoc != null) {
369 this.javadoc.resolve(this.scope);
372 if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
373 this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
377 public void resolveStatements() {
379 if (this.statements != null) {
380 for (int i = 0, length = this.statements.length; i < length; i++) {
381 this.statements[i].resolve(this.scope);
383 } else if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
384 this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1);
388 public void tagAsHavingErrors() {
390 this.ignoreFurtherInvestigation = true;
393 public void traverse(
395 ClassScope classScope) {
396 // default implementation: subclass will define it