1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.javadoc;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.ListIterator;
29 import java.util.Set;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import com.puppycrawl.tools.checkstyle.api.DetailAST;
34 import com.puppycrawl.tools.checkstyle.api.FileContents;
35 import com.puppycrawl.tools.checkstyle.api.FullIdent;
36 import com.puppycrawl.tools.checkstyle.api.Scope;
37 import com.puppycrawl.tools.checkstyle.api.TextBlock;
38 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
39 import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil;
40 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
41 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
43
44
45
46
47
48
49
50 public class JavadocMethodCheck extends AbstractTypeAwareCheck {
51
52
53
54
55
56 public static final String MSG_JAVADOC_MISSING = "javadoc.missing";
57
58
59
60
61
62 public static final String MSG_CLASS_INFO = "javadoc.classInfo";
63
64
65
66
67
68 public static final String MSG_UNUSED_TAG_GENERAL = "javadoc.unusedTagGeneral";
69
70
71
72
73
74 public static final String MSG_INVALID_INHERIT_DOC = "javadoc.invalidInheritDoc";
75
76
77
78
79
80 public static final String MSG_UNUSED_TAG = "javadoc.unusedTag";
81
82
83
84
85
86 public static final String MSG_EXPECTED_TAG = "javadoc.expectedTag";
87
88
89
90
91
92 public static final String MSG_RETURN_EXPECTED = "javadoc.return.expected";
93
94
95
96
97
98 public static final String MSG_DUPLICATE_TAG = "javadoc.duplicateTag";
99
100
101 private static final Pattern MATCH_JAVADOC_ARG = CommonUtil.createPattern(
102 "^\\s*(?>\\*|\\/\\*\\*)?\\s*@(throws|exception|param)\\s+(\\S+)\\s+\\S*");
103
104
105 private static final Pattern MATCH_JAVADOC_ARG_MULTILINE_START = CommonUtil.createPattern(
106 "^\\s*(?>\\*|\\/\\*\\*)?\\s*@(throws|exception|param)\\s+(\\S+)\\s*$");
107
108
109 private static final Pattern MATCH_JAVADOC_MULTILINE_CONT =
110 CommonUtil.createPattern("(\\*/|@|[^\\s\\*])");
111
112
113 private static final String END_JAVADOC = "*/";
114
115 private static final String NEXT_TAG = "@";
116
117
118 private static final Pattern MATCH_JAVADOC_NOARG =
119 CommonUtil.createPattern("^\\s*(?>\\*|\\/\\*\\*)?\\s*@(return|see)\\s+\\S");
120
121 private static final Pattern MATCH_JAVADOC_NOARG_MULTILINE_START =
122 CommonUtil.createPattern("^\\s*(?>\\*|\\/\\*\\*)?\\s*@(return|see)\\s*$");
123
124 private static final Pattern MATCH_JAVADOC_NOARG_CURLY =
125 CommonUtil.createPattern("\\{\\s*@(inheritDoc)\\s*\\}");
126
127
128 private static final int DEFAULT_MIN_LINE_COUNT = -1;
129
130
131 private Scope scope = Scope.PRIVATE;
132
133
134 private Scope excludeScope;
135
136
137 private int minLineCount = DEFAULT_MIN_LINE_COUNT;
138
139
140
141
142
143
144
145 private boolean allowUndeclaredRTE;
146
147
148
149
150 private boolean validateThrows;
151
152
153
154
155
156 private boolean allowThrowsTagsForSubclasses;
157
158
159
160
161
162 private boolean allowMissingParamTags;
163
164
165
166
167
168
169 private boolean allowMissingThrowsTags;
170
171
172
173
174
175 private boolean allowMissingReturnTag;
176
177
178
179
180
181 private boolean allowMissingJavadoc;
182
183
184
185
186
187 private boolean allowMissingPropertyJavadoc;
188
189
190 private List<String> allowedAnnotations = Collections.singletonList("Override");
191
192
193 private Pattern ignoreMethodNamesRegex;
194
195
196
197
198
199 public void setIgnoreMethodNamesRegex(Pattern pattern) {
200 ignoreMethodNamesRegex = pattern;
201 }
202
203
204
205
206
207 public void setMinLineCount(int value) {
208 minLineCount = value;
209 }
210
211
212
213
214
215 public void setValidateThrows(boolean value) {
216 validateThrows = value;
217 }
218
219
220
221
222
223 public void setAllowedAnnotations(String... userAnnotations) {
224 allowedAnnotations = Arrays.asList(userAnnotations);
225 }
226
227
228
229
230
231
232 public void setScope(Scope scope) {
233 this.scope = scope;
234 }
235
236
237
238
239
240
241 public void setExcludeScope(Scope excludeScope) {
242 this.excludeScope = excludeScope;
243 }
244
245
246
247
248
249
250
251
252
253 public void setAllowUndeclaredRTE(boolean flag) {
254 allowUndeclaredRTE = flag;
255 }
256
257
258
259
260
261
262
263 public void setAllowThrowsTagsForSubclasses(boolean flag) {
264 allowThrowsTagsForSubclasses = flag;
265 }
266
267
268
269
270
271
272
273 public void setAllowMissingParamTags(boolean flag) {
274 allowMissingParamTags = flag;
275 }
276
277
278
279
280
281
282
283
284 public void setAllowMissingThrowsTags(boolean flag) {
285 allowMissingThrowsTags = flag;
286 }
287
288
289
290
291
292
293
294 public void setAllowMissingReturnTag(boolean flag) {
295 allowMissingReturnTag = flag;
296 }
297
298
299
300
301
302
303
304 public void setAllowMissingJavadoc(boolean flag) {
305 allowMissingJavadoc = flag;
306 }
307
308
309
310
311
312
313
314 public void setAllowMissingPropertyJavadoc(final boolean flag) {
315 allowMissingPropertyJavadoc = flag;
316 }
317
318 @Override
319 public int[] getDefaultTokens() {
320 return getAcceptableTokens();
321 }
322
323 @Override
324 public int[] getAcceptableTokens() {
325 return new int[] {
326 TokenTypes.PACKAGE_DEF,
327 TokenTypes.IMPORT,
328 TokenTypes.CLASS_DEF,
329 TokenTypes.ENUM_DEF,
330 TokenTypes.INTERFACE_DEF,
331 TokenTypes.METHOD_DEF,
332 TokenTypes.CTOR_DEF,
333 TokenTypes.ANNOTATION_FIELD_DEF,
334 };
335 }
336
337 @Override
338 protected final void processAST(DetailAST ast) {
339 final Scope theScope = calculateScope(ast);
340 if (shouldCheck(ast, theScope)) {
341 final FileContents contents = getFileContents();
342 final TextBlock textBlock = contents.getJavadocBefore(ast.getLineNo());
343
344 if (textBlock == null) {
345 if (!isMissingJavadocAllowed(ast)) {
346 log(ast, MSG_JAVADOC_MISSING);
347 }
348 }
349 else {
350 checkComment(ast, textBlock);
351 }
352 }
353 }
354
355
356
357
358
359
360 private static int getMethodsNumberOfLine(DetailAST methodDef) {
361 final int numberOfLines;
362 final DetailAST lcurly = methodDef.getLastChild();
363 final DetailAST rcurly = lcurly.getLastChild();
364
365 if (lcurly.getFirstChild() == rcurly) {
366 numberOfLines = 1;
367 }
368 else {
369 numberOfLines = rcurly.getLineNo() - lcurly.getLineNo() - 1;
370 }
371 return numberOfLines;
372 }
373
374 @Override
375 protected final void logLoadError(Token ident) {
376 logLoadErrorImpl(ident.getLineNo(), ident.getColumnNo(),
377 MSG_CLASS_INFO,
378 JavadocTagInfo.THROWS.getText(), ident.getText());
379 }
380
381
382
383
384
385
386 private boolean isMissingJavadocAllowed(final DetailAST ast) {
387 return allowMissingJavadoc
388 || allowMissingPropertyJavadoc
389 && (CheckUtil.isSetterMethod(ast) || CheckUtil.isGetterMethod(ast))
390 || matchesSkipRegex(ast)
391 || isContentsAllowMissingJavadoc(ast);
392 }
393
394
395
396
397
398
399
400
401 private boolean isContentsAllowMissingJavadoc(DetailAST ast) {
402 return (ast.getType() == TokenTypes.METHOD_DEF || ast.getType() == TokenTypes.CTOR_DEF)
403 && (getMethodsNumberOfLine(ast) <= minLineCount
404 || AnnotationUtil.containsAnnotation(ast, allowedAnnotations));
405 }
406
407
408
409
410
411
412
413 private boolean matchesSkipRegex(DetailAST methodDef) {
414 boolean result = false;
415 if (ignoreMethodNamesRegex != null) {
416 final DetailAST ident = methodDef.findFirstToken(TokenTypes.IDENT);
417 final String methodName = ident.getText();
418
419 final Matcher matcher = ignoreMethodNamesRegex.matcher(methodName);
420 if (matcher.matches()) {
421 result = true;
422 }
423 }
424 return result;
425 }
426
427
428
429
430
431
432
433
434 private boolean shouldCheck(final DetailAST ast, final Scope nodeScope) {
435 final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast);
436
437 return (excludeScope == null
438 || nodeScope != excludeScope
439 && surroundingScope != excludeScope)
440 && nodeScope.isIn(scope)
441 && surroundingScope.isIn(scope);
442 }
443
444
445
446
447
448
449
450 private void checkComment(DetailAST ast, TextBlock comment) {
451 final List<JavadocTag> tags = getMethodTags(comment);
452
453 if (!hasShortCircuitTag(ast, tags)) {
454 if (ast.getType() == TokenTypes.ANNOTATION_FIELD_DEF) {
455 checkReturnTag(tags, ast.getLineNo(), true);
456 }
457 else {
458 final Iterator<JavadocTag> it = tags.iterator();
459
460 boolean hasInheritDocTag = false;
461 while (!hasInheritDocTag && it.hasNext()) {
462 hasInheritDocTag = it.next().isInheritDocTag();
463 }
464 final boolean reportExpectedTags = !hasInheritDocTag
465 && !AnnotationUtil.containsAnnotation(ast, allowedAnnotations);
466
467 checkParamTags(tags, ast, reportExpectedTags);
468 checkThrowsTags(tags, getThrows(ast), reportExpectedTags);
469 if (CheckUtil.isNonVoidMethod(ast)) {
470 checkReturnTag(tags, ast.getLineNo(), reportExpectedTags);
471 }
472 }
473
474
475 tags.stream().filter(javadocTag -> !javadocTag.isSeeOrInheritDocTag())
476 .forEach(javadocTag -> log(javadocTag.getLineNo(), MSG_UNUSED_TAG_GENERAL));
477 }
478 }
479
480
481
482
483
484
485
486
487
488 private boolean hasShortCircuitTag(final DetailAST ast, final List<JavadocTag> tags) {
489 boolean result = true;
490
491 if (tags.size() == 1
492 && tags.get(0).isInheritDocTag()) {
493
494 if (!JavadocTagInfo.INHERIT_DOC.isValidOn(ast)) {
495 log(ast, MSG_INVALID_INHERIT_DOC);
496 }
497 }
498 else {
499 result = false;
500 }
501 return result;
502 }
503
504
505
506
507
508
509
510
511
512 private static Scope calculateScope(final DetailAST ast) {
513 final Scope scope;
514
515 if (ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) {
516 scope = Scope.PUBLIC;
517 }
518 else {
519 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
520 scope = ScopeUtil.getScopeFromMods(mods);
521 }
522 return scope;
523 }
524
525
526
527
528
529
530
531
532 private static List<JavadocTag> getMethodTags(TextBlock comment) {
533 final String[] lines = comment.getText();
534 final List<JavadocTag> tags = new ArrayList<>();
535 int currentLine = comment.getStartLineNo() - 1;
536 final int startColumnNumber = comment.getStartColNo();
537
538 for (int i = 0; i < lines.length; i++) {
539 currentLine++;
540 final Matcher javadocArgMatcher =
541 MATCH_JAVADOC_ARG.matcher(lines[i]);
542 final Matcher javadocNoargMatcher =
543 MATCH_JAVADOC_NOARG.matcher(lines[i]);
544 final Matcher noargCurlyMatcher =
545 MATCH_JAVADOC_NOARG_CURLY.matcher(lines[i]);
546 final Matcher argMultilineStart =
547 MATCH_JAVADOC_ARG_MULTILINE_START.matcher(lines[i]);
548 final Matcher noargMultilineStart =
549 MATCH_JAVADOC_NOARG_MULTILINE_START.matcher(lines[i]);
550
551 if (javadocArgMatcher.find()) {
552 final int col = calculateTagColumn(javadocArgMatcher, i, startColumnNumber);
553 tags.add(new JavadocTag(currentLine, col, javadocArgMatcher.group(1),
554 javadocArgMatcher.group(2)));
555 }
556 else if (javadocNoargMatcher.find()) {
557 final int col = calculateTagColumn(javadocNoargMatcher, i, startColumnNumber);
558 tags.add(new JavadocTag(currentLine, col, javadocNoargMatcher.group(1)));
559 }
560 else if (noargCurlyMatcher.find()) {
561 final int col = calculateTagColumn(noargCurlyMatcher, i, startColumnNumber);
562 tags.add(new JavadocTag(currentLine, col, noargCurlyMatcher.group(1)));
563 }
564 else if (argMultilineStart.find()) {
565 final int col = calculateTagColumn(argMultilineStart, i, startColumnNumber);
566 tags.addAll(getMultilineArgTags(argMultilineStart, col, lines, i, currentLine));
567 }
568 else if (noargMultilineStart.find()) {
569 tags.addAll(getMultilineNoArgTags(noargMultilineStart, lines, i, currentLine));
570 }
571 }
572 return tags;
573 }
574
575
576
577
578
579
580
581
582 private static int calculateTagColumn(Matcher javadocTagMatcher,
583 int lineNumber, int startColumnNumber) {
584 int col = javadocTagMatcher.start(1) - 1;
585 if (lineNumber == 0) {
586 col += startColumnNumber;
587 }
588 return col;
589 }
590
591
592
593
594
595
596
597
598
599
600 private static List<JavadocTag> getMultilineArgTags(final Matcher argMultilineStart,
601 final int column, final String[] lines, final int lineIndex, final int tagLine) {
602 final List<JavadocTag> tags = new ArrayList<>();
603 final String param1 = argMultilineStart.group(1);
604 final String param2 = argMultilineStart.group(2);
605 for (int remIndex = lineIndex + 1; remIndex < lines.length; remIndex++) {
606 final Matcher multilineCont = MATCH_JAVADOC_MULTILINE_CONT.matcher(lines[remIndex]);
607 if (multilineCont.find()) {
608 final String lFin = multilineCont.group(1);
609 if (!lFin.equals(NEXT_TAG)
610 && !lFin.equals(END_JAVADOC)) {
611 tags.add(new JavadocTag(tagLine, column, param1, param2));
612 }
613 break;
614 }
615 }
616
617 return tags;
618 }
619
620
621
622
623
624
625
626
627
628 private static List<JavadocTag> getMultilineNoArgTags(final Matcher noargMultilineStart,
629 final String[] lines, final int lineIndex, final int tagLine) {
630 int remIndex = lineIndex;
631 Matcher multilineCont;
632
633 do {
634 remIndex++;
635 multilineCont = MATCH_JAVADOC_MULTILINE_CONT.matcher(lines[remIndex]);
636 } while (!multilineCont.find());
637
638 final List<JavadocTag> tags = new ArrayList<>();
639 final String lFin = multilineCont.group(1);
640 if (!lFin.equals(NEXT_TAG)
641 && !lFin.equals(END_JAVADOC)) {
642 final String param1 = noargMultilineStart.group(1);
643 final int col = noargMultilineStart.start(1) - 1;
644
645 tags.add(new JavadocTag(tagLine, col, param1));
646 }
647
648 return tags;
649 }
650
651
652
653
654
655
656
657 private static List<DetailAST> getParameters(DetailAST ast) {
658 final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
659 final List<DetailAST> returnValue = new ArrayList<>();
660
661 DetailAST child = params.getFirstChild();
662 while (child != null) {
663 if (child.getType() == TokenTypes.PARAMETER_DEF) {
664 final DetailAST ident = child.findFirstToken(TokenTypes.IDENT);
665 if (ident != null) {
666 returnValue.add(ident);
667 }
668 }
669 child = child.getNextSibling();
670 }
671 return returnValue;
672 }
673
674
675
676
677
678
679
680 private List<ExceptionInfo> getThrows(DetailAST ast) {
681 final List<ExceptionInfo> returnValue = new ArrayList<>();
682 final DetailAST throwsAST = ast
683 .findFirstToken(TokenTypes.LITERAL_THROWS);
684 if (throwsAST != null) {
685 DetailAST child = throwsAST.getFirstChild();
686 while (child != null) {
687 if (child.getType() == TokenTypes.IDENT
688 || child.getType() == TokenTypes.DOT) {
689 final FullIdent ident = FullIdent.createFullIdent(child);
690 final ExceptionInfo exceptionInfo = new ExceptionInfo(
691 createClassInfo(new Token(ident), getCurrentClassName()));
692 returnValue.add(exceptionInfo);
693 }
694 child = child.getNextSibling();
695 }
696 }
697 return returnValue;
698 }
699
700
701
702
703
704
705
706
707
708 private void checkParamTags(final List<JavadocTag> tags,
709 final DetailAST parent, boolean reportExpectedTags) {
710 final List<DetailAST> params = getParameters(parent);
711 final List<DetailAST> typeParams = CheckUtil
712 .getTypeParameters(parent);
713
714
715 final ListIterator<JavadocTag> tagIt = tags.listIterator();
716 while (tagIt.hasNext()) {
717 final JavadocTag tag = tagIt.next();
718
719 if (!tag.isParamTag()) {
720 continue;
721 }
722
723 tagIt.remove();
724
725 final String arg1 = tag.getFirstArg();
726 boolean found = removeMatchingParam(params, arg1);
727
728 if (CommonUtil.startsWithChar(arg1, '<') && CommonUtil.endsWithChar(arg1, '>')) {
729 found = searchMatchingTypeParameter(typeParams,
730 arg1.substring(1, arg1.length() - 1));
731 }
732
733
734 if (!found) {
735 log(tag.getLineNo(), tag.getColumnNo(), MSG_UNUSED_TAG,
736 "@param", arg1);
737 }
738 }
739
740
741
742 if (!allowMissingParamTags && reportExpectedTags) {
743 for (DetailAST param : params) {
744 log(param, MSG_EXPECTED_TAG,
745 JavadocTagInfo.PARAM.getText(), param.getText());
746 }
747
748 for (DetailAST typeParam : typeParams) {
749 log(typeParam, MSG_EXPECTED_TAG,
750 JavadocTagInfo.PARAM.getText(),
751 "<" + typeParam.findFirstToken(TokenTypes.IDENT).getText()
752 + ">");
753 }
754 }
755 }
756
757
758
759
760
761
762
763
764
765 private static boolean searchMatchingTypeParameter(List<DetailAST> typeParams,
766 String requiredTypeName) {
767
768 final Iterator<DetailAST> typeParamsIt = typeParams.iterator();
769 boolean found = false;
770 while (typeParamsIt.hasNext()) {
771 final DetailAST typeParam = typeParamsIt.next();
772 if (typeParam.findFirstToken(TokenTypes.IDENT).getText()
773 .equals(requiredTypeName)) {
774 found = true;
775 typeParamsIt.remove();
776 break;
777 }
778 }
779 return found;
780 }
781
782
783
784
785
786
787
788 private static boolean removeMatchingParam(List<DetailAST> params, String paramName) {
789 boolean found = false;
790 final Iterator<DetailAST> paramIt = params.iterator();
791 while (paramIt.hasNext()) {
792 final DetailAST param = paramIt.next();
793 if (param.getText().equals(paramName)) {
794 found = true;
795 paramIt.remove();
796 break;
797 }
798 }
799 return found;
800 }
801
802
803
804
805
806
807
808
809
810
811 private void checkReturnTag(List<JavadocTag> tags, int lineNo,
812 boolean reportExpectedTags) {
813
814
815 boolean found = false;
816 final ListIterator<JavadocTag> it = tags.listIterator();
817 while (it.hasNext()) {
818 final JavadocTag javadocTag = it.next();
819 if (javadocTag.isReturnTag()) {
820 if (found) {
821 log(javadocTag.getLineNo(), javadocTag.getColumnNo(),
822 MSG_DUPLICATE_TAG,
823 JavadocTagInfo.RETURN.getText());
824 }
825 found = true;
826 it.remove();
827 }
828 }
829
830
831
832 if (!found && !allowMissingReturnTag && reportExpectedTags) {
833 log(lineNo, MSG_RETURN_EXPECTED);
834 }
835 }
836
837
838
839
840
841
842
843
844
845 private void checkThrowsTags(List<JavadocTag> tags,
846 List<ExceptionInfo> throwsList, boolean reportExpectedTags) {
847
848
849 final Set<String> foundThrows = new HashSet<>();
850 final ListIterator<JavadocTag> tagIt = tags.listIterator();
851 while (tagIt.hasNext()) {
852 final JavadocTag tag = tagIt.next();
853
854 if (!tag.isThrowsTag()) {
855 continue;
856 }
857 tagIt.remove();
858
859
860 final String documentedEx = tag.getFirstArg();
861 final Token token = new Token(tag.getFirstArg(), tag.getLineNo(), tag
862 .getColumnNo());
863 final AbstractClassInfo documentedClassInfo = createClassInfo(token,
864 getCurrentClassName());
865 final boolean found = foundThrows.contains(documentedEx)
866 || isInThrows(throwsList, documentedClassInfo, foundThrows);
867
868
869 if (!found) {
870 boolean reqd = true;
871 if (allowUndeclaredRTE) {
872 reqd = !isUnchecked(documentedClassInfo.getClazz());
873 }
874
875 if (reqd && validateThrows) {
876 log(tag.getLineNo(), tag.getColumnNo(),
877 MSG_UNUSED_TAG,
878 JavadocTagInfo.THROWS.getText(), tag.getFirstArg());
879 }
880 }
881 }
882
883
884 if (!allowMissingThrowsTags && reportExpectedTags) {
885 throwsList.stream().filter(exceptionInfo -> !exceptionInfo.isFound())
886 .forEach(exceptionInfo -> {
887 final Token token = exceptionInfo.getName();
888 log(token.getLineNo(), token.getColumnNo(),
889 MSG_EXPECTED_TAG,
890 JavadocTagInfo.THROWS.getText(), token.getText());
891 });
892 }
893 }
894
895
896
897
898
899
900
901
902
903 private boolean isInThrows(List<ExceptionInfo> throwsList,
904 AbstractClassInfo documentedClassInfo, Set<String> foundThrows) {
905 boolean found = false;
906 ExceptionInfo foundException = null;
907
908
909 for (ExceptionInfo exceptionInfo : throwsList) {
910 if (exceptionInfo.getName().getText().equals(
911 documentedClassInfo.getName().getText())) {
912 found = true;
913 foundException = exceptionInfo;
914 break;
915 }
916 }
917
918
919 final ListIterator<ExceptionInfo> exceptionInfoIt = throwsList.listIterator();
920 while (!found && exceptionInfoIt.hasNext()) {
921 final ExceptionInfo exceptionInfo = exceptionInfoIt.next();
922
923 if (documentedClassInfo.getClazz() == exceptionInfo.getClazz()) {
924 found = true;
925 foundException = exceptionInfo;
926 }
927 else if (allowThrowsTagsForSubclasses) {
928 found = isSubclass(documentedClassInfo.getClazz(), exceptionInfo.getClazz());
929 }
930 }
931
932 if (foundException != null) {
933 foundException.setFound();
934 foundThrows.add(documentedClassInfo.getName().getText());
935 }
936
937 return found;
938 }
939
940
941 private static class ExceptionInfo {
942
943
944 private final AbstractClassInfo classInfo;
945
946 private boolean found;
947
948
949
950
951
952
953 ExceptionInfo(AbstractClassInfo classInfo) {
954 this.classInfo = classInfo;
955 }
956
957
958 private void setFound() {
959 found = true;
960 }
961
962
963
964
965
966 private boolean isFound() {
967 return found;
968 }
969
970
971
972
973
974 private Token getName() {
975 return classInfo.getName();
976 }
977
978
979
980
981
982 private Class<?> getClazz() {
983 return classInfo.getClazz();
984 }
985
986 }
987
988 }