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.Collections;
24 import java.util.Deque;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Optional;
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.checks.naming.AccessModifierOption;
39 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
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 @FileStatefulCheck
81 public class UnusedLocalVariableCheck extends AbstractCheck {
82
83
84
85
86
87 public static final String MSG_UNUSED_LOCAL_VARIABLE = "unused.local.var";
88
89
90
91
92
93 public static final String MSG_UNUSED_NAMED_LOCAL_VARIABLE = "unused.named.local.var";
94
95
96
97
98 private static final int[] INCREMENT_AND_DECREMENT_TOKENS = {
99 TokenTypes.POST_INC,
100 TokenTypes.POST_DEC,
101 TokenTypes.INC,
102 TokenTypes.DEC,
103 };
104
105
106
107
108 private static final int[] SCOPES = {
109 TokenTypes.SLIST,
110 TokenTypes.LITERAL_FOR,
111 TokenTypes.OBJBLOCK,
112 };
113
114
115
116
117 private static final int[] UNACCEPTABLE_CHILD_OF_DOT = {
118 TokenTypes.DOT,
119 TokenTypes.METHOD_CALL,
120 TokenTypes.LITERAL_NEW,
121 TokenTypes.LITERAL_SUPER,
122 TokenTypes.LITERAL_CLASS,
123 TokenTypes.LITERAL_THIS,
124 };
125
126
127
128
129 private static final int[] UNACCEPTABLE_PARENT_OF_IDENT = {
130 TokenTypes.VARIABLE_DEF,
131 TokenTypes.DOT,
132 TokenTypes.LITERAL_NEW,
133 TokenTypes.PATTERN_VARIABLE_DEF,
134 TokenTypes.METHOD_CALL,
135 TokenTypes.TYPE,
136 };
137
138
139
140
141 private static final int[] ANONYMOUS_CLASS_PARENT_TOKENS = {
142 TokenTypes.METHOD_DEF,
143 TokenTypes.CTOR_DEF,
144 TokenTypes.STATIC_INIT,
145 TokenTypes.INSTANCE_INIT,
146 TokenTypes.COMPACT_CTOR_DEF,
147 };
148
149
150
151
152
153
154
155
156
157 private static final int[] INCREMENT_DECREMENT_VARIABLE_USAGE_TYPES = {
158 TokenTypes.ELIST,
159 TokenTypes.INDEX_OP,
160 TokenTypes.ASSIGN,
161 TokenTypes.LITERAL_SWITCH,
162 };
163
164
165 private static final String PACKAGE_SEPARATOR = ".";
166
167
168
169
170 private final Deque<VariableDesc> variables = new ArrayDeque<>();
171
172
173
174
175
176
177 private final Deque<TypeDeclDesc> typeDeclarations = new ArrayDeque<>();
178
179
180
181
182 private final Map<DetailAST, TypeDeclDesc> typeDeclAstToTypeDeclDesc = new LinkedHashMap<>();
183
184
185
186
187
188 private final Map<DetailAST, TypeDeclDesc> anonInnerAstToTypeDeclDesc = new HashMap<>();
189
190
191
192
193
194 private final Set<DetailAST> anonInnerClassHolders = new HashSet<>();
195
196
197
198
199
200
201 private boolean allowUnnamedVariables = true;
202
203
204
205
206 private String packageName;
207
208
209
210
211 private int depth;
212
213
214
215
216
217
218
219
220
221 public void setAllowUnnamedVariables(boolean allowUnnamedVariables) {
222 this.allowUnnamedVariables = allowUnnamedVariables;
223 }
224
225 @Override
226 public int[] getDefaultTokens() {
227 return new int[] {
228 TokenTypes.DOT,
229 TokenTypes.VARIABLE_DEF,
230 TokenTypes.IDENT,
231 TokenTypes.SLIST,
232 TokenTypes.LITERAL_FOR,
233 TokenTypes.OBJBLOCK,
234 TokenTypes.CLASS_DEF,
235 TokenTypes.INTERFACE_DEF,
236 TokenTypes.ANNOTATION_DEF,
237 TokenTypes.PACKAGE_DEF,
238 TokenTypes.LITERAL_NEW,
239 TokenTypes.METHOD_DEF,
240 TokenTypes.CTOR_DEF,
241 TokenTypes.STATIC_INIT,
242 TokenTypes.INSTANCE_INIT,
243 TokenTypes.COMPILATION_UNIT,
244 TokenTypes.LAMBDA,
245 TokenTypes.ENUM_DEF,
246 TokenTypes.RECORD_DEF,
247 TokenTypes.COMPACT_CTOR_DEF,
248 };
249 }
250
251 @Override
252 public int[] getAcceptableTokens() {
253 return getDefaultTokens();
254 }
255
256 @Override
257 public int[] getRequiredTokens() {
258 return getDefaultTokens();
259 }
260
261 @Override
262 public void beginTree(DetailAST root) {
263 variables.clear();
264 typeDeclarations.clear();
265 typeDeclAstToTypeDeclDesc.clear();
266 anonInnerAstToTypeDeclDesc.clear();
267 anonInnerClassHolders.clear();
268 packageName = null;
269 depth = 0;
270 }
271
272 @Override
273 public void visitToken(DetailAST ast) {
274 final int type = ast.getType();
275 if (type == TokenTypes.DOT) {
276 visitDotToken(ast, variables);
277 }
278 else if (type == TokenTypes.VARIABLE_DEF && !skipUnnamedVariables(ast)) {
279 visitVariableDefToken(ast);
280 }
281 else if (type == TokenTypes.IDENT) {
282 visitIdentToken(ast, variables);
283 }
284 else if (isInsideLocalAnonInnerClass(ast)) {
285 visitLocalAnonInnerClass(ast);
286 }
287 else if (isNonLocalTypeDeclaration(ast)) {
288 visitNonLocalTypeDeclarationToken(ast);
289 }
290 else if (type == TokenTypes.PACKAGE_DEF) {
291 packageName = CheckUtil.extractQualifiedName(ast.getFirstChild().getNextSibling());
292 }
293 }
294
295 @Override
296 public void leaveToken(DetailAST ast) {
297 if (TokenUtil.isOfType(ast, SCOPES)) {
298 logViolations(ast, variables);
299 }
300 else if (ast.getType() == TokenTypes.COMPILATION_UNIT) {
301 leaveCompilationUnit();
302 }
303 else if (isNonLocalTypeDeclaration(ast)) {
304 depth--;
305 typeDeclarations.pop();
306 }
307 }
308
309
310
311
312
313
314
315 private static void visitDotToken(DetailAST dotAst, Deque<VariableDesc> variablesStack) {
316 if (dotAst.getParent().getType() != TokenTypes.LITERAL_NEW
317 && shouldCheckIdentTokenNestedUnderDot(dotAst)) {
318 final DetailAST identifier = dotAst.findFirstToken(TokenTypes.IDENT);
319 if (identifier != null) {
320 checkIdentifierAst(identifier, variablesStack);
321 }
322 }
323 }
324
325
326
327
328
329
330 private void visitVariableDefToken(DetailAST varDefAst) {
331 addLocalVariables(varDefAst, variables);
332 addInstanceOrClassVar(varDefAst);
333 }
334
335
336
337
338
339
340
341 private static void visitIdentToken(DetailAST identAst, Deque<VariableDesc> variablesStack) {
342 final DetailAST parent = identAst.getParent();
343 final boolean isMethodReferenceMethodName = parent.getType() == TokenTypes.METHOD_REF
344 && parent.getFirstChild() != identAst;
345 final boolean isConstructorReference = parent.getType() == TokenTypes.METHOD_REF
346 && parent.getLastChild().getType() == TokenTypes.LITERAL_NEW;
347 final boolean isNestedClassInitialization =
348 TokenUtil.isOfType(identAst.getNextSibling(), TokenTypes.LITERAL_NEW)
349 && parent.getType() == TokenTypes.DOT;
350
351 if (isNestedClassInitialization || !isMethodReferenceMethodName
352 && !isConstructorReference
353 && !TokenUtil.isOfType(parent, UNACCEPTABLE_PARENT_OF_IDENT)) {
354 checkIdentifierAst(identAst, variablesStack);
355 }
356 }
357
358
359
360
361
362
363 private void visitNonLocalTypeDeclarationToken(DetailAST typeDeclAst) {
364 final String qualifiedName = getQualifiedTypeDeclarationName(typeDeclAst);
365 final TypeDeclDesc currTypeDecl = new TypeDeclDesc(qualifiedName, depth, typeDeclAst);
366 depth++;
367 typeDeclarations.push(currTypeDecl);
368 typeDeclAstToTypeDeclDesc.put(typeDeclAst, currTypeDecl);
369 }
370
371
372
373
374
375
376 private void visitLocalAnonInnerClass(DetailAST literalNewAst) {
377 anonInnerAstToTypeDeclDesc.put(literalNewAst, typeDeclarations.peek());
378 anonInnerClassHolders.add(getBlockContainingLocalAnonInnerClass(literalNewAst));
379 }
380
381
382
383
384
385
386
387
388 private boolean skipUnnamedVariables(DetailAST varDefAst) {
389 final DetailAST ident = varDefAst.findFirstToken(TokenTypes.IDENT);
390 return allowUnnamedVariables && "_".equals(ident.getText());
391 }
392
393
394
395
396
397
398
399
400 private static boolean isInsideLocalAnonInnerClass(DetailAST literalNewAst) {
401 boolean result = false;
402 final DetailAST lastChild = literalNewAst.getLastChild();
403 if (lastChild != null && lastChild.getType() == TokenTypes.OBJBLOCK) {
404 DetailAST currentAst = literalNewAst;
405 while (!TokenUtil.isTypeDeclaration(currentAst.getType())) {
406 if (currentAst.getType() == TokenTypes.SLIST) {
407 result = true;
408 break;
409 }
410 currentAst = currentAst.getParent();
411 }
412 }
413 return result;
414 }
415
416
417
418
419
420
421
422 private void logViolations(DetailAST scopeAst, Deque<VariableDesc> variablesStack) {
423 while (!variablesStack.isEmpty() && variablesStack.peek().getScope() == scopeAst) {
424 final VariableDesc variableDesc = variablesStack.pop();
425 if (!variableDesc.isUsed()
426 && !variableDesc.isInstVarOrClassVar()) {
427 final DetailAST typeAst = variableDesc.getTypeAst();
428 if (allowUnnamedVariables) {
429 log(typeAst, MSG_UNUSED_NAMED_LOCAL_VARIABLE, variableDesc.getName());
430 }
431 else {
432 log(typeAst, MSG_UNUSED_LOCAL_VARIABLE, variableDesc.getName());
433 }
434 }
435 }
436 }
437
438
439
440
441
442
443
444 private void leaveCompilationUnit() {
445 anonInnerClassHolders.forEach(holder -> {
446 iterateOverBlockContainingLocalAnonInnerClass(holder, new ArrayDeque<>());
447 });
448 }
449
450
451
452
453
454
455
456 private static boolean isNonLocalTypeDeclaration(DetailAST typeDeclAst) {
457 return TokenUtil.isTypeDeclaration(typeDeclAst.getType())
458 && typeDeclAst.getParent().getType() != TokenTypes.SLIST;
459 }
460
461
462
463
464
465
466
467 private static DetailAST getBlockContainingLocalAnonInnerClass(DetailAST literalNewAst) {
468 DetailAST currentAst = literalNewAst;
469 DetailAST result = null;
470 DetailAST topMostLambdaAst = null;
471 while (currentAst != null && !TokenUtil.isOfType(currentAst,
472 ANONYMOUS_CLASS_PARENT_TOKENS)) {
473 if (currentAst.getType() == TokenTypes.LAMBDA) {
474 topMostLambdaAst = currentAst;
475 }
476 currentAst = currentAst.getParent();
477 result = currentAst;
478 }
479
480 if (currentAst == null) {
481 result = topMostLambdaAst;
482 }
483 return result;
484 }
485
486
487
488
489
490
491
492
493 private static void addLocalVariables(DetailAST varDefAst, Deque<VariableDesc> variablesStack) {
494 final DetailAST parentAst = varDefAst.getParent();
495 final DetailAST grandParent = parentAst.getParent();
496 final boolean isInstanceVarInInnerClass =
497 grandParent.getType() == TokenTypes.LITERAL_NEW
498 || grandParent.getType() == TokenTypes.CLASS_DEF;
499 if (isInstanceVarInInnerClass
500 || parentAst.getType() != TokenTypes.OBJBLOCK) {
501 final DetailAST ident = varDefAst.findFirstToken(TokenTypes.IDENT);
502 final VariableDesc desc = new VariableDesc(ident.getText(),
503 varDefAst.findFirstToken(TokenTypes.TYPE), findScopeOfVariable(varDefAst));
504 if (isInstanceVarInInnerClass) {
505 desc.registerAsInstOrClassVar();
506 }
507 variablesStack.push(desc);
508 }
509 }
510
511
512
513
514
515
516
517 private void addInstanceOrClassVar(DetailAST varDefAst) {
518 final DetailAST parentAst = varDefAst.getParent();
519 if (isNonLocalTypeDeclaration(parentAst.getParent())
520 && !isPrivateInstanceVariable(varDefAst)) {
521 final DetailAST ident = varDefAst.findFirstToken(TokenTypes.IDENT);
522 final VariableDesc desc = new VariableDesc(ident.getText());
523 typeDeclAstToTypeDeclDesc.get(parentAst.getParent()).addInstOrClassVar(desc);
524 }
525 }
526
527
528
529
530
531
532
533 private static boolean isPrivateInstanceVariable(DetailAST varDefAst) {
534 final AccessModifierOption varAccessModifier =
535 CheckUtil.getAccessModifierFromModifiersToken(varDefAst);
536 return varAccessModifier == AccessModifierOption.PRIVATE;
537 }
538
539
540
541
542
543
544
545 private TypeDeclDesc getSuperClassOfAnonInnerClass(DetailAST literalNewAst) {
546 TypeDeclDesc obtainedClass = null;
547 final String shortNameOfClass = CheckUtil.getShortNameOfAnonInnerClass(literalNewAst);
548 if (packageName != null && shortNameOfClass.startsWith(packageName)) {
549 final Optional<TypeDeclDesc> classWithCompletePackageName =
550 typeDeclAstToTypeDeclDesc.values()
551 .stream()
552 .filter(typeDeclDesc -> {
553 return typeDeclDesc.getQualifiedName().equals(shortNameOfClass);
554 })
555 .findFirst();
556 if (classWithCompletePackageName.isPresent()) {
557 obtainedClass = classWithCompletePackageName.orElseThrow();
558 }
559 }
560 else {
561 final List<TypeDeclDesc> typeDeclWithSameName = typeDeclWithSameName(shortNameOfClass);
562 if (!typeDeclWithSameName.isEmpty()) {
563 obtainedClass = getTheNearestClass(
564 anonInnerAstToTypeDeclDesc.get(literalNewAst).getQualifiedName(),
565 typeDeclWithSameName);
566 }
567 }
568 return obtainedClass;
569 }
570
571
572
573
574
575
576
577
578
579 private void modifyVariablesStack(TypeDeclDesc obtainedClass,
580 Deque<VariableDesc> variablesStack,
581 DetailAST literalNewAst) {
582 if (obtainedClass != null) {
583 final Deque<VariableDesc> instAndClassVarDeque = typeDeclAstToTypeDeclDesc
584 .get(obtainedClass.getTypeDeclAst())
585 .getUpdatedCopyOfVarStack(literalNewAst);
586 instAndClassVarDeque.forEach(variablesStack::push);
587 }
588 }
589
590
591
592
593
594
595
596 private List<TypeDeclDesc> typeDeclWithSameName(String superClassName) {
597 return typeDeclAstToTypeDeclDesc.values().stream()
598 .filter(typeDeclDesc -> {
599 return hasSameNameAsSuperClass(superClassName, typeDeclDesc);
600 })
601 .collect(Collectors.toUnmodifiableList());
602 }
603
604
605
606
607
608
609
610
611
612 private boolean hasSameNameAsSuperClass(String superClassName, TypeDeclDesc typeDeclDesc) {
613 final boolean result;
614 if (packageName == null && typeDeclDesc.getDepth() == 0) {
615 result = typeDeclDesc.getQualifiedName().equals(superClassName);
616 }
617 else {
618 result = typeDeclDesc.getQualifiedName()
619 .endsWith(PACKAGE_SEPARATOR + superClassName);
620 }
621 return result;
622 }
623
624
625
626
627
628
629
630
631
632 private static TypeDeclDesc getTheNearestClass(String outerTypeDeclName,
633 List<TypeDeclDesc> typeDeclWithSameName) {
634 return Collections.min(typeDeclWithSameName, (first, second) -> {
635 return getTypeDeclarationNameMatchingCountDiff(outerTypeDeclName, first, second);
636 });
637 }
638
639
640
641
642
643
644
645
646
647
648 private static int getTypeDeclarationNameMatchingCountDiff(String outerTypeDeclName,
649 TypeDeclDesc firstTypeDecl,
650 TypeDeclDesc secondTypeDecl) {
651 int diff = Integer.compare(
652 CheckUtil.typeDeclarationNameMatchingCount(
653 outerTypeDeclName, secondTypeDecl.getQualifiedName()),
654 CheckUtil.typeDeclarationNameMatchingCount(
655 outerTypeDeclName, firstTypeDecl.getQualifiedName()));
656 if (diff == 0) {
657 diff = Integer.compare(firstTypeDecl.getDepth(), secondTypeDecl.getDepth());
658 }
659 return diff;
660 }
661
662
663
664
665
666
667
668 private String getQualifiedTypeDeclarationName(DetailAST typeDeclAst) {
669 final String className = typeDeclAst.findFirstToken(TokenTypes.IDENT).getText();
670 String outerClassQualifiedName = null;
671 if (!typeDeclarations.isEmpty()) {
672 outerClassQualifiedName = typeDeclarations.peek().getQualifiedName();
673 }
674 return CheckUtil
675 .getQualifiedTypeDeclarationName(packageName, outerClassQualifiedName, className);
676 }
677
678
679
680
681
682
683
684 private void iterateOverBlockContainingLocalAnonInnerClass(
685 DetailAST ast, Deque<VariableDesc> variablesStack) {
686 DetailAST currNode = ast;
687 while (currNode != null) {
688 customVisitToken(currNode, variablesStack);
689 DetailAST toVisit = currNode.getFirstChild();
690 while (currNode != ast && toVisit == null) {
691 customLeaveToken(currNode, variablesStack);
692 toVisit = currNode.getNextSibling();
693 currNode = currNode.getParent();
694 }
695 currNode = toVisit;
696 }
697 }
698
699
700
701
702
703
704
705
706 private void customVisitToken(DetailAST ast, Deque<VariableDesc> variablesStack) {
707 final int type = ast.getType();
708 if (type == TokenTypes.DOT) {
709 visitDotToken(ast, variablesStack);
710 }
711 else if (type == TokenTypes.VARIABLE_DEF) {
712 addLocalVariables(ast, variablesStack);
713 }
714 else if (type == TokenTypes.IDENT) {
715 visitIdentToken(ast, variablesStack);
716 }
717 else if (isInsideLocalAnonInnerClass(ast)) {
718 final TypeDeclDesc obtainedClass = getSuperClassOfAnonInnerClass(ast);
719 modifyVariablesStack(obtainedClass, variablesStack, ast);
720 }
721 }
722
723
724
725
726
727
728
729
730 private void customLeaveToken(DetailAST ast, Deque<VariableDesc> variablesStack) {
731 logViolations(ast, variablesStack);
732 }
733
734
735
736
737
738
739
740 private static boolean shouldCheckIdentTokenNestedUnderDot(DetailAST dotAst) {
741
742 return TokenUtil.findFirstTokenByPredicate(dotAst,
743 childAst -> {
744 return TokenUtil.isOfType(childAst,
745 UNACCEPTABLE_CHILD_OF_DOT);
746 })
747 .isEmpty();
748 }
749
750
751
752
753
754
755
756 private static void checkIdentifierAst(DetailAST identAst, Deque<VariableDesc> variablesStack) {
757 for (VariableDesc variableDesc : variablesStack) {
758 if (identAst.getText().equals(variableDesc.getName())
759 && !isLeftHandSideValue(identAst)) {
760 variableDesc.registerAsUsed();
761 break;
762 }
763 }
764 }
765
766
767
768
769
770
771
772 private static DetailAST findScopeOfVariable(DetailAST variableDef) {
773 final DetailAST result;
774 final DetailAST parentAst = variableDef.getParent();
775 if (TokenUtil.isOfType(parentAst, TokenTypes.SLIST, TokenTypes.OBJBLOCK)) {
776 result = parentAst;
777 }
778 else {
779 result = parentAst.getParent();
780 }
781 return result;
782 }
783
784
785
786
787
788
789
790
791
792
793 private static boolean isLeftHandSideValue(DetailAST identAst) {
794 final DetailAST parent = identAst.getParent();
795 return isStandAloneIncrementOrDecrement(identAst)
796 || parent.getType() == TokenTypes.ASSIGN
797 && identAst != parent.getLastChild();
798 }
799
800
801
802
803
804
805
806
807
808 private static boolean isStandAloneIncrementOrDecrement(DetailAST identAst) {
809 final DetailAST parent = identAst.getParent();
810 final DetailAST grandParent = parent.getParent();
811 return TokenUtil.isOfType(parent, INCREMENT_AND_DECREMENT_TOKENS)
812 && TokenUtil.isOfType(grandParent, TokenTypes.EXPR)
813 && !isIncrementOrDecrementVariableUsed(grandParent);
814 }
815
816
817
818
819
820
821
822
823
824 private static boolean isIncrementOrDecrementVariableUsed(DetailAST exprAst) {
825 return TokenUtil.isOfType(exprAst.getParent(), INCREMENT_DECREMENT_VARIABLE_USAGE_TYPES)
826 && exprAst.getParent().getParent().getType() != TokenTypes.FOR_ITERATOR;
827 }
828
829
830
831
832 private static final class VariableDesc {
833
834
835
836
837 private final String name;
838
839
840
841
842 private final DetailAST typeAst;
843
844
845
846
847
848
849 private final DetailAST scope;
850
851
852
853
854 private boolean instVarOrClassVar;
855
856
857
858
859 private boolean used;
860
861
862
863
864
865
866
867
868
869
870 private VariableDesc(String name, DetailAST typeAst, DetailAST scope) {
871 this.name = name;
872 this.typeAst = typeAst;
873 this.scope = scope;
874 }
875
876
877
878
879
880
881 private VariableDesc(String name) {
882 this(name, null, null);
883 }
884
885
886
887
888
889
890
891
892
893 private VariableDesc(String name, DetailAST scope) {
894 this(name, null, scope);
895 }
896
897
898
899
900
901
902 public String getName() {
903 return name;
904 }
905
906
907
908
909
910
911 public DetailAST getTypeAst() {
912 return typeAst;
913 }
914
915
916
917
918
919
920
921
922 public DetailAST getScope() {
923 return scope;
924 }
925
926
927
928
929 public void registerAsUsed() {
930 used = true;
931 }
932
933
934
935
936
937 public void registerAsInstOrClassVar() {
938 instVarOrClassVar = true;
939 }
940
941
942
943
944
945
946 public boolean isUsed() {
947 return used;
948 }
949
950
951
952
953
954
955 public boolean isInstVarOrClassVar() {
956 return instVarOrClassVar;
957 }
958 }
959
960
961
962
963
964
965
966 private static final class TypeDeclDesc {
967
968
969
970
971 private final String qualifiedName;
972
973
974
975
976 private final int depth;
977
978
979
980
981 private final DetailAST typeDeclAst;
982
983
984
985
986 private final Deque<VariableDesc> instanceAndClassVarStack;
987
988
989
990
991
992
993
994
995 private TypeDeclDesc(String qualifiedName, int depth,
996 DetailAST typeDeclAst) {
997 this.qualifiedName = qualifiedName;
998 this.depth = depth;
999 this.typeDeclAst = typeDeclAst;
1000 instanceAndClassVarStack = new ArrayDeque<>();
1001 }
1002
1003
1004
1005
1006
1007
1008
1009 public String getQualifiedName() {
1010 return qualifiedName;
1011 }
1012
1013
1014
1015
1016
1017
1018 public int getDepth() {
1019 return depth;
1020 }
1021
1022
1023
1024
1025
1026
1027 public DetailAST getTypeDeclAst() {
1028 return typeDeclAst;
1029 }
1030
1031
1032
1033
1034
1035
1036
1037 public Deque<VariableDesc> getUpdatedCopyOfVarStack(DetailAST literalNewAst) {
1038 final DetailAST updatedScope = literalNewAst;
1039 final Deque<VariableDesc> instAndClassVarDeque = new ArrayDeque<>();
1040 instanceAndClassVarStack.forEach(instVar -> {
1041 final VariableDesc variableDesc = new VariableDesc(instVar.getName(),
1042 updatedScope);
1043 variableDesc.registerAsInstOrClassVar();
1044 instAndClassVarDeque.push(variableDesc);
1045 });
1046 return instAndClassVarDeque;
1047 }
1048
1049
1050
1051
1052
1053
1054 public void addInstOrClassVar(VariableDesc variableDesc) {
1055 instanceAndClassVarStack.push(variableDesc);
1056 }
1057 }
1058 }