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