001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.ASTVisitor;
014: import org.eclipse.jdt.internal.compiler.CompilationResult;
015: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
016: import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
017: import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
018: import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
019: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
020: import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
021: import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
022: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
023: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
024: import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
025: import org.eclipse.jdt.internal.compiler.parser.Parser;
026: import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
027: import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
028:
029: public class MethodDeclaration extends AbstractMethodDeclaration {
030:
031: public TypeReference returnType;
032: public TypeParameter[] typeParameters;
033:
034: /**
035: * MethodDeclaration constructor comment.
036: */
037: public MethodDeclaration(CompilationResult compilationResult) {
038: super (compilationResult);
039: }
040:
041: public void analyseCode(ClassScope classScope,
042: InitializationFlowContext initializationContext,
043: FlowInfo flowInfo) {
044:
045: // starting of the code analysis for methods
046: if (ignoreFurtherInvestigation)
047: return;
048: try {
049: if (binding == null)
050: return;
051:
052: if (!this .binding.isUsed()
053: && (this .binding.isPrivate() || (((this .binding.modifiers & (ExtraCompilerModifiers.AccOverriding | ExtraCompilerModifiers.AccImplementing)) == 0) && this .binding.declaringClass
054: .isLocalType()))) {
055: if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
056: scope.problemReporter().unusedPrivateMethod(this );
057: }
058: }
059:
060: // skip enum implicit methods
061: if (binding.declaringClass.isEnum()
062: && (this .selector == TypeConstants.VALUES || this .selector == TypeConstants.VALUEOF))
063: return;
064:
065: // may be in a non necessary <clinit> for innerclass with static final constant fields
066: if (binding.isAbstract() || binding.isNative())
067: return;
068:
069: ExceptionHandlingFlowContext methodContext = new ExceptionHandlingFlowContext(
070: initializationContext, this ,
071: binding.thrownExceptions, scope, FlowInfo.DEAD_END);
072:
073: // tag parameters as being set
074: if (this .arguments != null) {
075: for (int i = 0, count = this .arguments.length; i < count; i++) {
076: flowInfo
077: .markAsDefinitelyAssigned(this .arguments[i].binding);
078: }
079: }
080: // propagate to statements
081: if (statements != null) {
082: boolean didAlreadyComplain = false;
083: for (int i = 0, count = statements.length; i < count; i++) {
084: Statement stat = statements[i];
085: if (!stat.complainIfUnreachable(flowInfo, scope,
086: didAlreadyComplain)) {
087: flowInfo = stat.analyseCode(scope,
088: methodContext, flowInfo);
089: } else {
090: didAlreadyComplain = true;
091: }
092: }
093: }
094: // check for missing returning path
095: TypeBinding returnTypeBinding = binding.returnType;
096: if ((returnTypeBinding == TypeBinding.VOID) || isAbstract()) {
097: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
098: this .bits |= ASTNode.NeedFreeReturn;
099: }
100: } else {
101: if (flowInfo != FlowInfo.DEAD_END) {
102: scope.problemReporter().shouldReturn(
103: returnTypeBinding, this );
104: }
105: }
106: // check unreachable catch blocks
107: methodContext.complainIfUnusedExceptionHandlers(this );
108: } catch (AbortMethod e) {
109: this .ignoreFurtherInvestigation = true;
110: }
111: }
112:
113: public boolean isMethod() {
114:
115: return true;
116: }
117:
118: public void parseStatements(Parser parser,
119: CompilationUnitDeclaration unit) {
120:
121: //fill up the method body with statement
122: if (ignoreFurtherInvestigation)
123: return;
124: parser.parse(this , unit);
125: }
126:
127: public StringBuffer printReturnType(int indent, StringBuffer output) {
128:
129: if (returnType == null)
130: return output;
131: return returnType.printExpression(0, output).append(' ');
132: }
133:
134: public void resolveStatements() {
135:
136: // ========= abort on fatal error =============
137: if (this .returnType != null && this .binding != null) {
138: this .returnType.resolvedType = this .binding.returnType;
139: // record the return type binding
140: }
141: // check if method with constructor name
142: if (CharOperation.equals(
143: this .scope.enclosingSourceType().sourceName, selector)) {
144: this .scope.problemReporter()
145: .methodWithConstructorName(this );
146: }
147:
148: if (this .typeParameters != null) {
149: for (int i = 0, length = this .typeParameters.length; i < length; i++) {
150: this .typeParameters[i].resolve(this .scope);
151: }
152: }
153:
154: // check @Override annotation
155: final CompilerOptions compilerOptions = this .scope
156: .compilerOptions();
157: checkOverride: {
158: if (this .binding == null)
159: break checkOverride;
160: long sourceLevel = compilerOptions.sourceLevel;
161: if (sourceLevel < ClassFileConstants.JDK1_5)
162: break checkOverride;
163: int bindingModifiers = this .binding.modifiers;
164: boolean hasOverrideAnnotation = (this .binding.tagBits & TagBits.AnnotationOverride) != 0;
165: boolean isInterfaceMethod = this .binding.declaringClass
166: .isInterface();
167: if (hasOverrideAnnotation) {
168: // no static method is considered overriding
169: if (!isInterfaceMethod
170: && (bindingModifiers & (ClassFileConstants.AccStatic | ExtraCompilerModifiers.AccOverriding)) == ExtraCompilerModifiers.AccOverriding)
171: break checkOverride;
172: // in 1.5, strictly for overriding superclass method
173: // in 1.6 and above, also tolerate implementing interface method
174: if (sourceLevel >= ClassFileConstants.JDK1_6
175: && ((bindingModifiers & (ClassFileConstants.AccStatic | ExtraCompilerModifiers.AccImplementing)) == ExtraCompilerModifiers.AccImplementing))
176: break checkOverride;
177: // claims to override, and doesn't actually do so
178: this .scope.problemReporter().methodMustOverride(this );
179: } else if (!isInterfaceMethod
180: && (bindingModifiers & (ClassFileConstants.AccStatic | ExtraCompilerModifiers.AccOverriding)) == ExtraCompilerModifiers.AccOverriding) {
181: // actually overrides, but did not claim to do so
182: this .scope.problemReporter().missingOverrideAnnotation(
183: this );
184: }
185: }
186:
187: // by grammatical construction, interface methods are always abstract
188: switch (TypeDeclaration
189: .kind(this .scope.referenceType().modifiers)) {
190: case TypeDeclaration.ENUM_DECL:
191: if (this .selector == TypeConstants.VALUES)
192: break;
193: if (this .selector == TypeConstants.VALUEOF)
194: break;
195: case TypeDeclaration.CLASS_DECL:
196: // if a method has an semicolon body and is not declared as abstract==>error
197: // native methods may have a semicolon body
198: if ((this .modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
199: if ((this .modifiers & ClassFileConstants.AccNative) == 0)
200: if ((this .modifiers & ClassFileConstants.AccAbstract) == 0)
201: this .scope.problemReporter().methodNeedBody(
202: this );
203: } else {
204: // the method HAS a body --> abstract native modifiers are forbiden
205: if (((this .modifiers & ClassFileConstants.AccNative) != 0)
206: || ((this .modifiers & ClassFileConstants.AccAbstract) != 0))
207: this .scope.problemReporter().methodNeedingNoBody(
208: this );
209: }
210: }
211: super .resolveStatements();
212:
213: // TagBits.OverridingMethodWithSupercall is set during the resolveStatements() call
214: if (compilerOptions
215: .getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) {
216: if (this .binding != null) {
217: int bindingModifiers = this .binding.modifiers;
218: if ((bindingModifiers & (ExtraCompilerModifiers.AccOverriding | ExtraCompilerModifiers.AccImplementing)) == ExtraCompilerModifiers.AccOverriding
219: && (this .bits & ASTNode.OverridingMethodWithSupercall) == 0) {
220: this .scope.problemReporter()
221: .overridesMethodWithoutSuperInvocation(
222: this .binding);
223: }
224: }
225: }
226: }
227:
228: public void traverse(ASTVisitor visitor, ClassScope classScope) {
229:
230: if (visitor.visit(this , classScope)) {
231: if (this .javadoc != null) {
232: this .javadoc.traverse(visitor, scope);
233: }
234: if (this .annotations != null) {
235: int annotationsLength = this .annotations.length;
236: for (int i = 0; i < annotationsLength; i++)
237: this .annotations[i].traverse(visitor, scope);
238: }
239: if (this .typeParameters != null) {
240: int typeParametersLength = this .typeParameters.length;
241: for (int i = 0; i < typeParametersLength; i++) {
242: this .typeParameters[i].traverse(visitor, scope);
243: }
244: }
245: if (returnType != null)
246: returnType.traverse(visitor, scope);
247: if (arguments != null) {
248: int argumentLength = arguments.length;
249: for (int i = 0; i < argumentLength; i++)
250: arguments[i].traverse(visitor, scope);
251: }
252: if (thrownExceptions != null) {
253: int thrownExceptionsLength = thrownExceptions.length;
254: for (int i = 0; i < thrownExceptionsLength; i++)
255: thrownExceptions[i].traverse(visitor, scope);
256: }
257: if (statements != null) {
258: int statementsLength = statements.length;
259: for (int i = 0; i < statementsLength; i++)
260: statements[i].traverse(visitor, scope);
261: }
262: }
263: visitor.endVisit(this , classScope);
264: }
265:
266: public TypeParameter[] typeParameters() {
267: return this.typeParameters;
268: }
269: }
|