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