added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / Javadoc.java
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
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.classfmt.ClassFileConstants;
15 import org.eclipse.jdt.internal.compiler.lookup.*;
16 import org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser;
17
18 /**
19  * Node representing a structured Javadoc comment
20  */
21 public class Javadoc extends ASTNode {
22
23         public JavadocSingleNameReference[] paramReferences; // @param
24         public JavadocSingleTypeReference[] paramTypeParameters; // @param
25         public TypeReference[] exceptionReferences; // @throws, @exception
26         public JavadocReturnStatement returnStatement; // @return
27         public Expression[] seeReferences; // @see
28         public boolean inherited = false;
29         // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600
30         // Store param references for tag with invalid syntax
31         public JavadocSingleNameReference[] invalidParameters; // @param
32
33         public Javadoc(int sourceStart, int sourceEnd) {
34                 this.sourceStart = sourceStart;
35                 this.sourceEnd = sourceEnd;
36         }
37         
38         /*
39          * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#print(int, java.lang.StringBuffer)
40          */
41         public StringBuffer print(int indent, StringBuffer output) {
42                 printIndent(indent, output).append("/**\n"); //$NON-NLS-1$
43                 if (this.paramReferences != null) {
44                         for (int i = 0, length = this.paramReferences.length; i < length; i++) {
45                                 printIndent(indent + 1, output).append(" * @param "); //$NON-NLS-1$             
46                                 this.paramReferences[i].print(indent, output).append('\n');
47                         }
48                 }
49                 if (this.paramTypeParameters != null) {
50                         for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) {
51                                 printIndent(indent + 1, output).append(" * @param <"); //$NON-NLS-1$            
52                                 this.paramTypeParameters[i].print(indent, output).append(">\n"); //$NON-NLS-1$
53                         }
54                 }
55                 if (this.returnStatement != null) {
56                         printIndent(indent + 1, output).append(" * @"); //$NON-NLS-1$
57                         this.returnStatement.print(indent, output).append('\n');
58                 }
59                 if (this.exceptionReferences != null) {
60                         for (int i = 0, length = this.exceptionReferences.length; i < length; i++) {
61                                 printIndent(indent + 1, output).append(" * @throws "); //$NON-NLS-1$            
62                                 this.exceptionReferences[i].print(indent, output).append('\n');
63                         }
64                 }
65                 if (this.seeReferences != null) {
66                         for (int i = 0, length = this.seeReferences.length; i < length; i++) {
67                                 printIndent(indent + 1, output).append(" * @see"); //$NON-NLS-1$                
68                                 this.seeReferences[i].print(indent, output).append('\n');
69                         }
70                 }
71                 printIndent(indent, output).append(" */\n"); //$NON-NLS-1$
72                 return output;
73         }
74
75         /*
76          * Resolve type javadoc while a class scope
77          */
78         public void resolve(ClassScope classScope) {
79
80                 // @param tags
81                 int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
82                 for (int i = 0; i < paramTagsSize; i++) {
83                         JavadocSingleNameReference param = this.paramReferences[i];
84                         classScope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
85                 }
86                 resolveTypeParameterTags(classScope, true);
87
88                 // @return tags
89                 if (this.returnStatement != null) {
90                         classScope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd);
91                 }
92
93                 // @throws/@exception tags
94                 int throwsTagsLength = this.exceptionReferences == null ? 0 : this.exceptionReferences.length;
95                 for (int i = 0; i < throwsTagsLength; i++) {
96                         TypeReference typeRef = this.exceptionReferences[i];
97                         int start, end;
98                         if (typeRef instanceof JavadocSingleTypeReference) {
99                                 JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef;
100                                 start = singleRef.tagSourceStart;
101                                 end = singleRef.tagSourceEnd;
102                         } else if (typeRef instanceof JavadocQualifiedTypeReference) {
103                                 JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef;
104                                 start = qualifiedRef.tagSourceStart;
105                                 end = qualifiedRef.tagSourceEnd;
106                         } else {
107                                 start = typeRef.sourceStart;
108                                 end = typeRef.sourceEnd;
109                         }
110                         classScope.problemReporter().javadocUnexpectedTag(start, end);
111                 }
112
113                 // @see tags
114                 int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
115                 for (int i = 0; i < seeTagsLength; i++) {
116                         resolveReference(this.seeReferences[i], classScope);
117                 }
118         }
119         
120         /*
121          * Resolve method javadoc while a method scope
122          */
123         public void resolve(MethodScope methScope) {
124                 
125                 // get method declaration
126                 AbstractMethodDeclaration methDecl = methScope.referenceMethod();
127                 boolean overriding = methDecl == null ? false : (methDecl.binding.modifiers & (AccImplementing | AccOverriding)) != 0;
128
129                 // @see tags
130                 int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
131                 boolean superRef = false;
132                 for (int i = 0; i < seeTagsLength; i++) {
133                         
134                         // Resolve reference
135                         resolveReference(this.seeReferences[i], methScope);
136                         
137                         // see whether we can have a super reference
138                         try {
139                                 if (methDecl != null && (methDecl.isConstructor() || overriding) && !superRef) {
140                                         if (this.seeReferences[i] instanceof JavadocMessageSend) {
141                                                 JavadocMessageSend messageSend = (JavadocMessageSend) this.seeReferences[i];
142                                                 // if binding is valid then look if we have a reference to an overriden method/constructor
143                                                 if (messageSend.binding != null && messageSend.binding.isValidBinding()) {
144                                                         if (methDecl.binding.declaringClass.isCompatibleWith(messageSend.actualReceiverType) &&
145                                                                 CharOperation.equals(messageSend.selector, methDecl.selector) &&
146                                                                 (messageSend.binding.returnType == methDecl.binding.returnType)) {
147                                                                 if (messageSend.arguments == null && methDecl.arguments == null) {
148                                                                         superRef = true;
149                                                                 }
150                                                                 else if (messageSend.arguments != null && methDecl.arguments != null) {
151                                                                         superRef = methDecl.binding.areParametersEqual(messageSend.binding);
152                                                                 }
153                                                         }
154                                                 }
155                                         }
156                                         else if (this.seeReferences[i] instanceof JavadocAllocationExpression) {
157                                                 JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.seeReferences[i];
158                                                 // if binding is valid then look if we have a reference to an overriden method/constructor
159                                                 if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) {
160                                                         if (methDecl.binding.declaringClass.isCompatibleWith(allocationExpr.resolvedType)) {
161                                                                 if (allocationExpr.arguments == null && methDecl.arguments == null) {
162                                                                         superRef = true;
163                                                                 }
164                                                                 else if (allocationExpr.arguments != null && methDecl.arguments != null) {
165                                                                         superRef = methDecl.binding.areParametersEqual(allocationExpr.binding);
166                                                                 }
167                                                         }
168                                                 }
169                                         }
170                                 }
171                         }
172                         catch (Exception e) {
173                                 // Something wrong happen, forget super ref...
174                         }
175                 }
176                 
177                 // Store if a reference exists to an overriden method/constructor or the method is in a local type,
178                 boolean reportMissing = methDecl == null || !((overriding && this.inherited) || superRef || (methDecl.binding.declaringClass != null && methDecl.binding.declaringClass.isLocalType()));
179
180                 // @param tags
181                 resolveParamTags(methScope, reportMissing);
182                 resolveTypeParameterTags(methScope, reportMissing);
183
184                 // @return tags
185                 if (this.returnStatement == null) {
186                         if (reportMissing && methDecl != null) {
187                                 if (methDecl.isMethod()) {
188                                         MethodDeclaration meth = (MethodDeclaration) methDecl;
189                                         if (meth.binding.returnType != VoidBinding) {
190                                                 // method with return should have @return tag
191                                                 methScope.problemReporter().javadocMissingReturnTag(meth.returnType.sourceStart, meth.returnType.sourceEnd, methDecl.binding.modifiers);
192                                         }
193                                 }
194                         }
195                 } else {
196                         this.returnStatement.resolve(methScope);
197                 }
198
199                 // @throws/@exception tags
200                 resolveThrowsTags(methScope, reportMissing);
201
202                 // Resolve param tags with invalid syntax
203                 int length = this.invalidParameters == null ? 0 : this.invalidParameters.length;
204                 for (int i = 0; i < length; i++) {
205                         this.invalidParameters[i].resolve(methScope, false);
206                 }
207         }
208         
209         private void resolveReference(Expression reference, Scope scope) {
210
211                 // Perform resolve
212                 switch (scope.kind) {
213                         case Scope.METHOD_SCOPE:
214                                 reference.resolveType((MethodScope)scope);
215                         break;
216                         case Scope.CLASS_SCOPE:
217                                 reference.resolveType((ClassScope)scope);
218                         break;
219                 }
220
221                 // Verify field references
222                 boolean verifyValues = scope.environment().options.sourceLevel >= ClassFileConstants.JDK1_5;
223                 if (reference instanceof JavadocFieldReference) {
224                         JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
225                         int modifiers = fieldRef.binding==null ? -1 : fieldRef.binding.modifiers;
226                         
227                         // Verify if this is a method reference
228                         // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51911
229                         if (fieldRef.methodBinding != null) {
230                                 // cannot refer to method for @value tag
231                                 if (fieldRef.tagValue == AbstractCommentParser.TAG_VALUE_VALUE) {
232                                         scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, modifiers);
233                                 }
234                                 else if (fieldRef.receiverType != null) {
235                                         fieldRef.superAccess = scope.enclosingSourceType().isCompatibleWith(fieldRef.receiverType);
236                                         fieldRef.methodBinding = scope.findMethod((ReferenceBinding)fieldRef.receiverType, fieldRef.token, new TypeBinding[0], fieldRef);
237                                 }
238                         }
239
240                         // Verify whether field ref should be static or not (for @value tags)
241                         else if (verifyValues && fieldRef.binding != null && fieldRef.binding.isValidBinding()) {
242                                 if (fieldRef.tagValue == AbstractCommentParser.TAG_VALUE_VALUE && !fieldRef.binding.isStatic()) {
243                                         scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, modifiers);
244                                 }
245                         }
246                 }
247
248                 // If not 1.5 level, verification is finished
249                 if (!verifyValues)  return;
250
251                 // Verify that message reference are not used for @value tags
252                 else if (reference instanceof JavadocMessageSend) {
253                         JavadocMessageSend msgSend = (JavadocMessageSend) reference;
254                         int modifiers = msgSend.binding==null ? -1 : msgSend.binding.modifiers;
255                         if (msgSend.tagValue == AbstractCommentParser.TAG_VALUE_VALUE) { // cannot refer to method for @value tag
256                                 scope.problemReporter().javadocInvalidValueReference(msgSend.sourceStart, msgSend.sourceEnd, modifiers);
257                         }
258                 }
259
260                 // Verify that constructorreference are not used for @value tags
261                 else if (reference instanceof JavadocAllocationExpression) {
262                         JavadocAllocationExpression alloc = (JavadocAllocationExpression) reference;
263                         int modifiers = alloc.binding==null ? -1 : alloc.binding.modifiers;
264                         if (alloc.tagValue == AbstractCommentParser.TAG_VALUE_VALUE) { // cannot refer to method for @value tag
265                                 scope.problemReporter().javadocInvalidValueReference(alloc.sourceStart, alloc.sourceEnd, modifiers);
266                         }
267                 }
268         }
269
270         /*
271          * Resolve @param tags while method scope
272          */
273         private void resolveParamTags(MethodScope methScope, boolean reportMissing) {
274                 AbstractMethodDeclaration md = methScope.referenceMethod();
275                 int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
276
277                 // If no referenced method (field initializer for example) then report a problem for each param tag
278                 if (md == null) {
279                         for (int i = 0; i < paramTagsSize; i++) {
280                                 JavadocSingleNameReference param = this.paramReferences[i];
281                                 methScope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
282                         }
283                         return;
284                 }
285                 
286                 // If no param tags then report a problem for each method argument
287                 int argumentsSize = md.arguments == null ? 0 : md.arguments.length;
288                 if (paramTagsSize == 0) {
289                         if (reportMissing) {
290                                 for (int i = 0; i < argumentsSize; i++) {
291                                         Argument arg = md.arguments[i];
292                                         methScope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, md.binding.modifiers);
293                                 }
294                         }
295                 } else {
296                         LocalVariableBinding[] bindings = new LocalVariableBinding[paramTagsSize];
297                         int maxBindings = 0;
298
299                         // Scan all @param tags
300                         for (int i = 0; i < paramTagsSize; i++) {
301                                 JavadocSingleNameReference param = this.paramReferences[i];
302                                 param.resolve(methScope);
303                                 if (param.binding != null && param.binding.isValidBinding()) {
304                                         // Verify duplicated tags
305                                         boolean found = false;
306                                         for (int j = 0; j < maxBindings && !found; j++) {
307                                                 if (bindings[j] == param.binding) {
308                                                         methScope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, md.binding.modifiers);
309                                                         found = true;
310                                                 }
311                                         }
312                                         if (!found) {
313                                                 bindings[maxBindings++] = (LocalVariableBinding) param.binding;
314                                         }
315                                 }
316                         }
317
318                         // Look for undocumented arguments
319                         if (reportMissing) {
320                                 for (int i = 0; i < argumentsSize; i++) {
321                                         Argument arg = md.arguments[i];
322                                         boolean found = false;
323                                         for (int j = 0; j < maxBindings && !found; j++) {
324                                                 LocalVariableBinding binding = bindings[j];
325                                                 if (arg.binding == binding) {
326                                                         found = true;
327                                                 }
328                                         }
329                                         if (!found) {
330                                                 methScope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, md.binding.modifiers);
331                                         }
332                                 }
333                         }
334                 }
335         }
336
337         /*
338          * Resolve @param tags for type parameters
339          */
340         private void resolveTypeParameterTags(Scope scope, boolean reportMissing) {
341                 int paramTypeParamLength = this.paramTypeParameters == null ? 0 : this.paramTypeParameters.length;
342
343                 // Get declaration infos
344                 TypeDeclaration typeDeclaration = null;
345                 AbstractMethodDeclaration methodDeclaration = null;
346                 TypeVariableBinding[] typeVariables = null;
347                 int modifiers = -1;
348                 switch (scope.kind) {
349                         case Scope.METHOD_SCOPE:
350                                 methodDeclaration = ((MethodScope)scope).referenceMethod();
351                                 // If no referenced method (field initializer for example) then report a problem for each param tag
352                                 if (methodDeclaration == null) {
353                                         for (int i = 0; i < paramTypeParamLength; i++) {
354                                                 JavadocSingleNameReference param = this.paramReferences[i];
355                                                 scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
356                                         }
357                                         return;
358                                 }
359                                 typeVariables = methodDeclaration.binding.typeVariables;
360                                 modifiers = methodDeclaration.binding.modifiers;
361                                 break;
362                         case Scope.CLASS_SCOPE:
363                                 typeDeclaration = ((ClassScope) scope).referenceContext;
364                                 typeVariables = typeDeclaration.binding.typeVariables;
365                                 modifiers = typeDeclaration.binding.modifiers;
366                                 break;
367                 }
368
369                 // If no type variables then report a problem for each param type parameter tag
370                 if (typeVariables == null || typeVariables.length == 0) {
371                         for (int i = 0; i < paramTypeParamLength; i++) {
372                                 JavadocSingleTypeReference param = this.paramTypeParameters[i];
373                                 scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
374                         }
375                         return;
376                 }
377                 
378                 // If no param tags then report a problem for each declaration type parameter
379                 TypeParameter[] parameters = typeDeclaration==null ? methodDeclaration.typeParameters() : typeDeclaration.typeParameters;
380                 int typeParametersLength = parameters == null ? 0 : parameters.length;
381                 if (paramTypeParamLength == 0) {
382                         if (reportMissing) {
383                                 for (int i = 0, l=parameters.length; i<l; i++) {
384                                         scope.problemReporter().javadocMissingParamTag(parameters[i].name, parameters[i].sourceStart, parameters[i].sourceEnd, modifiers);
385                                 }
386                         }
387                 // Otherwise verify that all param tags match type parameters
388                 } else if (typeVariables.length == typeParametersLength) {
389                         TypeVariableBinding[] bindings = new TypeVariableBinding[paramTypeParamLength];
390                         int maxBindings = 0;
391
392                         // Scan all @param tags
393                         for (int i = 0; i < paramTypeParamLength; i++) {
394                                 JavadocSingleTypeReference param = this.paramTypeParameters[i];
395                                 TypeBinding paramBindind = param.internalResolveType(scope);
396                                 if (paramBindind != null && paramBindind.isValidBinding()) {
397                                         if (paramBindind.isTypeVariable()) {
398                                                 // Verify duplicated tags
399                                                 boolean duplicate = false;
400                                                 for (int j = 0; j < maxBindings && !duplicate; j++) {
401                                                         if (bindings[j] == param.resolvedType) {
402                                                                 scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
403                                                                 duplicate = true;
404                                                         }
405                                                 }
406                                                 if (!duplicate) {
407                                                         bindings[maxBindings++] = (TypeVariableBinding) param.resolvedType;
408                                                 }
409                                         } else {
410                                                 scope.problemReporter().javadocUndeclaredParamTagName(param.token, param.sourceStart, param.sourceEnd, modifiers);
411                                         }
412                                 }
413                         }
414
415                         // Look for undocumented type parameters
416                         if (reportMissing) {
417                                 for (int i = 0; i < typeParametersLength; i++) {
418                                         TypeParameter parameter = parameters[i];
419                                         boolean found = false;
420                                         for (int j = 0; j < maxBindings && !found; j++) {
421                                                 if (parameter.binding == bindings[j]) {
422                                                         found = true;
423                                                 }
424                                         }
425                                         if (!found) {
426                                                 scope.problemReporter().javadocMissingParamTag(parameter.name, parameter.sourceStart, parameter.sourceEnd, modifiers);
427                                         }
428                                 }
429                         }
430                 }
431         }
432
433         /*
434          * Resolve @throws/@exception tags while method scope
435          */
436         private void resolveThrowsTags(MethodScope methScope, boolean reportMissing) {
437                 AbstractMethodDeclaration md = methScope.referenceMethod();
438                 int throwsTagsLength = this.exceptionReferences == null ? 0 : this.exceptionReferences.length;
439
440                 // If no referenced method (field initializer for example) then report a problem for each throws tag
441                 if (md == null) {
442                         for (int i = 0; i < throwsTagsLength; i++) {
443                                 TypeReference typeRef = this.exceptionReferences[i];
444                                 int start = typeRef.sourceStart;
445                                 int end = typeRef.sourceEnd;
446                                 if (typeRef instanceof JavadocQualifiedTypeReference) {
447                                         start = ((JavadocQualifiedTypeReference) typeRef).tagSourceStart;
448                                         end = ((JavadocQualifiedTypeReference) typeRef).tagSourceEnd;
449                                 } else if (typeRef instanceof JavadocSingleTypeReference) {
450                                         start = ((JavadocSingleTypeReference) typeRef).tagSourceStart;
451                                         end = ((JavadocSingleTypeReference) typeRef).tagSourceEnd;
452                                 }
453                                 methScope.problemReporter().javadocUnexpectedTag(start, end);
454                         }
455                         return;
456                 }
457
458                 // If no throws tags then report a problem for each method thrown exception
459                 int boundExceptionLength = (md.binding == null || md.binding.thrownExceptions == null) ? 0 : md.binding.thrownExceptions.length;
460                 int thrownExceptionLength = md.thrownExceptions == null ? 0 : md.thrownExceptions.length;
461                 if (throwsTagsLength == 0) {
462                         if (reportMissing) {
463                                 for (int i = 0; i < boundExceptionLength; i++) {
464                                         ReferenceBinding exceptionBinding = md.binding.thrownExceptions[i];
465                                         if (exceptionBinding != null && exceptionBinding.isValidBinding()) { // flag only valid class name
466                                                 int j=i;
467                                                 while (j<thrownExceptionLength && exceptionBinding != md.thrownExceptions[j].resolvedType) j++;
468                                                 if (j<thrownExceptionLength) {
469                                                         methScope.problemReporter().javadocMissingThrowsTag(md.thrownExceptions[j], md.binding.modifiers);
470                                                 }
471                                         }
472                                 }
473                         }
474                 } else {
475                         int maxRef = 0;
476                         TypeReference[] typeReferences = new TypeReference[throwsTagsLength];
477
478                         // Scan all @throws tags
479                         for (int i = 0; i < throwsTagsLength; i++) {
480                                 TypeReference typeRef = this.exceptionReferences[i];
481                                 typeRef.resolve(methScope);
482                                 TypeBinding typeBinding = typeRef.resolvedType;
483
484                                 if (typeBinding != null && typeBinding.isValidBinding() && typeBinding.isClass()) {
485                                         typeReferences[maxRef++] = typeRef;
486                                 }
487                         }
488
489                         // Look for undocumented thrown exception
490                         for (int i = 0; i < boundExceptionLength; i++) {
491                                 ReferenceBinding exceptionBinding = md.binding.thrownExceptions[i];
492                                 boolean found = false;
493                                 for (int j = 0; j < maxRef && !found; j++) {
494                                         if (typeReferences[j] != null) {
495                                                 TypeBinding typeBinding = typeReferences[j].resolvedType;
496                                                 if (exceptionBinding == typeBinding) {
497                                                         found = true;
498                                                         typeReferences[j] = null;
499                                                 }
500                                         }
501                                 }
502                                 if (!found && reportMissing) {
503                                         if (exceptionBinding != null && exceptionBinding.isValidBinding()) { // flag only valid class name
504                                                 int k=i;
505                                                 while (k<thrownExceptionLength && exceptionBinding != md.thrownExceptions[k].resolvedType) k++;
506                                                 if (k<thrownExceptionLength) {
507                                                         methScope.problemReporter().javadocMissingThrowsTag(md.thrownExceptions[k], md.binding.modifiers);
508                                                 }
509                                         }
510                                 }
511                         }
512
513                         // Verify additional @throws tags
514                         for (int i = 0; i < maxRef; i++) {
515                                 TypeReference typeRef = typeReferences[i];
516                                 if (typeRef != null) {
517                                         boolean compatible = false;
518                                         // thrown exceptions subclasses are accepted
519                                         for (int j = 0; j<thrownExceptionLength && !compatible; j++) {
520                                                 TypeBinding exceptionBinding = md.thrownExceptions[j].resolvedType;
521                                                 if (exceptionBinding != null) {
522                                                         compatible = typeRef.resolvedType.isCompatibleWith(exceptionBinding);
523                                                 }
524                                         }
525                         
526                                         //  If not compatible only complain on unchecked exception
527                                         if (!compatible &&
528                                                  !typeRef.resolvedType.isCompatibleWith(methScope.getJavaLangRuntimeException()) &&
529                                                  !typeRef.resolvedType.isCompatibleWith(methScope.getJavaLangError())) {
530                                                 methScope.problemReporter().javadocInvalidThrowsClassName(typeRef, md.binding.modifiers);
531                                         }
532                                 }
533                         }
534                 }
535         }
536         
537         /*
538          * Search node with a given staring position in javadoc objects arrays.
539          */
540         public ASTNode getNodeStartingAt(int start) {
541                 int length = 0;
542                 // parameters array
543                 if (this.paramReferences != null) {
544                         length = this.paramReferences.length;
545                         for (int i=0; i<length; i++) {
546                                 JavadocSingleNameReference param = this.paramReferences[i];
547                                 if (param.sourceStart==start) {
548                                         return param;
549                                 }
550                         }
551                 }
552                 // array of invalid syntax tags parameters
553                 if (this.invalidParameters != null) {
554                         length = this.invalidParameters.length;
555                         for (int i=0; i<length; i++) {
556                                 JavadocSingleNameReference param = this.invalidParameters[i];
557                                 if (param.sourceStart==start) {
558                                         return param;
559                                 }
560                         }
561                 }
562                 // type parameters array
563                 if (this.paramTypeParameters != null) {
564                         length = this.paramTypeParameters.length;
565                         for (int i=0; i<length; i++) {
566                                 JavadocSingleTypeReference param = this.paramTypeParameters[i];
567                                 if (param.sourceStart==start) {
568                                         return param;
569                                 }
570                         }
571                 }
572                 // thrown exception array
573                 if (this.exceptionReferences != null) {
574                         length = this.exceptionReferences.length;
575                         for (int i=0; i<length; i++) {
576                                 TypeReference typeRef = this.exceptionReferences[i];
577                                 if (typeRef.sourceStart==start) {
578                                         return typeRef;
579                                 }
580                         }
581                 }
582                 // references array
583                 if (this.seeReferences != null) {
584                         length = this.seeReferences.length;
585                         for (int i=0; i<length; i++) {
586                                 org.eclipse.jdt.internal.compiler.ast.Expression expression = this.seeReferences[i];
587                                 if (expression.sourceStart==start) {
588                                         return expression;
589                                 } else if (expression instanceof JavadocAllocationExpression) {
590                                         JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.seeReferences[i];
591                                         // if binding is valid then look at arguments
592                                         if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) {
593                                                 if (allocationExpr.arguments != null) {
594                                                         for (int j=0, l=allocationExpr.arguments.length; j<l; j++) {
595                                                                 if (allocationExpr.arguments[j].sourceStart == start) {
596                                                                         return allocationExpr.arguments[j];
597                                                                 }
598                                                         }
599                                                 }
600                                         }
601                                 } else if (expression instanceof JavadocMessageSend) {
602                                         JavadocMessageSend messageSend = (JavadocMessageSend) this.seeReferences[i];
603                                         // if binding is valid then look at arguments
604                                         if (messageSend.binding != null && messageSend.binding.isValidBinding()) {
605                                                 if (messageSend.arguments != null) {
606                                                         for (int j=0, l=messageSend.arguments.length; j<l; j++) {
607                                                                 if (messageSend.arguments[j].sourceStart == start) {
608                                                                         return messageSend.arguments[j];
609                                                                 }
610                                                         }
611                                                 }
612                                         }
613                                 }
614                         }
615                 }
616                 return null;
617         }
618 }