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