001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.codeassist.complete;
011:
012: import org.eclipse.jdt.internal.compiler.ast.*;
013: import org.eclipse.jdt.internal.compiler.lookup.*;
014:
015: /**
016: * Node representing a Javadoc comment including code selection.
017: */
018: public class CompletionJavadoc extends Javadoc {
019:
020: Expression completionNode;
021:
022: public CompletionJavadoc(int sourceStart, int sourceEnd) {
023: super (sourceStart, sourceEnd);
024: }
025:
026: /**
027: * @return Returns the completionNode.
028: */
029: public Expression getCompletionNode() {
030: return this .completionNode;
031: }
032:
033: /**
034: * Resolve selected node if not null and throw exception to let clients know
035: * that it has been found.
036: *
037: * @throws CompletionNodeFound
038: */
039: private void internalResolve(Scope scope) {
040: if (this .completionNode != null) {
041: if (this .completionNode instanceof CompletionOnJavadocTag) {
042: ((CompletionOnJavadocTag) this .completionNode)
043: .filterPossibleTags(scope);
044: } else {
045: boolean resolve = true;
046: if (this .completionNode instanceof CompletionOnJavadocParamNameReference) {
047: resolve = ((CompletionOnJavadocParamNameReference) this .completionNode).token != null;
048: } else if (this .completionNode instanceof CompletionOnJavadocTypeParamReference) {
049: resolve = ((CompletionOnJavadocTypeParamReference) this .completionNode).token != null;
050: }
051: if (resolve) {
052: switch (scope.kind) {
053: case Scope.CLASS_SCOPE:
054: this .completionNode
055: .resolveType((ClassScope) scope);
056: break;
057: case Scope.METHOD_SCOPE:
058: this .completionNode
059: .resolveType((MethodScope) scope);
060: break;
061: }
062: }
063: if (this .completionNode instanceof CompletionOnJavadocParamNameReference) {
064: CompletionOnJavadocParamNameReference paramNameReference = (CompletionOnJavadocParamNameReference) this .completionNode;
065: if (scope.kind == Scope.METHOD_SCOPE) {
066: paramNameReference.missingParams = missingParamTags(
067: paramNameReference.binding,
068: (MethodScope) scope);
069: }
070: if (paramNameReference.token == null
071: || paramNameReference.token.length == 0) {
072: paramNameReference.missingTypeParams = missingTypeParameterTags(
073: paramNameReference.binding, scope);
074: }
075: } else if (this .completionNode instanceof CompletionOnJavadocTypeParamReference) {
076: CompletionOnJavadocTypeParamReference typeParamReference = (CompletionOnJavadocTypeParamReference) this .completionNode;
077: typeParamReference.missingParams = missingTypeParameterTags(
078: typeParamReference.resolvedType, scope);
079: }
080: }
081: Binding qualifiedBinding = null;
082: if (this .completionNode instanceof CompletionOnJavadocQualifiedTypeReference) {
083: CompletionOnJavadocQualifiedTypeReference typeRef = (CompletionOnJavadocQualifiedTypeReference) this .completionNode;
084: if (typeRef.packageBinding == null) {
085: qualifiedBinding = typeRef.resolvedType;
086: } else {
087: qualifiedBinding = typeRef.packageBinding;
088: }
089: } else if (this .completionNode instanceof CompletionOnJavadocMessageSend) {
090: CompletionOnJavadocMessageSend msg = (CompletionOnJavadocMessageSend) this .completionNode;
091: if (!msg.receiver.isThis())
092: qualifiedBinding = msg.receiver.resolvedType;
093: } else if (this .completionNode instanceof CompletionOnJavadocAllocationExpression) {
094: CompletionOnJavadocAllocationExpression alloc = (CompletionOnJavadocAllocationExpression) this .completionNode;
095: qualifiedBinding = alloc.type.resolvedType;
096: }
097: throw new CompletionNodeFound(this .completionNode,
098: qualifiedBinding, scope);
099: }
100: }
101:
102: /*
103: * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#print(int, java.lang.StringBuffer)
104: */
105: public StringBuffer print(int indent, StringBuffer output) {
106: printIndent(indent, output).append("/**\n"); //$NON-NLS-1$
107: boolean nodePrinted = false;
108: if (this .paramReferences != null) {
109: for (int i = 0, length = this .paramReferences.length; i < length; i++) {
110: printIndent(indent, output).append(" * @param "); //$NON-NLS-1$
111: this .paramReferences[i].print(indent, output).append(
112: '\n');
113: if (!nodePrinted && this .completionNode != null) {
114: nodePrinted = this .completionNode == this .paramReferences[i];
115: }
116: }
117: }
118: if (this .paramTypeParameters != null) {
119: for (int i = 0, length = this .paramTypeParameters.length; i < length; i++) {
120: printIndent(indent, output).append(" * @param <"); //$NON-NLS-1$
121: this .paramTypeParameters[i].print(indent, output)
122: .append(">\n"); //$NON-NLS-1$
123: if (!nodePrinted && this .completionNode != null) {
124: nodePrinted = this .completionNode == this .paramTypeParameters[i];
125: }
126: }
127: }
128: if (this .returnStatement != null) {
129: printIndent(indent, output).append(" * @"); //$NON-NLS-1$
130: this .returnStatement.print(indent, output).append('\n');
131: }
132: if (this .exceptionReferences != null) {
133: for (int i = 0, length = this .exceptionReferences.length; i < length; i++) {
134: printIndent(indent, output).append(" * @throws "); //$NON-NLS-1$
135: this .exceptionReferences[i].print(indent, output)
136: .append('\n');
137: if (!nodePrinted && this .completionNode != null) {
138: nodePrinted = this .completionNode == this .exceptionReferences[i];
139: }
140: }
141: }
142: if (this .seeReferences != null) {
143: for (int i = 0, length = this .seeReferences.length; i < length; i++) {
144: printIndent(indent, output).append(" * @see "); //$NON-NLS-1$
145: this .seeReferences[i].print(indent, output)
146: .append('\n');
147: if (!nodePrinted && this .completionNode != null) {
148: nodePrinted = this .completionNode == this .seeReferences[i];
149: }
150: }
151: }
152: if (!nodePrinted && this .completionNode != null) {
153: printIndent(indent, output).append(" * "); //$NON-NLS-1$
154: this .completionNode.print(indent, output).append('\n');
155: }
156: printIndent(indent, output).append(" */\n"); //$NON-NLS-1$
157: return output;
158: }
159:
160: /**
161: * Resolve completion node if not null and throw exception to let clients know
162: * that it has been found.
163: *
164: * @throws CompletionNodeFound
165: */
166: public void resolve(ClassScope scope) {
167: super .resolve(scope);
168: internalResolve(scope);
169: }
170:
171: /**
172: * Resolve completion node if not null and throw exception to let clients know
173: * that it has been found.
174: *
175: * @throws CompletionNodeFound
176: */
177: public void resolve(CompilationUnitScope scope) {
178: internalResolve(scope);
179: }
180:
181: /**
182: * Resolve completion node if not null and throw exception to let clients know
183: * that it has been found.
184: *
185: * @throws CompletionNodeFound
186: */
187: public void resolve(MethodScope scope) {
188: super .resolve(scope);
189: internalResolve(scope);
190: }
191:
192: /*
193: * Look for missing method @param tags
194: */
195: private char[][] missingParamTags(Binding paramNameRefBinding,
196: MethodScope methScope) {
197:
198: // Verify if there's some possible param tag
199: AbstractMethodDeclaration md = methScope.referenceMethod();
200: int paramTagsSize = this .paramReferences == null ? 0
201: : this .paramReferences.length;
202: if (md == null)
203: return null;
204: int argumentsSize = md.arguments == null ? 0
205: : md.arguments.length;
206: if (argumentsSize == 0)
207: return null;
208:
209: // Store all method arguments if there's no @param in javadoc
210: if (paramTagsSize == 0) {
211: char[][] missingParams = new char[argumentsSize][];
212: for (int i = 0; i < argumentsSize; i++) {
213: missingParams[i] = md.arguments[i].name;
214: }
215: return missingParams;
216: }
217:
218: // Look for missing arguments
219: char[][] missingParams = new char[argumentsSize][];
220: int size = 0;
221: for (int i = 0; i < argumentsSize; i++) {
222: Argument arg = md.arguments[i];
223: boolean found = false;
224: int paramNameRefCount = 0;
225: for (int j = 0; j < paramTagsSize && !found; j++) {
226: JavadocSingleNameReference param = this .paramReferences[j];
227: if (arg.binding == param.binding) {
228: if (param.binding == paramNameRefBinding) { // do not count first occurence of param name reference
229: paramNameRefCount++;
230: found = paramNameRefCount > 1;
231: } else {
232: found = true;
233: }
234: }
235: }
236: if (!found) {
237: missingParams[size++] = arg.name;
238: }
239: }
240: if (size > 0) {
241: if (size != argumentsSize) {
242: System.arraycopy(missingParams, 0,
243: missingParams = new char[size][], 0, size);
244: }
245: return missingParams;
246: }
247: return null;
248: }
249:
250: /*
251: * Look for missing type parameters @param tags
252: */
253: private char[][] missingTypeParameterTags(
254: Binding paramNameRefBinding, Scope scope) {
255: int paramTypeParamLength = this .paramTypeParameters == null ? 0
256: : this .paramTypeParameters.length;
257:
258: // Verify if there's any type parameter to tag
259: TypeParameter[] parameters = null;
260: TypeVariableBinding[] typeVariables = null;
261: switch (scope.kind) {
262: case Scope.METHOD_SCOPE:
263: AbstractMethodDeclaration methodDeclaration = ((MethodScope) scope)
264: .referenceMethod();
265: if (methodDeclaration == null)
266: return null;
267: parameters = methodDeclaration.typeParameters();
268: typeVariables = methodDeclaration.binding.typeVariables;
269: break;
270: case Scope.CLASS_SCOPE:
271: TypeDeclaration typeDeclaration = ((ClassScope) scope).referenceContext;
272: parameters = typeDeclaration.typeParameters;
273: typeVariables = typeDeclaration.binding.typeVariables;
274: break;
275: }
276: if (typeVariables == null || typeVariables.length == 0)
277: return null;
278:
279: // Store all type parameters if there's no @param in javadoc
280: if (parameters != null) {
281: int typeParametersLength = parameters.length;
282: if (paramTypeParamLength == 0) {
283: char[][] missingParams = new char[typeParametersLength][];
284: for (int i = 0; i < typeParametersLength; i++) {
285: missingParams[i] = parameters[i].name;
286: }
287: return missingParams;
288: }
289:
290: // Look for missing type parameter
291: char[][] missingParams = new char[typeParametersLength][];
292: int size = 0;
293: for (int i = 0; i < typeParametersLength; i++) {
294: TypeParameter parameter = parameters[i];
295: boolean found = false;
296: int paramNameRefCount = 0;
297: for (int j = 0; j < paramTypeParamLength && !found; j++) {
298: if (parameter.binding == this .paramTypeParameters[j].resolvedType) {
299: if (parameter.binding == paramNameRefBinding) { // do not count first occurence of param nmae reference
300: paramNameRefCount++;
301: found = paramNameRefCount > 1;
302: } else {
303: found = true;
304: }
305: }
306: }
307: if (!found) {
308: missingParams[size++] = parameter.name;
309: }
310: }
311: if (size > 0) {
312: if (size != typeParametersLength) {
313: System.arraycopy(missingParams, 0,
314: missingParams = new char[size][], 0, size);
315: }
316: return missingParams;
317: }
318: }
319: return null;
320: }
321: }
|