KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > Javadoc


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17 import org.eclipse.jdt.internal.compiler.parser.JavadocTagConstants;
18
19 /**
20  * Node representing a structured Javadoc comment
21  */

22 public class Javadoc extends ASTNode {
23
24     public JavadocSingleNameReference[] paramReferences; // @param
25
public JavadocSingleTypeReference[] paramTypeParameters; // @param
26
public TypeReference[] exceptionReferences; // @throws, @exception
27
public JavadocReturnStatement returnStatement; // @return
28
public Expression[] seeReferences; // @see
29
public long inheritedPositions = -1;
30     // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600
31
// Store param references for tag with invalid syntax
32
public JavadocSingleNameReference[] invalidParameters; // @param
33
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=153399
34
// Store value tag positions
35
public long valuePositions = -1;
36
37     public Javadoc(int sourceStart, int sourceEnd) {
38         this.sourceStart = sourceStart;
39         this.sourceEnd = sourceEnd;
40     }
41     /**
42      * Returns whether a type can be seen at a given visibility level or not.
43      *
44      * @param visibility Level of visiblity allowed to see references
45      * @param modifiers modifiers of java element to be seen
46      * @return true if the type can be seen, false otherwise
47      */

48     boolean canBeSeen(int visibility, int modifiers) {
49         if (modifiers < 0) return true;
50         switch (modifiers & ExtraCompilerModifiers.AccVisibilityMASK) {
51             case ClassFileConstants.AccPublic :
52                 return true;
53             case ClassFileConstants.AccProtected:
54                 return (visibility != ClassFileConstants.AccPublic);
55             case ClassFileConstants.AccDefault:
56                 return (visibility == ClassFileConstants.AccDefault || visibility == ClassFileConstants.AccPrivate);
57             case ClassFileConstants.AccPrivate:
58                 return (visibility == ClassFileConstants.AccPrivate);
59         }
60         return true;
61     }
62
63     /*
64      * Search node with a given staring position in javadoc objects arrays.
65      */

66     public ASTNode getNodeStartingAt(int start) {
67         int length = 0;
68         // parameters array
69
if (this.paramReferences != null) {
70             length = this.paramReferences.length;
71             for (int i=0; i<length; i++) {
72                 JavadocSingleNameReference param = this.paramReferences[i];
73                 if (param.sourceStart==start) {
74                     return param;
75                 }
76             }
77         }
78         // array of invalid syntax tags parameters
79
if (this.invalidParameters != null) {
80             length = this.invalidParameters.length;
81             for (int i=0; i<length; i++) {
82                 JavadocSingleNameReference param = this.invalidParameters[i];
83                 if (param.sourceStart==start) {
84                     return param;
85                 }
86             }
87         }
88         // type parameters array
89
if (this.paramTypeParameters != null) {
90             length = this.paramTypeParameters.length;
91             for (int i=0; i<length; i++) {
92                 JavadocSingleTypeReference param = this.paramTypeParameters[i];
93                 if (param.sourceStart==start) {
94                     return param;
95                 }
96             }
97         }
98         // thrown exception array
99
if (this.exceptionReferences != null) {
100             length = this.exceptionReferences.length;
101             for (int i=0; i<length; i++) {
102                 TypeReference typeRef = this.exceptionReferences[i];
103                 if (typeRef.sourceStart==start) {
104                     return typeRef;
105                 }
106             }
107         }
108         // references array
109
if (this.seeReferences != null) {
110             length = this.seeReferences.length;
111             for (int i=0; i<length; i++) {
112                 org.eclipse.jdt.internal.compiler.ast.Expression expression = this.seeReferences[i];
113                 if (expression.sourceStart==start) {
114                     return expression;
115                 } else if (expression instanceof JavadocAllocationExpression) {
116                     JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.seeReferences[i];
117                     // if binding is valid then look at arguments
118
if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) {
119                         if (allocationExpr.arguments != null) {
120                             for (int j=0, l=allocationExpr.arguments.length; j<l; j++) {
121                                 if (allocationExpr.arguments[j].sourceStart == start) {
122                                     return allocationExpr.arguments[j];
123                                 }
124                             }
125                         }
126                     }
127                 } else if (expression instanceof JavadocMessageSend) {
128                     JavadocMessageSend messageSend = (JavadocMessageSend) this.seeReferences[i];
129                     // if binding is valid then look at arguments
130
if (messageSend.binding != null && messageSend.binding.isValidBinding()) {
131                         if (messageSend.arguments != null) {
132                             for (int j=0, l=messageSend.arguments.length; j<l; j++) {
133                                 if (messageSend.arguments[j].sourceStart == start) {
134                                     return messageSend.arguments[j];
135                                 }
136                             }
137                         }
138                     }
139                 }
140             }
141         }
142         return null;
143     }
144
145     /*
146      * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#print(int, java.lang.StringBuffer)
147      */

