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.impl.Constant;
015: import org.eclipse.jdt.internal.compiler.lookup.*;
016:
017: public class JavadocMessageSend extends MessageSend {
018:
019: public int tagSourceStart, tagSourceEnd;
020: public int tagValue;
021:
022: public JavadocMessageSend(char[] name, long pos) {
023: this .selector = name;
024: this .nameSourcePosition = pos;
025: this .sourceStart = (int) (this .nameSourcePosition >>> 32);
026: this .sourceEnd = (int) this .nameSourcePosition;
027: this .bits |= InsideJavadoc;
028: }
029:
030: public JavadocMessageSend(char[] name, long pos,
031: JavadocArgumentExpression[] arguments) {
032: this (name, pos);
033: this .arguments = arguments;
034: }
035:
036: /*
037: * Resolves type on a Block or Class scope.
038: */
039: private TypeBinding internalResolveType(Scope scope) {
040: // Answer the signature return type
041: // Base type promotion
042: this .constant = Constant.NotAConstant;
043: if (this .receiver == null) {
044: this .actualReceiverType = scope.enclosingSourceType();
045: } else if (scope.kind == Scope.CLASS_SCOPE) {
046: this .actualReceiverType = this .receiver
047: .resolveType((ClassScope) scope);
048: } else {
049: this .actualReceiverType = this .receiver
050: .resolveType((BlockScope) scope);
051: }
052:
053: // will check for null after args are resolved
054:
055: TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
056: boolean hasArgsTypeVar = false;
057: if (this .arguments != null) {
058: boolean argHasError = false; // typeChecks all arguments
059: int length = this .arguments.length;
060: argumentTypes = new TypeBinding[length];
061: for (int i = 0; i < length; i++) {
062: Expression argument = this .arguments[i];
063: if (scope.kind == Scope.CLASS_SCOPE) {
064: argumentTypes[i] = argument
065: .resolveType((ClassScope) scope);
066: } else {
067: argumentTypes[i] = argument
068: .resolveType((BlockScope) scope);
069: }
070: if (argumentTypes[i] == null) {
071: argHasError = true;
072: } else if (!hasArgsTypeVar) {
073: hasArgsTypeVar = argumentTypes[i].isTypeVariable();
074: }
075: }
076: if (argHasError) {
077: return null;
078: }
079: }
080:
081: // check receiver type
082: if (this .actualReceiverType == null) {
083: return null;
084: }
085: this .actualReceiverType = scope.environment().convertToRawType(
086: this .receiver.resolvedType);
087: SourceTypeBinding enclosingType = scope.enclosingSourceType();
088: if (enclosingType == null ? false : enclosingType
089: .isCompatibleWith(this .actualReceiverType)) {
090: this .bits |= ASTNode.SuperAccess;
091: }
092:
093: // base type cannot receive any message
094: if (this .actualReceiverType.isBaseType()) {
095: scope.problemReporter().javadocErrorNoMethodFor(this ,
096: this .actualReceiverType, argumentTypes,
097: scope.getDeclarationModifiers());
098: return null;
099: }
100: this .binding = scope.getMethod(this .actualReceiverType,
101: this .selector, argumentTypes, this );
102: if (!this .binding.isValidBinding()) {
103: // Try method in enclosing types
104: TypeBinding enclosingTypeBinding = this .actualReceiverType;
105: MethodBinding methodBinding = this .binding;
106: while (!methodBinding.isValidBinding()
107: && (enclosingTypeBinding.isMemberType() || enclosingTypeBinding
108: .isLocalType())) {
109: enclosingTypeBinding = enclosingTypeBinding
110: .enclosingType();
111: methodBinding = scope.getMethod(enclosingTypeBinding,
112: this .selector, argumentTypes, this );
113: }
114: if (methodBinding.isValidBinding()) {
115: this .binding = methodBinding;
116: } else {
117: // Try to search a constructor instead
118: enclosingTypeBinding = this .actualReceiverType;
119: MethodBinding contructorBinding = this .binding;
120: while (!contructorBinding.isValidBinding()
121: && (enclosingTypeBinding.isMemberType() || enclosingTypeBinding
122: .isLocalType())) {
123: enclosingTypeBinding = enclosingTypeBinding
124: .enclosingType();
125: if (CharOperation.equals(this .selector,
126: enclosingTypeBinding.shortReadableName())) {
127: contructorBinding = scope
128: .getConstructor(
129: (ReferenceBinding) enclosingTypeBinding,
130: argumentTypes, this );
131: }
132: }
133: if (contructorBinding.isValidBinding()) {
134: this .binding = contructorBinding;
135: }
136: }
137: }
138: if (!this .binding.isValidBinding()) {
139: // implicit lookup may discover issues due to static/constructor contexts. javadoc must be resilient
140: switch (this .binding.problemId()) {
141: case ProblemReasons.NonStaticReferenceInConstructorInvocation:
142: case ProblemReasons.NonStaticReferenceInStaticContext:
143: case ProblemReasons.InheritedNameHidesEnclosingName:
144: case ProblemReasons.Ambiguous:
145: MethodBinding closestMatch = ((ProblemMethodBinding) this .binding).closestMatch;
146: if (closestMatch != null) {
147: this .binding = closestMatch; // ignore problem if can reach target method through it
148: }
149: }
150: }
151: if (!this .binding.isValidBinding()) {
152: if (this .binding.declaringClass == null) {
153: if (this .actualReceiverType instanceof ReferenceBinding) {
154: this .binding.declaringClass = (ReferenceBinding) this .actualReceiverType;
155: } else {
156: scope.problemReporter().javadocErrorNoMethodFor(
157: this , this .actualReceiverType,
158: argumentTypes,
159: scope.getDeclarationModifiers());
160: return null;
161: }
162: }
163: scope.problemReporter().javadocInvalidMethod(this ,
164: this .binding, scope.getDeclarationModifiers());
165: // record the closest match, for clients who may still need hint about possible method match
166: if (this .binding instanceof ProblemMethodBinding) {
167: MethodBinding closestMatch = ((ProblemMethodBinding) this .binding).closestMatch;
168: if (closestMatch != null)
169: this .binding = closestMatch;
170: }
171: return this .resolvedType = this .binding == null ? null
172: : this .binding.returnType;
173: } else if (hasArgsTypeVar) {
174: MethodBinding problem = new ProblemMethodBinding(
175: this .binding, this .selector, argumentTypes,
176: ProblemReasons.NotFound);
177: scope.problemReporter().javadocInvalidMethod(this , problem,
178: scope.getDeclarationModifiers());
179: } else if (binding.isVarargs()) {
180: int length = argumentTypes.length;
181: if (!(binding.parameters.length == length && argumentTypes[length - 1]
182: .isArrayType())) {
183: MethodBinding problem = new ProblemMethodBinding(
184: this .binding, this .selector, argumentTypes,
185: ProblemReasons.NotFound);
186: scope.problemReporter().javadocInvalidMethod(this ,
187: problem, scope.getDeclarationModifiers());
188: }
189: } else {
190: int length = argumentTypes.length;
191: for (int i = 0; i < length; i++) {
192: if (this .binding.parameters[i].erasure() != argumentTypes[i]
193: .erasure()) {
194: MethodBinding problem = new ProblemMethodBinding(
195: this .binding, this .selector, argumentTypes,
196: ProblemReasons.NotFound);
197: scope.problemReporter().javadocInvalidMethod(this ,
198: problem, scope.getDeclarationModifiers());
199: break;
200: }
201: }
202: }
203: if (isMethodUseDeprecated(this .binding, scope, true)) {
204: scope.problemReporter()
205: .javadocDeprecatedMethod(this .binding, this ,
206: scope.getDeclarationModifiers());
207: }
208:
209: return this .resolvedType = this .binding.returnType;
210: }
211:
212: /* (non-Javadoc)
213: * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess()
214: */
215: public boolean isSuperAccess() {
216: return (this .bits & ASTNode.SuperAccess) != 0;
217: }
218:
219: public StringBuffer printExpression(int indent, StringBuffer output) {
220:
221: if (this .receiver != null) {
222: this .receiver.printExpression(0, output);
223: }
224: output.append('#').append(this .selector).append('(');
225: if (this .arguments != null) {
226: for (int i = 0; i < this .arguments.length; i++) {
227: if (i > 0)
228: output.append(", "); //$NON-NLS-1$
229: this .arguments[i].printExpression(0, output);
230: }
231: }
232: return output.append(')');
233: }
234:
235: public TypeBinding resolveType(BlockScope scope) {
236: return internalResolveType(scope);
237: }
238:
239: public TypeBinding resolveType(ClassScope scope) {
240: return internalResolveType(scope);
241: }
242:
243: /* (non-Javadoc)
244: * Redefine to capture javadoc specific signatures
245: * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
246: */
247: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
248: if (visitor.visit(this , blockScope)) {
249: if (this .receiver != null) {
250: this .receiver.traverse(visitor, blockScope);
251: }
252: if (this .arguments != null) {
253: int argumentsLength = this .arguments.length;
254: for (int i = 0; i < argumentsLength; i++)
255: this .arguments[i].traverse(visitor, blockScope);
256: }
257: }
258: visitor.endVisit(this , blockScope);
259: }
260:
261: /* (non-Javadoc)
262: * Redefine to capture javadoc specific signatures
263: * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
264: */
265: public void traverse(ASTVisitor visitor, ClassScope scope) {
266: if (visitor.visit(this , scope)) {
267: if (this .receiver != null) {
268: this .receiver.traverse(visitor, scope);
269: }
270: if (this .arguments != null) {
271: int argumentsLength = this .arguments.length;
272: for (int i = 0; i < argumentsLength; i++)
273: this.arguments[i].traverse(visitor, scope);
274: }
275: }
276: visitor.endVisit(this, scope);
277: }
278: }
|