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