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