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