148     public StringBuffer JavaDoc print(int indent, StringBuffer JavaDoc output) {
149         printIndent(indent, output).append("/**\n"); //$NON-NLS-1$
150
if (this.paramReferences != null) {
151             for (int i = 0, length = this.paramReferences.length; i < length; i++) {
152                 printIndent(indent + 1, output).append(" * @param "); //$NON-NLS-1$
153
this.paramReferences[i].print(indent, output).append('\n');
154             }
155         }
156         if (this.paramTypeParameters != null) {
157             for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) {
158                 printIndent(indent + 1, output).append(" * @param <"); //$NON-NLS-1$
159
this.paramTypeParameters[i].print(indent, output).append(">\n"); //$NON-NLS-1$
160
}
161         }
162         if (this.returnStatement != null) {
163             printIndent(indent + 1, output).append(" * @"); //$NON-NLS-1$
164
this.returnStatement.print(indent, output).append('\n');
165         }
166         if (this.exceptionReferences != null) {
167             for (int i = 0, length = this.exceptionReferences.length; i < length; i++) {
168                 printIndent(indent + 1, output).append(" * @throws "); //$NON-NLS-1$
169
this.exceptionReferences[i].print(indent, output).append('\n');
170             }
171         }
172         if (this.seeReferences != null) {
173             for (int i = 0, length = this.seeReferences.length; i < length; i++) {
174                 printIndent(indent + 1, output).append(" * @see "); //$NON-NLS-1$
175
this.seeReferences[i].print(indent, output).append('\n');
176             }
177         }
178         printIndent(indent, output).append(" */\n"); //$NON-NLS-1$
179
return output;
180     }
181
182     /*
183      * Resolve type javadoc
184      */

185     public void resolve(ClassScope scope) {
186
187         // @param tags
188
int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
189         for (int i = 0; i < paramTagsSize; i++) {
190             JavadocSingleNameReference param = this.paramReferences[i];
191             scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
192         }
193         resolveTypeParameterTags(scope, true);
194
195         // @return tags
196
if (this.returnStatement != null) {
197             scope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd);
198         }
199
200         // @throws/@exception tags
201
int throwsTagsLength = this.exceptionReferences == null ? 0 : this.exceptionReferences.length;
202         for (int i = 0; i < throwsTagsLength; i++) {
203             TypeReference typeRef = this.exceptionReferences[i];
204             int start, end;
205             if (typeRef instanceof JavadocSingleTypeReference) {
206                 JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef;
207                 start = singleRef.tagSourceStart;
208                 end = singleRef.tagSourceEnd;
209             } else if (typeRef instanceof JavadocQualifiedTypeReference) {
210                 JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef;
211                 start = qualifiedRef.tagSourceStart;
212                 end = qualifiedRef.tagSourceEnd;
213             } else {
214                 start = typeRef.sourceStart;
215                 end = typeRef.sourceEnd;
216             }
217             scope.problemReporter().javadocUnexpectedTag(start, end);
218         }
219
220         // @see tags
221
int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
222         for (int i = 0; i < seeTagsLength; i++) {
223             resolveReference(this.seeReferences[i], scope);
224         }
225
226         // @value tag
227
boolean source15 = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
228         if (!source15 && this.valuePositions != -1) {
229             scope.problemReporter().javadocUnexpectedTag((int)(this.valuePositions>>>32), (int) this.valuePositions);
230         }
231     }
232
233     /*
234      * Resolve compilation unit javadoc
235      */

236     public void resolve(CompilationUnitScope unitScope) {
237         // do nothing
238
}
239
240     /*
241      * Resolve method javadoc
242      */

