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