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.coding;
21
22 import java.util.ArrayDeque;
23 import java.util.BitSet;
24 import java.util.Deque;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.LinkedList;
28 import java.util.Map;
29 import java.util.Queue;
30 import java.util.Set;
31
32 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
33 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
34 import com.puppycrawl.tools.checkstyle.api.DetailAST;
35 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
37 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
38 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 @FileStatefulCheck
108 public class RequireThisCheck extends AbstractCheck {
109
110
111
112
113
114 public static final String MSG_METHOD = "require.this.method";
115
116
117
118
119 public static final String MSG_VARIABLE = "require.this.variable";
120
121
122 private static final BitSet DECLARATION_TOKENS = TokenUtil.asBitSet(
123 TokenTypes.VARIABLE_DEF,
124 TokenTypes.CTOR_DEF,
125 TokenTypes.METHOD_DEF,
126 TokenTypes.CLASS_DEF,
127 TokenTypes.ENUM_DEF,
128 TokenTypes.ANNOTATION_DEF,
129 TokenTypes.INTERFACE_DEF,
130 TokenTypes.PARAMETER_DEF,
131 TokenTypes.TYPE_ARGUMENT,
132 TokenTypes.RECORD_DEF,
133 TokenTypes.RECORD_COMPONENT_DEF,
134 TokenTypes.RESOURCE
135 );
136
137 private static final BitSet ASSIGN_TOKENS = TokenUtil.asBitSet(
138 TokenTypes.ASSIGN,
139 TokenTypes.PLUS_ASSIGN,
140 TokenTypes.STAR_ASSIGN,
141 TokenTypes.DIV_ASSIGN,
142 TokenTypes.MOD_ASSIGN,
143 TokenTypes.SR_ASSIGN,
144 TokenTypes.BSR_ASSIGN,
145 TokenTypes.SL_ASSIGN,
146 TokenTypes.BAND_ASSIGN,
147 TokenTypes.BXOR_ASSIGN
148 );
149
150 private static final BitSet COMPOUND_ASSIGN_TOKENS = TokenUtil.asBitSet(
151 TokenTypes.PLUS_ASSIGN,
152 TokenTypes.STAR_ASSIGN,
153 TokenTypes.DIV_ASSIGN,
154 TokenTypes.MOD_ASSIGN,
155 TokenTypes.SR_ASSIGN,
156 TokenTypes.BSR_ASSIGN,
157 TokenTypes.SL_ASSIGN,
158 TokenTypes.BAND_ASSIGN,
159 TokenTypes.BXOR_ASSIGN
160 );
161
162
163 private final Deque<AbstractFrame> current = new ArrayDeque<>();
164
165
166 private Map<DetailAST, AbstractFrame> frames;
167
168
169 private boolean checkFields = true;
170
171 private boolean checkMethods = true;
172
173 private boolean validateOnlyOverlapping = true;
174
175
176
177
178
179
180
181 public void setCheckFields(boolean checkFields) {
182 this.checkFields = checkFields;
183 }
184
185
186
187
188
189
190
191 public void setCheckMethods(boolean checkMethods) {
192 this.checkMethods = checkMethods;
193 }
194
195
196
197
198
199
200
201 public void setValidateOnlyOverlapping(boolean validateOnlyOverlapping) {
202 this.validateOnlyOverlapping = validateOnlyOverlapping;
203 }
204
205 @Override
206 public int[] getDefaultTokens() {
207 return getRequiredTokens();
208 }
209
210 @Override
211 public int[] getRequiredTokens() {
212 return new int[] {
213 TokenTypes.CLASS_DEF,
214 TokenTypes.INTERFACE_DEF,
215 TokenTypes.ENUM_DEF,
216 TokenTypes.ANNOTATION_DEF,
217 TokenTypes.CTOR_DEF,
218 TokenTypes.METHOD_DEF,
219 TokenTypes.LITERAL_FOR,
220 TokenTypes.SLIST,
221 TokenTypes.IDENT,
222 TokenTypes.RECORD_DEF,
223 TokenTypes.COMPACT_CTOR_DEF,
224 TokenTypes.LITERAL_TRY,
225 TokenTypes.RESOURCE,
226 };
227 }
228
229 @Override
230 public int[] getAcceptableTokens() {
231 return getRequiredTokens();
232 }
233
234 @Override
235 public void beginTree(DetailAST rootAST) {
236 frames = new HashMap<>();
237 current.clear();
238
239 final Deque<AbstractFrame> frameStack = new LinkedList<>();
240 DetailAST curNode = rootAST;
241 while (curNode != null) {
242 collectDeclarations(frameStack, curNode);
243 DetailAST toVisit = curNode.getFirstChild();
244 while (curNode != null && toVisit == null) {
245 endCollectingDeclarations(frameStack, curNode);
246 toVisit = curNode.getNextSibling();
247 curNode = curNode.getParent();
248 }
249 curNode = toVisit;
250 }
251 }
252
253 @Override
254 public void visitToken(DetailAST ast) {
255 switch (ast.getType()) {
256 case TokenTypes.IDENT:
257 processIdent(ast);
258 break;
259 case TokenTypes.CLASS_DEF:
260 case TokenTypes.INTERFACE_DEF:
261 case TokenTypes.ENUM_DEF:
262 case TokenTypes.ANNOTATION_DEF:
263 case TokenTypes.SLIST:
264 case TokenTypes.METHOD_DEF:
265 case TokenTypes.CTOR_DEF:
266 case TokenTypes.LITERAL_FOR:
267 case TokenTypes.RECORD_DEF:
268 current.push(frames.get(ast));
269 break;
270 case TokenTypes.LITERAL_TRY:
271 if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
272 current.push(frames.get(ast));
273 }
274 break;
275 default:
276 break;
277 }
278 }
279
280 @Override
281 public void leaveToken(DetailAST ast) {
282 switch (ast.getType()) {
283 case TokenTypes.CLASS_DEF:
284 case TokenTypes.INTERFACE_DEF:
285 case TokenTypes.ENUM_DEF:
286 case TokenTypes.ANNOTATION_DEF:
287 case TokenTypes.SLIST:
288 case TokenTypes.METHOD_DEF:
289 case TokenTypes.CTOR_DEF:
290 case TokenTypes.LITERAL_FOR:
291 case TokenTypes.RECORD_DEF:
292 current.pop();
293 break;
294 case TokenTypes.LITERAL_TRY:
295 if (current.peek().getType() == FrameType.TRY_WITH_RESOURCES_FRAME) {
296 current.pop();
297 }
298 break;
299 default:
300 break;
301 }
302 }
303
304
305
306
307
308
309
310 private void processIdent(DetailAST ast) {
311 int parentType = ast.getParent().getType();
312 if (parentType == TokenTypes.EXPR
313 && ast.getParent().getParent().getParent().getType()
314 == TokenTypes.ANNOTATION_FIELD_DEF) {
315 parentType = TokenTypes.ANNOTATION_FIELD_DEF;
316 }
317 switch (parentType) {
318 case TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR:
319 case TokenTypes.ANNOTATION:
320 case TokenTypes.ANNOTATION_FIELD_DEF:
321
322 break;
323 case TokenTypes.METHOD_CALL:
324 if (checkMethods) {
325 final AbstractFrame frame = getMethodWithoutThis(ast);
326 if (frame != null) {
327 logViolation(MSG_METHOD, ast, frame);
328 }
329 }
330 break;
331 default:
332 if (checkFields) {
333 final AbstractFrame frame = getFieldWithoutThis(ast, parentType);
334 final boolean canUseThis = !isInCompactConstructor(ast);
335 if (frame != null && canUseThis) {
336 logViolation(MSG_VARIABLE, ast, frame);
337 }
338 }
339 break;
340 }
341 }
342
343
344
345
346
347
348
349
350 private void logViolation(String msgKey, DetailAST ast, AbstractFrame frame) {
351 if (frame.getFrameName().equals(getNearestClassFrameName())) {
352 log(ast, msgKey, ast.getText(), "");
353 }
354 else if (!(frame instanceof AnonymousClassFrame)) {
355 log(ast, msgKey, ast.getText(), frame.getFrameName() + '.');
356 }
357 }
358
359
360
361
362
363
364
365
366
367
368 private AbstractFrame getFieldWithoutThis(DetailAST ast, int parentType) {
369 final boolean importOrPackage = ScopeUtil.getSurroundingScope(ast) == null;
370 final boolean typeName = parentType == TokenTypes.TYPE
371 || parentType == TokenTypes.LITERAL_NEW;
372 AbstractFrame frame = null;
373
374 if (!importOrPackage
375 && !typeName
376 && !isDeclarationToken(parentType)
377 && !isLambdaParameter(ast)) {
378 final AbstractFrame fieldFrame = findClassFrame(ast, false);
379
380 if (fieldFrame != null && ((ClassFrame) fieldFrame).hasInstanceMember(ast)) {
381 frame = getClassFrameWhereViolationIsFound(ast);
382 }
383 }
384 return frame;
385 }
386
387
388
389
390
391
392
393 private static boolean isInCompactConstructor(DetailAST ast) {
394 boolean isInCompactCtor = false;
395 DetailAST parent = ast;
396 while (parent != null) {
397 if (parent.getType() == TokenTypes.COMPACT_CTOR_DEF) {
398 isInCompactCtor = true;
399 break;
400 }
401 parent = parent.getParent();
402 }
403 return isInCompactCtor;
404 }
405
406
407
408
409
410
411
412
413 private static void collectDeclarations(Deque<AbstractFrame> frameStack, DetailAST ast) {
414 final AbstractFrame frame = frameStack.peek();
415 switch (ast.getType()) {
416 case TokenTypes.VARIABLE_DEF:
417 collectVariableDeclarations(ast, frame);
418 break;
419 case TokenTypes.RECORD_COMPONENT_DEF:
420 final DetailAST componentIdent = ast.findFirstToken(TokenTypes.IDENT);
421 ((ClassFrame) frame).addInstanceMember(componentIdent);
422 break;
423 case TokenTypes.PARAMETER_DEF:
424 if (!CheckUtil.isReceiverParameter(ast)
425 && !isLambdaParameter(ast)) {
426 final DetailAST parameterIdent = ast.findFirstToken(TokenTypes.IDENT);
427 frame.addIdent(parameterIdent);
428 }
429 break;
430 case TokenTypes.RESOURCE:
431 final DetailAST resourceIdent = ast.findFirstToken(TokenTypes.IDENT);
432 if (resourceIdent != null) {
433 frame.addIdent(resourceIdent);
434 }
435 break;
436 case TokenTypes.CLASS_DEF:
437 case TokenTypes.INTERFACE_DEF:
438 case TokenTypes.ENUM_DEF:
439 case TokenTypes.ANNOTATION_DEF:
440 case TokenTypes.RECORD_DEF:
441 final DetailAST classFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
442 frameStack.addFirst(new ClassFrame(frame, classFrameNameIdent));
443 break;
444 case TokenTypes.SLIST:
445 frameStack.addFirst(new BlockFrame(frame, ast));
446 break;
447 case TokenTypes.METHOD_DEF:
448 collectMethodDeclarations(frameStack, ast, frame);
449 break;
450 case TokenTypes.CTOR_DEF:
451 case TokenTypes.COMPACT_CTOR_DEF:
452 final DetailAST ctorFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
453 frameStack.addFirst(new ConstructorFrame(frame, ctorFrameNameIdent));
454 break;
455 case TokenTypes.ENUM_CONSTANT_DEF:
456 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
457 ((ClassFrame) frame).addStaticMember(ident);
458 break;
459 case TokenTypes.LITERAL_CATCH:
460 final AbstractFrame catchFrame = new CatchFrame(frame, ast);
461 frameStack.addFirst(catchFrame);
462 break;
463 case TokenTypes.LITERAL_FOR:
464 final AbstractFrame forFrame = new ForFrame(frame, ast);
465 frameStack.addFirst(forFrame);
466 break;
467 case TokenTypes.LITERAL_NEW:
468 if (isAnonymousClassDef(ast)) {
469 frameStack.addFirst(new AnonymousClassFrame(frame,
470 ast.toString()));
471 }
472 break;
473 case TokenTypes.LITERAL_TRY:
474 if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
475 frameStack.addFirst(new TryWithResourcesFrame(frame, ast));
476 }
477 break;
478 default:
479
480 }
481 }
482
483
484
485
486
487
488
489 private static void collectVariableDeclarations(DetailAST ast, AbstractFrame frame) {
490 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
491 if (frame.getType() == FrameType.CLASS_FRAME) {
492 final DetailAST mods =
493 ast.findFirstToken(TokenTypes.MODIFIERS);
494 if (ScopeUtil.isInInterfaceBlock(ast)
495 || mods.findFirstToken(TokenTypes.LITERAL_STATIC) != null) {
496 ((ClassFrame) frame).addStaticMember(ident);
497 }
498 else {
499 ((ClassFrame) frame).addInstanceMember(ident);
500 }
501 }
502 else {
503 frame.addIdent(ident);
504 }
505 }
506
507
508
509
510
511
512
513
514 private static void collectMethodDeclarations(Deque<AbstractFrame> frameStack,
515 DetailAST ast, AbstractFrame frame) {
516 final DetailAST methodFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
517 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
518 if (mods.findFirstToken(TokenTypes.LITERAL_STATIC) == null) {
519 ((ClassFrame) frame).addInstanceMethod(methodFrameNameIdent);
520 }
521 else {
522 ((ClassFrame) frame).addStaticMethod(methodFrameNameIdent);
523 }
524 frameStack.addFirst(new MethodFrame(frame, methodFrameNameIdent));
525 }
526
527
528
529
530
531
532
533 private void endCollectingDeclarations(Queue<AbstractFrame> frameStack, DetailAST ast) {
534 switch (ast.getType()) {
535 case TokenTypes.CLASS_DEF:
536 case TokenTypes.INTERFACE_DEF:
537 case TokenTypes.ENUM_DEF:
538 case TokenTypes.ANNOTATION_DEF:
539 case TokenTypes.SLIST:
540 case TokenTypes.METHOD_DEF:
541 case TokenTypes.CTOR_DEF:
542 case TokenTypes.LITERAL_CATCH:
543 case TokenTypes.LITERAL_FOR:
544 case TokenTypes.RECORD_DEF:
545 case TokenTypes.COMPACT_CTOR_DEF:
546 frames.put(ast, frameStack.poll());
547 break;
548 case TokenTypes.LITERAL_NEW:
549 if (isAnonymousClassDef(ast)) {
550 frameStack.remove();
551 }
552 break;
553 case TokenTypes.LITERAL_TRY:
554 if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
555 frames.put(ast, frameStack.poll());
556 }
557 break;
558 default:
559
560 }
561 }
562
563
564
565
566
567
568
569 private static boolean isAnonymousClassDef(DetailAST ast) {
570 final DetailAST lastChild = ast.getLastChild();
571 return lastChild != null
572 && lastChild.getType() == TokenTypes.OBJBLOCK;
573 }
574
575
576
577
578
579
580
581
582
583
584 private AbstractFrame getClassFrameWhereViolationIsFound(DetailAST ast) {
585 AbstractFrame frameWhereViolationIsFound = null;
586 final AbstractFrame variableDeclarationFrame = findFrame(ast, false);
587 final FrameType variableDeclarationFrameType = variableDeclarationFrame.getType();
588 final DetailAST prevSibling = ast.getPreviousSibling();
589 if (variableDeclarationFrameType == FrameType.CLASS_FRAME
590 && !validateOnlyOverlapping
591 && (prevSibling == null || !isInExpression(ast))
592 && canBeReferencedFromStaticContext(ast)) {
593 frameWhereViolationIsFound = variableDeclarationFrame;
594 }
595 else if (variableDeclarationFrameType == FrameType.METHOD_FRAME) {
596 if (isOverlappingByArgument(ast)) {
597 if (!isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
598 && !isReturnedVariable(variableDeclarationFrame, ast)
599 && canBeReferencedFromStaticContext(ast)
600 && canAssignValueToClassField(ast)) {
601 frameWhereViolationIsFound = findFrame(ast, true);
602 }
603 }
604 else if (!validateOnlyOverlapping
605 && prevSibling == null
606 && isAssignToken(ast.getParent().getType())
607 && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
608 && canBeReferencedFromStaticContext(ast)
609 && canAssignValueToClassField(ast)) {
610 frameWhereViolationIsFound = findFrame(ast, true);
611 }
612 }
613 else if (variableDeclarationFrameType == FrameType.CTOR_FRAME
614 && isOverlappingByArgument(ast)
615 && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)) {
616 frameWhereViolationIsFound = findFrame(ast, true);
617 }
618 else if (variableDeclarationFrameType == FrameType.BLOCK_FRAME
619 && isOverlappingByLocalVariable(ast)
620 && canAssignValueToClassField(ast)
621 && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
622 && !isReturnedVariable(variableDeclarationFrame, ast)
623 && canBeReferencedFromStaticContext(ast)) {
624 frameWhereViolationIsFound = findFrame(ast, true);
625 }
626 return frameWhereViolationIsFound;
627 }
628
629
630
631
632
633
634
635 private static boolean isInExpression(DetailAST ast) {
636 return TokenTypes.DOT == ast.getParent().getType()
637 || TokenTypes.METHOD_REF == ast.getParent().getType();
638 }
639
640
641
642
643
644
645
646
647
648 private static boolean isUserDefinedArrangementOfThis(AbstractFrame currentFrame,
649 DetailAST ident) {
650 final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
651 final DetailAST definitionToken = blockFrameNameIdent.getParent();
652 final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
653 final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
654
655 boolean userDefinedArrangementOfThis = false;
656
657 final Set<DetailAST> variableUsagesInsideBlock =
658 getAllTokensWhichAreEqualToCurrent(definitionToken, ident,
659 blockEndToken.getLineNo());
660
661 for (DetailAST variableUsage : variableUsagesInsideBlock) {
662 final DetailAST prevSibling = variableUsage.getPreviousSibling();
663 if (prevSibling != null
664 && prevSibling.getType() == TokenTypes.LITERAL_THIS) {
665 userDefinedArrangementOfThis = true;
666 break;
667 }
668 }
669 return userDefinedArrangementOfThis;
670 }
671
672
673
674
675
676
677
678
679 private static DetailAST getBlockEndToken(DetailAST blockNameIdent, DetailAST blockStartToken) {
680 DetailAST blockEndToken = null;
681 final DetailAST blockNameIdentParent = blockNameIdent.getParent();
682 if (blockNameIdentParent.getType() == TokenTypes.CASE_GROUP) {
683 blockEndToken = blockNameIdentParent.getNextSibling();
684 }
685 else {
686 final Set<DetailAST> rcurlyTokens = getAllTokensOfType(blockNameIdent,
687 TokenTypes.RCURLY);
688 for (DetailAST currentRcurly : rcurlyTokens) {
689 final DetailAST parent = currentRcurly.getParent();
690 if (TokenUtil.areOnSameLine(blockStartToken, parent)) {
691 blockEndToken = currentRcurly;
692 }
693 }
694 }
695 return blockEndToken;
696 }
697
698
699
700
701
702
703
704
705 private static boolean isReturnedVariable(AbstractFrame currentFrame, DetailAST ident) {
706 final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
707 final DetailAST definitionToken = blockFrameNameIdent.getParent();
708 final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
709 final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
710
711 final Set<DetailAST> returnsInsideBlock = getAllTokensOfType(definitionToken,
712 TokenTypes.LITERAL_RETURN, blockEndToken.getLineNo());
713
714 return returnsInsideBlock.stream()
715 .anyMatch(returnToken -> isAstInside(returnToken, ident));
716 }
717
718
719
720
721
722
723
724
725 private static boolean isAstInside(DetailAST tree, DetailAST ast) {
726 boolean result = false;
727
728 if (isAstSimilar(tree, ast)) {
729 result = true;
730 }
731 else {
732 for (DetailAST child = tree.getFirstChild(); child != null
733 && !result; child = child.getNextSibling()) {
734 result = isAstInside(child, ast);
735 }
736 }
737
738 return result;
739 }
740
741
742
743
744
745
746
747 private static boolean canBeReferencedFromStaticContext(DetailAST ident) {
748 boolean staticContext = false;
749
750 final DetailAST codeBlockDefinition = getCodeBlockDefinitionToken(ident);
751 if (codeBlockDefinition != null) {
752 final DetailAST modifiers = codeBlockDefinition.getFirstChild();
753 staticContext = codeBlockDefinition.getType() == TokenTypes.STATIC_INIT
754 || modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
755 }
756 return !staticContext;
757 }
758
759
760
761
762
763
764
765
766 private static DetailAST getCodeBlockDefinitionToken(DetailAST ident) {
767 DetailAST parent = ident;
768 while (parent != null
769 && parent.getType() != TokenTypes.METHOD_DEF
770 && parent.getType() != TokenTypes.STATIC_INIT) {
771 parent = parent.getParent();
772 }
773 return parent;
774 }
775
776
777
778
779
780
781
782
783
784 private boolean canAssignValueToClassField(DetailAST ast) {
785 final AbstractFrame fieldUsageFrame = findFrame(ast, false);
786 final boolean fieldUsageInConstructor = isInsideConstructorFrame(fieldUsageFrame);
787
788 final AbstractFrame declarationFrame = findFrame(ast, true);
789 final boolean finalField = ((ClassFrame) declarationFrame).hasFinalField(ast);
790
791 return fieldUsageInConstructor || !finalField;
792 }
793
794
795
796
797
798
799
800 private static boolean isInsideConstructorFrame(AbstractFrame frame) {
801 AbstractFrame fieldUsageFrame = frame;
802 while (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) {
803 fieldUsageFrame = fieldUsageFrame.getParent();
804 }
805 return fieldUsageFrame.getType() == FrameType.CTOR_FRAME;
806 }
807
808
809
810
811
812
813
814 private boolean isOverlappingByArgument(DetailAST ast) {
815 boolean overlapping = false;
816 final DetailAST parent = ast.getParent();
817 final DetailAST sibling = ast.getNextSibling();
818 if (sibling != null && isAssignToken(parent.getType())) {
819 if (isCompoundAssignToken(parent.getType())) {
820 overlapping = true;
821 }
822 else {
823 final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
824 final Set<DetailAST> exprIdents = getAllTokensOfType(sibling, TokenTypes.IDENT);
825 overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
826 }
827 }
828 return overlapping;
829 }
830
831
832
833
834
835
836
837 private boolean isOverlappingByLocalVariable(DetailAST ast) {
838 boolean overlapping = false;
839 final DetailAST parent = ast.getParent();
840 if (isAssignToken(parent.getType())) {
841 final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
842 final Set<DetailAST> exprIdents =
843 getAllTokensOfType(ast.getNextSibling(), TokenTypes.IDENT);
844 overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
845 }
846 return overlapping;
847 }
848
849
850
851
852
853
854
855
856 private static Set<DetailAST> getAllTokensOfType(DetailAST ast, int tokenType) {
857 DetailAST vertex = ast;
858 final Set<DetailAST> result = new HashSet<>();
859 final Deque<DetailAST> stack = new ArrayDeque<>();
860 while (vertex != null || !stack.isEmpty()) {
861 if (!stack.isEmpty()) {
862 vertex = stack.pop();
863 }
864 while (vertex != null) {
865 if (vertex.getType() == tokenType) {
866 result.add(vertex);
867 }
868 if (vertex.getNextSibling() != null) {
869 stack.push(vertex.getNextSibling());
870 }
871 vertex = vertex.getFirstChild();
872 }
873 }
874 return result;
875 }
876
877
878
879
880
881
882
883
884
885
886
887 private static Set<DetailAST> getAllTokensOfType(DetailAST ast, int tokenType,
888 int endLineNumber) {
889 DetailAST vertex = ast;
890 final Set<DetailAST> result = new HashSet<>();
891 final Deque<DetailAST> stack = new ArrayDeque<>();
892 while (vertex != null || !stack.isEmpty()) {
893 if (!stack.isEmpty()) {
894 vertex = stack.pop();
895 }
896 while (vertex != null) {
897 if (tokenType == vertex.getType()
898 && vertex.getLineNo() <= endLineNumber) {
899 result.add(vertex);
900 }
901 if (vertex.getNextSibling() != null) {
902 stack.push(vertex.getNextSibling());
903 }
904 vertex = vertex.getFirstChild();
905 }
906 }
907 return result;
908 }
909
910
911
912
913
914
915
916
917
918
919
920 private static Set<DetailAST> getAllTokensWhichAreEqualToCurrent(DetailAST ast, DetailAST token,
921 int endLineNumber) {
922 DetailAST vertex = ast;
923 final Set<DetailAST> result = new HashSet<>();
924 final Deque<DetailAST> stack = new ArrayDeque<>();
925 while (vertex != null || !stack.isEmpty()) {
926 if (!stack.isEmpty()) {
927 vertex = stack.pop();
928 }
929 while (vertex != null) {
930 if (isAstSimilar(token, vertex)
931 && vertex.getLineNo() <= endLineNumber) {
932 result.add(vertex);
933 }
934 if (vertex.getNextSibling() != null) {
935 stack.push(vertex.getNextSibling());
936 }
937 vertex = vertex.getFirstChild();
938 }
939 }
940 return result;
941 }
942
943
944
945
946
947
948
949
950
951 private AbstractFrame getMethodWithoutThis(DetailAST ast) {
952 AbstractFrame result = null;
953 if (!validateOnlyOverlapping) {
954 final AbstractFrame frame = findFrame(ast, true);
955 if (frame != null
956 && ((ClassFrame) frame).hasInstanceMethod(ast)
957 && !((ClassFrame) frame).hasStaticMethod(ast)) {
958 result = frame;
959 }
960 }
961 return result;
962 }
963
964
965
966
967
968
969
970
971 private AbstractFrame findClassFrame(DetailAST name, boolean lookForMethod) {
972 AbstractFrame frame = current.peek();
973
974 while (true) {
975 frame = findFrame(frame, name, lookForMethod);
976
977 if (frame == null || frame instanceof ClassFrame) {
978 break;
979 }
980
981 frame = frame.getParent();
982 }
983
984 return frame;
985 }
986
987
988
989
990
991
992
993
994 private AbstractFrame findFrame(DetailAST name, boolean lookForMethod) {
995 return findFrame(current.peek(), name, lookForMethod);
996 }
997
998
999
1000
1001
1002
1003
1004
1005
1006 private static AbstractFrame findFrame(AbstractFrame frame, DetailAST name,
1007 boolean lookForMethod) {
1008 return frame.getIfContains(name, lookForMethod);
1009 }
1010
1011
1012
1013
1014
1015
1016
1017 private static boolean isDeclarationToken(int parentType) {
1018 return DECLARATION_TOKENS.get(parentType);
1019 }
1020
1021
1022
1023
1024
1025
1026
1027 private static boolean isAssignToken(int tokenType) {
1028 return ASSIGN_TOKENS.get(tokenType);
1029 }
1030
1031
1032
1033
1034
1035
1036
1037 private static boolean isCompoundAssignToken(int tokenType) {
1038 return COMPOUND_ASSIGN_TOKENS.get(tokenType);
1039 }
1040
1041
1042
1043
1044
1045
1046 private String getNearestClassFrameName() {
1047 AbstractFrame frame = current.peek();
1048 while (frame.getType() != FrameType.CLASS_FRAME) {
1049 frame = frame.getParent();
1050 }
1051 return frame.getFrameName();
1052 }
1053
1054
1055
1056
1057
1058
1059
1060 private static boolean isLambdaParameter(DetailAST ast) {
1061 DetailAST parent;
1062 for (parent = ast; parent != null; parent = parent.getParent()) {
1063 if (parent.getType() == TokenTypes.LAMBDA) {
1064 break;
1065 }
1066 }
1067 final boolean isLambdaParameter;
1068 if (parent == null) {
1069 isLambdaParameter = false;
1070 }
1071 else if (ast.getType() == TokenTypes.PARAMETER_DEF) {
1072 isLambdaParameter = true;
1073 }
1074 else {
1075 final DetailAST lambdaParameters = parent.findFirstToken(TokenTypes.PARAMETERS);
1076 if (lambdaParameters == null) {
1077 isLambdaParameter = parent.getFirstChild().getText().equals(ast.getText());
1078 }
1079 else {
1080 isLambdaParameter = TokenUtil.findFirstTokenByPredicate(lambdaParameters,
1081 paramDef -> {
1082 final DetailAST param = paramDef.findFirstToken(TokenTypes.IDENT);
1083 return param != null && param.getText().equals(ast.getText());
1084 }).isPresent();
1085 }
1086 }
1087 return isLambdaParameter;
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097 private static boolean isAstSimilar(DetailAST left, DetailAST right) {
1098 return left.getType() == right.getType() && left.getText().equals(right.getText());
1099 }
1100
1101
1102 private enum FrameType {
1103
1104
1105 CLASS_FRAME,
1106
1107 CTOR_FRAME,
1108
1109 METHOD_FRAME,
1110
1111 BLOCK_FRAME,
1112
1113 CATCH_FRAME,
1114
1115 FOR_FRAME,
1116
1117 TRY_WITH_RESOURCES_FRAME
1118
1119 }
1120
1121
1122
1123
1124 private abstract static class AbstractFrame {
1125
1126
1127 private final Set<DetailAST> varIdents;
1128
1129
1130 private final AbstractFrame parent;
1131
1132
1133 private final DetailAST frameNameIdent;
1134
1135
1136
1137
1138
1139
1140
1141 protected AbstractFrame(AbstractFrame parent, DetailAST ident) {
1142 this.parent = parent;
1143 frameNameIdent = ident;
1144 varIdents = new HashSet<>();
1145 }
1146
1147
1148
1149
1150
1151
1152 protected abstract FrameType getType();
1153
1154
1155
1156
1157
1158
1159 private void addIdent(DetailAST identToAdd) {
1160 varIdents.add(identToAdd);
1161 }
1162
1163
1164
1165
1166
1167
1168 protected AbstractFrame getParent() {
1169 return parent;
1170 }
1171
1172
1173
1174
1175
1176
1177 protected String getFrameName() {
1178 return frameNameIdent.getText();
1179 }
1180
1181
1182
1183
1184
1185
1186 public DetailAST getFrameNameIdent() {
1187 return frameNameIdent;
1188 }
1189
1190
1191
1192
1193
1194
1195
1196 protected boolean containsFieldOrVariable(DetailAST identToFind) {
1197 return containsFieldOrVariableDef(varIdents, identToFind);
1198 }
1199
1200
1201
1202
1203
1204
1205
1206
1207 protected AbstractFrame getIfContains(DetailAST identToFind, boolean lookForMethod) {
1208 final AbstractFrame frame;
1209
1210 if (!lookForMethod
1211 && containsFieldOrVariable(identToFind)) {
1212 frame = this;
1213 }
1214 else {
1215 frame = parent.getIfContains(identToFind, lookForMethod);
1216 }
1217 return frame;
1218 }
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229 protected boolean containsFieldOrVariableDef(Set<DetailAST> set, DetailAST ident) {
1230 boolean result = false;
1231 for (DetailAST ast: set) {
1232 if (isProperDefinition(ident, ast)) {
1233 result = true;
1234 break;
1235 }
1236 }
1237 return result;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247 protected boolean isProperDefinition(DetailAST ident, DetailAST ast) {
1248 final String identToFind = ident.getText();
1249 return identToFind.equals(ast.getText())
1250 && CheckUtil.isBeforeInSource(ast, ident);
1251 }
1252 }
1253
1254
1255
1256
1257 private static class MethodFrame extends AbstractFrame {
1258
1259
1260
1261
1262
1263
1264
1265 protected MethodFrame(AbstractFrame parent, DetailAST ident) {
1266 super(parent, ident);
1267 }
1268
1269 @Override
1270 protected FrameType getType() {
1271 return FrameType.METHOD_FRAME;
1272 }
1273
1274 }
1275
1276
1277
1278
1279 private static class ConstructorFrame extends AbstractFrame {
1280
1281
1282
1283
1284
1285
1286
1287 protected ConstructorFrame(AbstractFrame parent, DetailAST ident) {
1288 super(parent, ident);
1289 }
1290
1291 @Override
1292 protected FrameType getType() {
1293 return FrameType.CTOR_FRAME;
1294 }
1295
1296 }
1297
1298
1299
1300
1301 private static class ClassFrame extends AbstractFrame {
1302
1303
1304 private final Set<DetailAST> instanceMembers;
1305
1306 private final Set<DetailAST> instanceMethods;
1307
1308 private final Set<DetailAST> staticMembers;
1309
1310 private final Set<DetailAST> staticMethods;
1311
1312
1313
1314
1315
1316
1317
1318 private ClassFrame(AbstractFrame parent, DetailAST ident) {
1319 super(parent, ident);
1320 instanceMembers = new HashSet<>();
1321 instanceMethods = new HashSet<>();
1322 staticMembers = new HashSet<>();
1323 staticMethods = new HashSet<>();
1324 }
1325
1326 @Override
1327 protected FrameType getType() {
1328 return FrameType.CLASS_FRAME;
1329 }
1330
1331
1332
1333
1334
1335
1336 public void addStaticMember(final DetailAST ident) {
1337 staticMembers.add(ident);
1338 }
1339
1340
1341
1342
1343
1344
1345 public void addStaticMethod(final DetailAST ident) {
1346 staticMethods.add(ident);
1347 }
1348
1349
1350
1351
1352
1353
1354 public void addInstanceMember(final DetailAST ident) {
1355 instanceMembers.add(ident);
1356 }
1357
1358
1359
1360
1361
1362
1363 public void addInstanceMethod(final DetailAST ident) {
1364 instanceMethods.add(ident);
1365 }
1366
1367
1368
1369
1370
1371
1372
1373
1374 public boolean hasInstanceMember(final DetailAST ident) {
1375 return containsFieldOrVariableDef(instanceMembers, ident);
1376 }
1377
1378
1379
1380
1381
1382
1383
1384
1385 public boolean hasInstanceMethod(final DetailAST ident) {
1386 return containsMethodDef(instanceMethods, ident);
1387 }
1388
1389
1390
1391
1392
1393
1394
1395
1396 public boolean hasStaticMethod(final DetailAST ident) {
1397 return containsMethodDef(staticMethods, ident);
1398 }
1399
1400
1401
1402
1403
1404
1405
1406 public boolean hasFinalField(final DetailAST instanceMember) {
1407 boolean result = false;
1408 for (DetailAST member : instanceMembers) {
1409 final DetailAST parent = member.getParent();
1410 if (parent.getType() == TokenTypes.RECORD_COMPONENT_DEF) {
1411 result = true;
1412 }
1413 else {
1414 final DetailAST mods = parent.findFirstToken(TokenTypes.MODIFIERS);
1415 final boolean finalMod = mods.findFirstToken(TokenTypes.FINAL) != null;
1416 if (finalMod && isAstSimilar(member, instanceMember)) {
1417 result = true;
1418 }
1419 }
1420 }
1421 return result;
1422 }
1423
1424 @Override
1425 protected boolean containsFieldOrVariable(DetailAST identToFind) {
1426 return containsFieldOrVariableDef(instanceMembers, identToFind)
1427 || containsFieldOrVariableDef(staticMembers, identToFind);
1428 }
1429
1430 @Override
1431 protected boolean isProperDefinition(DetailAST ident, DetailAST ast) {
1432 final String identToFind = ident.getText();
1433 return identToFind.equals(ast.getText());
1434 }
1435
1436 @Override
1437 protected AbstractFrame getIfContains(DetailAST identToFind, boolean lookForMethod) {
1438 AbstractFrame frame = null;
1439
1440 if (containsMethod(identToFind)
1441 || containsFieldOrVariable(identToFind)) {
1442 frame = this;
1443 }
1444 else if (getParent() != null) {
1445 frame = getParent().getIfContains(identToFind, lookForMethod);
1446 }
1447 return frame;
1448 }
1449
1450
1451
1452
1453
1454
1455
1456 private boolean containsMethod(DetailAST methodToFind) {
1457 return containsMethodDef(instanceMethods, methodToFind)
1458 || containsMethodDef(staticMethods, methodToFind);
1459 }
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 private static boolean containsMethodDef(Set<DetailAST> set, DetailAST ident) {
1471 boolean result = false;
1472 for (DetailAST ast: set) {
1473 if (isSimilarSignature(ident, ast)) {
1474 result = true;
1475 break;
1476 }
1477 }
1478 return result;
1479 }
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489 private static boolean isSimilarSignature(DetailAST ident, DetailAST ast) {
1490 boolean result = false;
1491 final DetailAST elistToken = ident.getParent().findFirstToken(TokenTypes.ELIST);
1492 if (elistToken != null && ident.getText().equals(ast.getText())) {
1493 final int paramsNumber =
1494 ast.getParent().findFirstToken(TokenTypes.PARAMETERS).getChildCount();
1495 final int argsNumber = elistToken.getChildCount();
1496 result = paramsNumber == argsNumber;
1497 }
1498 return result;
1499 }
1500
1501 }
1502
1503
1504
1505
1506 private static class AnonymousClassFrame extends ClassFrame {
1507
1508
1509 private final String frameName;
1510
1511
1512
1513
1514
1515
1516
1517 protected AnonymousClassFrame(AbstractFrame parent, String frameName) {
1518 super(parent, null);
1519 this.frameName = frameName;
1520 }
1521
1522 @Override
1523 protected String getFrameName() {
1524 return frameName;
1525 }
1526
1527 }
1528
1529
1530
1531
1532 private static class BlockFrame extends AbstractFrame {
1533
1534
1535
1536
1537
1538
1539
1540 protected BlockFrame(AbstractFrame parent, DetailAST ident) {
1541 super(parent, ident);
1542 }
1543
1544 @Override
1545 protected FrameType getType() {
1546 return FrameType.BLOCK_FRAME;
1547 }
1548
1549 }
1550
1551
1552
1553
1554 private static class CatchFrame extends AbstractFrame {
1555
1556
1557
1558
1559
1560
1561
1562 protected CatchFrame(AbstractFrame parent, DetailAST ident) {
1563 super(parent, ident);
1564 }
1565
1566 @Override
1567 public FrameType getType() {
1568 return FrameType.CATCH_FRAME;
1569 }
1570
1571 @Override
1572 protected AbstractFrame getIfContains(DetailAST identToFind, boolean lookForMethod) {
1573 final AbstractFrame frame;
1574
1575 if (!lookForMethod
1576 && containsFieldOrVariable(identToFind)) {
1577 frame = this;
1578 }
1579 else if (getParent().getType() == FrameType.TRY_WITH_RESOURCES_FRAME) {
1580
1581 frame = getParent().getParent().getIfContains(identToFind, lookForMethod);
1582 }
1583 else {
1584 frame = getParent().getIfContains(identToFind, lookForMethod);
1585 }
1586 return frame;
1587 }
1588
1589 }
1590
1591
1592
1593
1594 private static class ForFrame extends AbstractFrame {
1595
1596
1597
1598
1599
1600
1601
1602 protected ForFrame(AbstractFrame parent, DetailAST ident) {
1603 super(parent, ident);
1604 }
1605
1606 @Override
1607 public FrameType getType() {
1608 return FrameType.FOR_FRAME;
1609 }
1610
1611 }
1612
1613
1614
1615
1616
1617 private static class TryWithResourcesFrame extends AbstractFrame {
1618
1619
1620
1621
1622
1623
1624
1625 protected TryWithResourcesFrame(AbstractFrame parent, DetailAST ident) {
1626 super(parent, ident);
1627 }
1628
1629 @Override
1630 public FrameType getType() {
1631 return FrameType.TRY_WITH_RESOURCES_FRAME;
1632 }
1633
1634 }
1635
1636 }