243     public void resolve(MethodScope methScope) {
244         
245         // get method declaration
246
AbstractMethodDeclaration methDecl = methScope.referenceMethod();
247         boolean overriding = methDecl == null /* field declaration */ || methDecl.binding == null /* compiler error */
248             ? false :
249             !methDecl.binding.isStatic() && ((methDecl.binding.modifiers & (ExtraCompilerModifiers.AccImplementing | ExtraCompilerModifiers.AccOverriding)) != 0);
250         
251         // @see tags
252
int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
253         boolean superRef = false;
254         for (int i = 0; i < seeTagsLength; i++) {
255             
256             // Resolve reference
257
resolveReference(this.seeReferences[i], methScope);
258             
259             // see whether we can have a super reference
260
if (methDecl != null && (methDecl.isConstructor() || overriding) && !superRef) {
261                 if (this.seeReferences[i] instanceof JavadocMessageSend) {
262                     JavadocMessageSend messageSend = (JavadocMessageSend) this.seeReferences[i];
263                     // if binding is valid then look if we have a reference to an overriden method/constructor
264
if (messageSend.binding != null && messageSend.binding.isValidBinding() && messageSend.actualReceiverType instanceof ReferenceBinding) {
265                         ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
266                         if ((methodReceiverType.isSuperclassOf(methDecl.binding.declaringClass) || (methodReceiverType.isInterface() && methDecl.binding.declaringClass.implementsInterface(methodReceiverType, true))) &&
267                                 CharOperation.equals(messageSend.selector, methDecl.selector) &&
268                                 (methDecl.binding.returnType.isCompatibleWith(messageSend.binding.returnType))) {
269                             if (messageSend.arguments == null && methDecl.arguments == null) {
270                                 superRef = true;
271                             }
272                             else if (messageSend.arguments != null && methDecl.arguments != null) {
273                                 superRef = methDecl.binding.areParameterErasuresEqual(messageSend.binding);
274                             }
275                         }
276                     }
277                 }
278                 else if (this.seeReferences[i] instanceof JavadocAllocationExpression) {
279                     JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.seeReferences[i];
280                     // if binding is valid then look if we have a reference to an overriden method/constructor
281
if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) {
282                         if (methDecl.binding.declaringClass.isCompatibleWith(allocationExpr.resolvedType)) {
283                             if (allocationExpr.arguments == null && methDecl.arguments == null) {
284                                 superRef = true;
285                             }
286                             else if (allocationExpr.arguments != null && methDecl.arguments != null && allocationExpr.arguments.length == methDecl.arguments.length) {
287                                 superRef = methDecl.binding.areParametersCompatibleWith(allocationExpr.binding.parameters);
288                             }
289                         }
290                     }
291                 }
292             }
293         }
294         
295         // Look at @Override annotations
296
if (!superRef && methDecl != null && methDecl.annotations != null) {
297             int length = methDecl.annotations.length;
298             for (int i=0; i<length && !superRef; i++) {
299                 superRef = (methDecl.binding.tagBits & TagBits.AnnotationOverride) != 0;
300             }
301         }
302         
303         // Store if a reference exists to an overriden method/constructor or the method is in a local type,
304
boolean reportMissing = methDecl == null || !((overriding && this.inheritedPositions != -1) || superRef || (methDecl.binding.declaringClass != null && methDecl.binding.declaringClass.isLocalType()));
305         if (!overriding && this.inheritedPositions != -1) {
306             int start = (int) (this.inheritedPositions >>> 32);
307             int end = (int) this.inheritedPositions;
308             methScope.problemReporter().javadocUnexpectedTag(start, end);
309         }
310
311         // @param tags
312
boolean considerParamRefAsUsage = methScope.compilerOptions().reportUnusedParameterIncludeDocCommentReference;
313         resolveParamTags(methScope, reportMissing, considerParamRefAsUsage);
314         resolveTypeParameterTags(methScope, reportMissing);
315
316         // @return tags
317
if (this.returnStatement == null) {
318             if (reportMissing && methDecl != null) {
319                 if (methDecl.isMethod()) {
320                     MethodDeclaration meth = (MethodDeclaration) methDecl;
321                     if (meth.binding.returnType != TypeBinding.VOID) {
322                         // method with return should have @return tag
323
methScope.problemReporter().javadocMissingReturnTag(meth.returnType.sourceStart, meth.returnType.sourceEnd, methDecl.binding.modifiers);
324                     }
325                 }
326             }
327         } else {
328             this.returnStatement.resolve(methScope);
329         }
330
331         // @throws/@exception tags
332
resolveThrowsTags(methScope, reportMissing);
333
334         // @value tag
335
boolean source15 = methScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
336         if (!source15 && methDecl != null && this.valuePositions != -1) {
337             methScope.problemReporter().javadocUnexpectedTag((int)(this.valuePositions>>>32), (int) this.valuePositions);
338         }
339
340         // Resolve param tags with invalid syntax
341
int length = this.invalidParameters == null ? 0 : this.invalidParameters.length;
342         for (int i = 0; i < length; i++) {
343             this.invalidParameters[i].resolve(methScope, false, false);
344         }
345     }
346     
347     private void resolveReference(Expression reference, Scope scope) {
348
349         // Perform resolve
350
int problemCount = scope.referenceContext().compilationResult().problemCount;
351         switch (scope.kind) {
352             case Scope.METHOD_SCOPE:
353                 reference.resolveType((MethodScope)scope);
354                 break;
355             case Scope.CLASS_SCOPE:
356                 reference.resolveType((ClassScope)scope);
357                 break;
358         }
359         boolean hasProblems = scope.referenceContext().compilationResult().problemCount > problemCount;
360
361         // Verify field references
362
boolean source15 = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
363         int scopeModifiers = -1;
364         if (reference instanceof JavadocFieldReference) {
365             JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
366             
367             // Verify if this is a method reference
368
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51911
369
if (fieldRef.methodBinding != null) {
370                 // cannot refer to method for @value tag
371
if (fieldRef.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) {
372                     if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
373                     scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, scopeModifiers);
374                 }
375                 else if (fieldRef.receiverType != null) {
376                     if (scope.enclosingSourceType().isCompatibleWith(fieldRef.receiverType)) {
377                         fieldRef.bits |= ASTNode.SuperAccess;
378                     }
379                     fieldRef.methodBinding = scope.findMethod((ReferenceBinding)fieldRef.receiverType, fieldRef.token, new TypeBinding[0], fieldRef);
380                 }
381             }
382
383             // Verify whether field ref should be static or not (for @value tags)
384
else if (source15 && fieldRef.binding != null && fieldRef.binding.isValidBinding()) {
385                 if (fieldRef.tagValue == JavadocTagConstants.TAG_VALUE_VALUE && !fieldRef.binding.isStatic()) {
386                     if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
387                     scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, scopeModifiers);
388                 }
389             }
390
391             // Verify type references
392
if (!hasProblems && fieldRef.binding != null && fieldRef.binding.isValidBinding() && fieldRef.receiverType instanceof ReferenceBinding) {
393                 ReferenceBinding resolvedType = (ReferenceBinding) fieldRef.receiverType;
394                 verifyTypeReference(fieldRef, fieldRef.receiver, scope, source15, resolvedType, fieldRef.binding.modifiers);
395             }
396
397             // That's it for field references
398
return;
399         }
400
401         // Verify type references
402
if (!hasProblems && (reference instanceof JavadocSingleTypeReference || reference instanceof JavadocQualifiedTypeReference) && reference.resolvedType instanceof ReferenceBinding) {
403             ReferenceBinding resolvedType = (ReferenceBinding) reference.resolvedType;
404             verifyTypeReference(reference, reference, scope, source15, resolvedType, resolvedType.modifiers);
405         }
406
407         // Verify that message reference are not used for @value tags
408
if (reference instanceof JavadocMessageSend) {
409             JavadocMessageSend msgSend = (JavadocMessageSend) reference;
410
411             // tag value
412
if (source15 && msgSend.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) { // cannot refer to method for @value tag
413
if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
414                 scope.problemReporter().javadocInvalidValueReference(msgSend.sourceStart, msgSend.sourceEnd, scopeModifiers);
415             }
416
417             // Verify type references
418
if (!hasProblems && msgSend.binding != null && msgSend.binding.isValidBinding() && msgSend.actualReceiverType instanceof ReferenceBinding) {
419                 ReferenceBinding resolvedType = (ReferenceBinding) msgSend.actualReceiverType;
420                 verifyTypeReference(msgSend, msgSend.receiver, scope, source15, resolvedType, msgSend.binding.modifiers);
421             }
422         }
423
424         // Verify that constructor reference are not used for @value tags
425
else if (reference instanceof JavadocAllocationExpression) {
426             JavadocAllocationExpression alloc = (JavadocAllocationExpression) reference;
427
428             // tag value
429
if (source15 && alloc.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) { // cannot refer to method for @value tag
430
if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
431                 scope.problemReporter().javadocInvalidValueReference(alloc.sourceStart, alloc.sourceEnd, scopeModifiers);
432             }
433
434             // Verify type references
435
if (!hasProblems && alloc.binding != null && alloc.binding.isValidBinding() && alloc.resolvedType instanceof ReferenceBinding) {
436                 ReferenceBinding resolvedType = (ReferenceBinding) alloc.resolvedType;
437                 verifyTypeReference(alloc, alloc.type, scope, source15, resolvedType, alloc.binding.modifiers);
438             }
439         }
440         
441         // Verify that there's no type variable reference
442
// (javadoc does not accept them and this is not a referenced bug or requested enhancement)
443
if (reference.resolvedType != null && reference.resolvedType.isTypeVariable()) {
444             scope.problemReporter().javadocInvalidReference(reference.sourceStart, reference.sourceEnd);
445         }
446     }
447
448     /*
449      * Resolve @param tags while method scope
450      */

