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