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 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;
44 public Javadoc javadoc;
47 public int bodyEnd = -1;
48 public CompilationResult compilationResult;
50 public boolean errorInSignature = false;
52 AbstractMethodDeclaration(CompilationResult compilationResult){
53 this.compilationResult = compilationResult;
57 * We cause the compilation task to abort to a given extent.
59 public void abort(int abortLevel, IProblem problem) {
62 case AbortCompilation :
63 throw new AbortCompilation(this.compilationResult, problem);
64 case AbortCompilationUnit :
65 throw new AbortCompilationUnit(this.compilationResult, problem);
67 throw new AbortType(this.compilationResult, problem);
69 throw new AbortMethod(this.compilationResult, problem);
73 public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info);
76 * Bind and add argument's binding into the scope of the method
78 public void bindArguments() {
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();
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;
97 * Record the thrown exception type bindings in the corresponding type references.
99 public void bindThrownExceptions() {
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];
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;
125 // qualified type reference
126 if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
127 thrownException.resolvedType = thrownExceptionBinding;
136 public CompilationResult compilationResult() {
138 return this.compilationResult;
142 * Bytecode generation for a method
146 public void generateCode(ClassScope classScope, ClassFile classFile) {
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
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);
162 // regular code generation
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.
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) {
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);
184 // produce a problem method accounting for this fatal error
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);
195 public void generateCode(ClassFile classFile) {
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);
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);
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);
220 if (this.needFreeReturn) {
221 codeStream.return_();
223 // local variable attributes
224 codeStream.exitUserScope(this.scope);
225 codeStream.recordPositionsFrom(0, this.declarationSourceEnd);
226 classFile.completeCodeAttribute(codeAttributeOffset);
229 checkArgumentsSize();
231 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
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);
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) {
250 this.scope.problemReporter().noMoreAvailableSpaceForArgument(this.scope.locals[i], this.scope.locals[i].declaration);
255 public boolean hasErrors() {
256 return this.ignoreFurtherInvestigation;
259 public boolean isAbstract() {
261 if (this.binding != null)
262 return this.binding.isAbstract();
263 return (this.modifiers & AccAbstract) != 0;
266 public boolean isAnnotationMethod() {
271 public boolean isClinit() {
276 public boolean isConstructor() {
281 public boolean isDefaultConstructor() {
286 public boolean isInitializationMethod() {
291 public boolean isMethod() {
296 public boolean isNative() {
298 if (this.binding != null)
299 return this.binding.isNative();
300 return (this.modifiers & AccNative) != 0;
303 public boolean isStatic() {
305 if (this.binding != null)
306 return this.binding.isStatic();
307 return (this.modifiers & AccStatic) != 0;
311 * Fill up the method body with statement
315 public abstract void parseStatements(
317 CompilationUnitDeclaration unit);
319 public StringBuffer print(int tab, StringBuffer output) {
321 printIndent(tab, output);
322 printModifiers(this.modifiers, output);
323 if (this.annotations != null) printAnnotations(this.annotations, output);
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$
333 typeParams[max].print(0, output);
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);
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);
352 printBody(tab + 1, output);
356 public StringBuffer printBody(int indent, StringBuffer output) {
358 if (isAbstract() || (this.modifiers & AccSemicolonBody) != 0)
359 return output.append(';');
361 output.append(" {"); //$NON-NLS-1$
362 if (this.statements != null) {
363 for (int i = 0; i < this.statements.length; i++) {
365 this.statements[i].printStatement(indent, output);
368 output.append('\n'); //$NON-NLS-1$
369 printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
373 public StringBuffer printReturnType(int indent, StringBuffer output) {
378 public void resolve(ClassScope upperScope) {
380 if (this.binding == null) {
381 this.ignoreFurtherInvestigation = true;
386 bindThrownExceptions();
388 resolveAnnotations(scope, this.annotations, this.binding);
390 } catch (AbortMethod e) { // ========= abort on fatal error =============
391 this.ignoreFurtherInvestigation = true;
395 public void resolveJavadoc() {
397 if (this.binding == null) return;
398 if (this.javadoc != null) {
399 this.javadoc.resolve(this.scope);
402 if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
403 this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
407 public void resolveStatements() {
409 if (this.statements != null) {
410 for (int i = 0, length = this.statements.length; i < length; i++) {
411 this.statements[i].resolve(this.scope);
413 } else if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
414 this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1);
418 public void tagAsHavingErrors() {
420 this.ignoreFurtherInvestigation = true;
423 public void traverse(
425 ClassScope classScope) {
426 // default implementation: subclass will define it
429 public TypeParameter[] typeParameters() {