451     private void resolveParamTags(MethodScope scope, boolean reportMissing, boolean considerParamRefAsUsage) {
452         AbstractMethodDeclaration methodDecl = scope.referenceMethod();
453         int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
454
455         // If no referenced method (field initializer for example) then report a problem for each param tag
456
if (methodDecl == null) {
457             for (int i = 0; i < paramTagsSize; i++) {
458                 JavadocSingleNameReference param = this.paramReferences[i];
459                 scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
460             }
461             return;
462         }
463         
464         // If no param tags then report a problem for each method argument
465
int argumentsSize = methodDecl.arguments == null ? 0 : methodDecl.arguments.length;
466         if (paramTagsSize == 0) {
467             if (reportMissing) {
468                 for (int i = 0; i < argumentsSize; i++) {
469                     Argument arg = methodDecl.arguments[i];
470                     scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers);
471                 }
472             }
473         } else {
474             LocalVariableBinding[] bindings = new LocalVariableBinding[paramTagsSize];
475             int maxBindings = 0;
476
477             // Scan all @param tags
478
for (int i = 0; i < paramTagsSize; i++) {
479                 JavadocSingleNameReference param = this.paramReferences[i];
480                 param.resolve(scope, true, considerParamRefAsUsage);
481                 if (param.binding != null && param.binding.isValidBinding()) {
482                     // Verify duplicated tags
483
boolean found = false;
484                     for (int j = 0; j < maxBindings && !found; j++) {
485                         if (bindings[j] == param.binding) {
486                             scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, methodDecl.binding.modifiers);
487                             found = true;
488                         }
489                     }
490                     if (!found) {
491                         bindings[maxBindings++] = (LocalVariableBinding) param.binding;
492                     }
493                 }
494             }
495
496             // Look for undocumented arguments
497
if (reportMissing) {
498                 for (int i = 0; i < argumentsSize; i++) {
499                     Argument arg = methodDecl.arguments[i];
500                     boolean found = false;
501                     for (int j = 0; j < maxBindings && !found; j++) {
502                         LocalVariableBinding binding = bindings[j];
503                         if (arg.binding == binding) {
504                             found = true;
505                         }
506                     }
507                     if (!found) {
508                         scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers);
509                     }
510                 }
511             }
512         }
513     }
514
515     /*
516      * Resolve @param tags for type parameters
517      */

518     private void resolveTypeParameterTags(Scope scope, boolean reportMissing) {
519         int paramTypeParamLength = this.paramTypeParameters == null ? 0 : this.paramTypeParameters.length;
520
521         // Get declaration infos
522
TypeParameter[] parameters = null;
523         TypeVariableBinding[] typeVariables = null;
524         int modifiers = -1;
525         switch (scope.kind) {
526             case Scope.METHOD_SCOPE:
527                 AbstractMethodDeclaration methodDeclaration = ((MethodScope)scope).referenceMethod();
528                 // If no referenced method (field initializer for example) then report a problem for each param tag
529
if (methodDeclaration == null) {
530                     for (int i = 0; i < paramTypeParamLength; i++) {
531                         JavadocSingleNameReference param = this.paramReferences[i];
532                         scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
533                     }
534                     return;
535                 }
536                 parameters = methodDeclaration.typeParameters();
537                 typeVariables = methodDeclaration.binding.typeVariables;
538                 modifiers = methodDeclaration.binding.modifiers;
539                 break;
540             case Scope.CLASS_SCOPE:
541                 TypeDeclaration typeDeclaration = ((ClassScope) scope).referenceContext;
542                 parameters = typeDeclaration.typeParameters;
543                 typeVariables = typeDeclaration.binding.typeVariables;
544                 modifiers = typeDeclaration.binding.modifiers;
545                 break;
546         }
547
548         // If no type variables then report a problem for each param type parameter tag
549
if (typeVariables == null || typeVariables.length == 0) {
550             for (int i = 0; i < paramTypeParamLength; i++) {
551                 JavadocSingleTypeReference param = this.paramTypeParameters[i];
552                 scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
553             }
554             return;
555         }
556         
557         // If no param tags then report a problem for each declaration type parameter
558
if (parameters != null) {
559             int typeParametersLength = parameters.length;
560             if (paramTypeParamLength == 0) {
561                 if (reportMissing) {
562                     for (int i = 0, l=typeParametersLength; i<l; i++) {
563                         scope.problemReporter().javadocMissingParamTag(parameters[i].name, parameters[i].sourceStart, parameters[i].sourceEnd, modifiers);
564                     }
565                 }
566
567             // Otherwise verify that all param tags match type parameters
568
} else if (typeVariables.length == typeParametersLength) {
569                 TypeVariableBinding[] bindings = new TypeVariableBinding[paramTypeParamLength];
570
571                 // Scan all @param tags
572
for (int i = 0; i < paramTypeParamLength; i++) {
573                     JavadocSingleTypeReference param = this.paramTypeParameters[i];
574                     TypeBinding paramBindind = param.internalResolveType(scope);
575                     if (paramBindind != null && paramBindind.isValidBinding()) {
576                         if (paramBindind.isTypeVariable()) {
577                             // Verify duplicated tags
578
boolean duplicate = false;
579                             for (int j = 0; j < i && !duplicate; j++) {
580                                 if (bindings[j] == param.resolvedType) {
581                                     scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
582                                     duplicate = true;
583                                 }
584                             }
585                             if (!duplicate) {
586                                 bindings[i] = (TypeVariableBinding) param.resolvedType;
587                             }
588                         } else {
589                             scope.problemReporter().javadocUndeclaredParamTagName(param.token, param.sourceStart, param.sourceEnd, modifiers);
590                         }
591                     }
592                 }
593
594                 // Look for undocumented type parameters
595
for (int i = 0; i < typeParametersLength; i++) {
596                     TypeParameter parameter = parameters[i];
597                     boolean found = false;
598                     for (int j = 0; j < paramTypeParamLength && !found; j++) {
599                         if (parameter.binding == bindings[j]) {
600                             found = true;
601                             bindings[j] = null;
602                         }
603                     }
604                     if (!found && reportMissing) {
605                         scope.problemReporter().javadocMissingParamTag(parameter.name, parameter.sourceStart, parameter.sourceEnd, modifiers);
606                     }
607                 }
608             
609                 // Report invalid param
610
for (int i=0; i<paramTypeParamLength; i++) {
611                     if (bindings[i] != null) {
612                         JavadocSingleTypeReference param = this.paramTypeParameters[i];
613                         scope.problemReporter().javadocUndeclaredParamTagName(param.token, param.sourceStart, param.sourceEnd, modifiers);
614                     }
615                 }
616             }
617         }
618     }
619
620     /*
621      * Resolve @throws/@exception tags while method scope
622      */

623     private void resolveThrowsTags(MethodScope methScope, boolean reportMissing) {
624         AbstractMethodDeclaration md = methScope.referenceMethod();
625         int throwsTagsLength = this.exceptionReferences == null ? 0 : this.exceptionReferences.length;
626
627         // If no referenced method (field initializer for example) then report a problem for each throws tag
628
if (md == null) {
629             for (int i = 0; i < throwsTagsLength; i++) {
630                 TypeReference typeRef = this.exceptionReferences[i];
631                 int start = typeRef.sourceStart;
632                 int end = typeRef.sourceEnd;
633                 if (typeRef instanceof JavadocQualifiedTypeReference) {
634                     start = ((JavadocQualifiedTypeReference) typeRef).tagSourceStart;
635                     end = ((JavadocQualifiedTypeReference) typeRef).tagSourceEnd;
636                 } else if (typeRef instanceof JavadocSingleTypeReference) {
637                     start = ((JavadocSingleTypeReference) typeRef).tagSourceStart;
638                     end = ((JavadocSingleTypeReference) typeRef).tagSourceEnd;
639                 }
640                 methScope.problemReporter().javadocUnexpectedTag(start, end);
641             }
642             return;
643         }
644
645         // If no throws tags then report a problem for each method thrown exception
646
int boundExceptionLength = (md.binding == null) ? 0 : md.binding.thrownExceptions.length;
647         int thrownExceptionLength = md.thrownExceptions == null ? 0 : md.thrownExceptions.length;
648         if (throwsTagsLength == 0) {
649             if (reportMissing) {
650                 for (int i = 0; i < boundExceptionLength; i++) {
651                     ReferenceBinding exceptionBinding = md.binding.thrownExceptions[i];
652                     if (exceptionBinding != null && exceptionBinding.isValidBinding()) { // flag only valid class name
653
int j=i;
654                         while (j<thrownExceptionLength && exceptionBinding != md.thrownExceptions[j].resolvedType) j++;
655                         if (j<thrownExceptionLength) {
656                             methScope.problemReporter().javadocMissingThrowsTag(md.thrownExceptions[j], md.binding.modifiers);
657                         }
658                     }
659                 }
660             }
661         } else {
662             int maxRef = 0;
663             TypeReference[] typeReferences = new TypeReference[throwsTagsLength];
664
665             // Scan all @throws tags
666
for (int i = 0; i < throwsTagsLength; i++) {
667                 TypeReference typeRef = this.exceptionReferences[i];
668                 typeRef.resolve(methScope);
669                 TypeBinding typeBinding = typeRef.resolvedType;
670
671                 if (typeBinding != null && typeBinding.isValidBinding() && typeBinding.isClass()) {
672                     // accept only valid class binding
673
typeReferences[maxRef++] = typeRef;
674                 }
675             }
676
677             // Look for undocumented thrown exception
678
for (int i = 0; i < boundExceptionLength; i++) {
679                 ReferenceBinding exceptionBinding = md.binding.thrownExceptions[i];
680                 if (exceptionBinding != null) exceptionBinding = (ReferenceBinding) exceptionBinding.erasure();
681                 boolean found = false;
682                 for (int j = 0; j < maxRef && !found; j++) {
683                     if (typeReferences[j] != null) {
684                         TypeBinding typeBinding = typeReferences[j].resolvedType;
685                         if (exceptionBinding == typeBinding) {
686                             found = true;
687                             typeReferences[j] = null;
688                         }
689                     }
690                 }
691                 if (!found && reportMissing) {
692                     if (exceptionBinding != null && exceptionBinding.isValidBinding()) { // flag only valid class name
693
int k=i;
694                         while (k<thrownExceptionLength && exceptionBinding != md.thrownExceptions[k].resolvedType) k++;
695                         if (k<thrownExceptionLength) {
696                             methScope.problemReporter().javadocMissingThrowsTag(md.thrownExceptions[k], md.binding.modifiers);
697                         }
698                     }
699                 }
700             }
701
702             // Verify additional @throws tags
703
for (int i = 0; i < maxRef; i++) {
704                 TypeReference typeRef = typeReferences[i];
705                 if (typeRef != null) {
706                     boolean compatible = false;
707                     // thrown exceptions subclasses are accepted
708
for (int j = 0; j<thrownExceptionLength && !compatible; j++) {
709                         TypeBinding exceptionBinding = md.thrownExceptions[j].resolvedType;
710                         if (exceptionBinding != null) {
711                             compatible = typeRef.resolvedType.isCompatibleWith(exceptionBinding);
712                         }
713                     }
714             
715                     // If not compatible only complain on unchecked exception
716
if (!compatible && !typeRef.resolvedType.isUncheckedException(false)) {
717                         methScope.problemReporter().javadocInvalidThrowsClassName(typeRef, md.binding.modifiers);
718                     }
719                 }
720             }
721         }
722     }
723
724     private void verifyTypeReference(Expression reference, Expression typeReference, Scope scope, boolean source15, ReferenceBinding resolvedType, int modifiers) {
725         if (resolvedType.isValidBinding()) {
726             int scopeModifiers = -1;
727
728             // reference must have enough visibility to be used
729
if (!canBeSeen(scope.problemReporter().options.reportInvalidJavadocTagsVisibility, modifiers)) {
730                 scope.problemReporter().javadocHiddenReference(typeReference.sourceStart, reference.sourceEnd, scope, modifiers);
731                 return;
732             }
733
734             // type reference must have enough visibility to be used
735
if (reference != typeReference) {
736                 if (!canBeSeen(scope.problemReporter().options.reportInvalidJavadocTagsVisibility, resolvedType.modifiers)) {
737                     scope.problemReporter().javadocHiddenReference(typeReference.sourceStart, typeReference.sourceEnd, scope, resolvedType.modifiers);
738                     return;
739                 }
740             }
741             
742             // member types
743
if (resolvedType.isMemberType()) {
744                 ReferenceBinding topLevelType = resolvedType;
745                 // rebuild and store (in reverse order) compound name to handle embedded inner class
746
int packageLength = topLevelType.fPackage.compoundName.length;
747                 int depth = resolvedType.depth();
748                 int idx = depth + packageLength;
749                 char[][] computedCompoundName = new char[idx+1][];
750                 computedCompoundName[idx] = topLevelType.sourceName;
751                 while (topLevelType.enclosingType() != null) {
752                     topLevelType = topLevelType.enclosingType();
753                     computedCompoundName[--idx] = topLevelType.sourceName;
754                 }
755                 
756                 // add package information
757
for (int i = packageLength; --i >= 0;) {
758                     computedCompoundName[--idx] = topLevelType.fPackage.compoundName[i];
759                 }
760                                         
761                 ClassScope topLevelScope = scope.classScope();
762                 // when scope is not on compilation unit type, then inner class may not be visible...
763
if (topLevelScope.parent.kind != Scope.COMPILATION_UNIT_SCOPE ||
764                     !CharOperation.equals(topLevelType.sourceName, topLevelScope.referenceContext.name)) {
765                     topLevelScope = topLevelScope.outerMostClassScope();
766                     if (typeReference instanceof JavadocSingleTypeReference) {
767                         // inner class single reference can only be done in same unit
768
if ((!source15 && depth == 1) || topLevelType != topLevelScope.referenceContext.binding) {
769                             // search for corresponding import
770
boolean hasValidImport = false;
771                             if (source15) {
772                                 CompilationUnitScope unitScope = topLevelScope.compilationUnitScope();
773                                 ImportBinding[] imports = unitScope.imports;
774                                 int length = imports == null ? 0 : imports.length;
775                                 mainLoop: for (int i=0; i<length; i++) {
776                                     char[][] compoundName = imports[i].compoundName;
777                                     int compoundNameLength = compoundName.length;
778                                     if ((imports[i].onDemand && compoundNameLength == computedCompoundName.length-1) ||
779                                         (compoundNameLength == computedCompoundName.length))
780                                     {
781                                         for (int j = compoundNameLength; --j >= 0;) {
782                                             if (CharOperation.equals(imports[i].compoundName[j], computedCompoundName[j])) {
783                                                 if (j == 0) {
784                                                     hasValidImport = true;
785                                                     break mainLoop;
786                                                 }
787                                             } else {
788                                                 break;
789                                             }
790                                         }
791                                     }
792                                 }
793                                 if (!hasValidImport) {
794                                     if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
795                                     scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
796                                 }
797                             } else {
798                                 if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
799                                 scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
800                                 return;
801                             }
802                         }
803                     }
804                 }
805             }
806         }
807     }
808
809     public void traverse(ASTVisitor visitor, BlockScope scope) {
810         if (visitor.visit(this, scope)) {
811             if (this.paramReferences != null) {
812                 for (int i = 0, length = this.paramReferences.length; i < length; i++) {
813                     this.paramReferences[i].traverse(visitor, scope);
814                 }
815             }
816             if (this.paramTypeParameters != null) {
817                 for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) {
818                     this.paramTypeParameters[i].traverse(visitor, scope);
819                 }
820             }
821             if (this.returnStatement != null) {
822                 this.returnStatement.traverse(visitor, scope);
823             }
824             if (this.exceptionReferences != null) {
825                 for (int i = 0, length = this.exceptionReferences.length; i < length; i++) {
826                     this.exceptionReferences[i].traverse(visitor, scope);
827                 }
828             }
829             if (this.seeReferences != null) {
830                 for (int i = 0, length = this.seeReferences.length; i < length; i++) {
831                     this.seeReferences[i].traverse(visitor, scope);
832                 }
833             }
834         }
835         visitor.endVisit(this, scope);
836     }
837     public void traverse(ASTVisitor visitor, ClassScope scope) {
838         if (visitor.visit(this, scope)) {
839             if (this.paramReferences != null) {
840                 for (int i = 0, length = this.paramReferences.length; i < length; i++) {
841                     this.paramReferences[i].traverse(visitor, scope);
842                 }
843             }
844             if (this.paramTypeParameters != null) {
845                 for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) {
846                     this.paramTypeParameters[i].traverse(visitor, scope);
847                 }
848             }
849             if (this.returnStatement != null) {
850                 this.returnStatement.traverse(visitor, scope);
851             }
852             if (this.exceptionReferences != null) {
853                 for (int i = 0, length = this.exceptionReferences.length; i < length; i++) {
854                     this.exceptionReferences[i].traverse(visitor, scope);
855                 }
856             }
857             if (this.seeReferences != null) {
858                 for (int i = 0, length = this.seeReferences.length; i < length; i++) {
859                     this.seeReferences[i].traverse(visitor, scope);
860                 }
861             }
862         }
863         visitor.endVisit(this, scope);
864     }
865 }
866
Popular Tags