757 refs.remove(ExprRef.direct(depth));
758 boolean indirectRef = refs.remove(ExprRef.indirect(depth));
759 scan(tree.index);
760 refs.discardExprs(depth);
761 if (indirectRef) {
762 refs.add(ExprRef.direct(depth));
763 refs.add(ExprRef.indirect(depth));
764 }
765 }
766
767 @Override
768 public void visitSelect(JCFieldAccess tree) {
769
770 // Scan the selected thing
771 scan(tree.selected);
772 boolean selectedDirectRef = refs.remove(ExprRef.direct(depth));
773 boolean selectedIndirectRef = refs.remove(ExprRef.indirect(depth));
774
775 // Explicit 'this' reference?
776 Type.ClassType currentClassType = (Type.ClassType)methodClass.sym.type;
777 if (isExplicitThisReference(types, currentClassType, tree)) {
778 refs.mapInto(refs, ThisRef.class, direct -> new ExprRef(depth, direct));
779 return;
780 }
781
782 // Explicit outer 'this' reference?
783 Type selectedType = types.erasure(tree.selected.type);
784 if (selectedType.hasTag(CLASS)) {
785 ClassSymbol currentClassSym = (ClassSymbol)currentClassType.tsym;
786 ClassSymbol selectedTypeSym = (ClassSymbol)selectedType.tsym;
787 if (tree.name == names._this &&
788 selectedTypeSym != currentClassSym &&
789 currentClassSym.isEnclosedBy(selectedTypeSym)) {
790 refs.mapInto(refs, OuterRef.class, direct -> new ExprRef(depth, direct));
791 return;
792 }
793 }
794
795 // Methods - the "value" of a non-static method is a reference to its instance
796 Symbol sym = tree.sym;
797 if (sym.kind == MTH) {
1145 pendingWarning = callStack.toArray(new DiagnosticPosition[0]);
1146 callStack.pop();
1147 }
1148
1149 // Copy pending warning, if any, to the warning list and reset
1150 private boolean copyPendingWarning() {
1151 if (pendingWarning == null)
1152 return false;
1153 warningList.add(pendingWarning);
1154 pendingWarning = null;
1155 return true;
1156 }
1157
1158 // Does the symbol correspond to a parameter or local variable (not a field)?
1159 private boolean isParamOrVar(Symbol sym) {
1160 return sym != null &&
1161 sym.kind == VAR &&
1162 (sym.owner.kind == MTH || sym.owner.kind == VAR);
1163 }
1164
1165 /** Check if the given tree is an explicit reference to the 'this' instance of the
1166 * class currently being compiled. This is true if tree is:
1167 * - An unqualified 'this' identifier
1168 * - A 'super' identifier qualified by a class name whose type is 'currentClass' or a supertype
1169 * - A 'this' identifier qualified by a class name whose type is 'currentClass' or a supertype
1170 * but also NOT an enclosing outer class of 'currentClass'.
1171 */
1172 private boolean isExplicitThisReference(Types types, Type.ClassType currentClass, JCTree tree) {
1173 switch (tree.getTag()) {
1174 case PARENS:
1175 return isExplicitThisReference(types, currentClass, TreeInfo.skipParens(tree));
1176 case IDENT:
1177 {
1178 JCIdent ident = (JCIdent)tree;
1179 Names names = ident.name.table.names;
1180 return ident.name == names._this;
1181 }
1182 case SELECT:
1183 {
1184 JCFieldAccess select = (JCFieldAccess)tree;
1185 Type selectedType = types.erasure(select.selected.type);
1186 if (!selectedType.hasTag(CLASS))
1187 return false;
1188 ClassSymbol currentClassSym = (ClassSymbol)((Type.ClassType)types.erasure(currentClass)).tsym;
1189 ClassSymbol selectedClassSym = (ClassSymbol)((Type.ClassType)selectedType).tsym;
1190 Names names = select.name.table.names;
1191 return currentClassSym.isSubClass(selectedClassSym, types) &&
1192 (select.name == names._super ||
1193 (select.name == names._this &&
1194 (currentClassSym == selectedClassSym ||
1195 !currentClassSym.isEnclosedBy(selectedClassSym))));
1196 }
1197 default:
1198 return false;
1199 }
1200 }
1201
1202 // When scanning nodes we can be in one of two modes:
1203 // (a) Looking for constructors - we do not recurse into any code blocks
1204 // (b) Analyzing a constructor - we are tracing its possible execution paths
1205 private boolean isAnalyzing() {
1206 return targetClass != null;
1207 }
1208
1209 // Debugging
1210
1211 // Invariant checks
1212 private boolean checkInvariants(boolean analyzing, boolean allowExpr) {
1213 Assert.check(analyzing == isAnalyzing());
1214 if (isAnalyzing()) {
1215 Assert.check(methodClass != null);
1216 Assert.check(targetClass != null);
1217 Assert.check(refs != null);
1218 Assert.check(depth >= 0);
1219 Assert.check(refs.stream().noneMatch(ref -> ref.getDepth() > depth));
1220 Assert.check(allowExpr || !refs.contains(ExprRef.direct(depth)));
1221 Assert.check(allowExpr || !refs.contains(ExprRef.indirect(depth)));
|
757 refs.remove(ExprRef.direct(depth));
758 boolean indirectRef = refs.remove(ExprRef.indirect(depth));
759 scan(tree.index);
760 refs.discardExprs(depth);
761 if (indirectRef) {
762 refs.add(ExprRef.direct(depth));
763 refs.add(ExprRef.indirect(depth));
764 }
765 }
766
767 @Override
768 public void visitSelect(JCFieldAccess tree) {
769
770 // Scan the selected thing
771 scan(tree.selected);
772 boolean selectedDirectRef = refs.remove(ExprRef.direct(depth));
773 boolean selectedIndirectRef = refs.remove(ExprRef.indirect(depth));
774
775 // Explicit 'this' reference?
776 Type.ClassType currentClassType = (Type.ClassType)methodClass.sym.type;
777 if (TreeInfo.isExplicitThisReference(types, currentClassType, tree)) {
778 refs.mapInto(refs, ThisRef.class, direct -> new ExprRef(depth, direct));
779 return;
780 }
781
782 // Explicit outer 'this' reference?
783 Type selectedType = types.erasure(tree.selected.type);
784 if (selectedType.hasTag(CLASS)) {
785 ClassSymbol currentClassSym = (ClassSymbol)currentClassType.tsym;
786 ClassSymbol selectedTypeSym = (ClassSymbol)selectedType.tsym;
787 if (tree.name == names._this &&
788 selectedTypeSym != currentClassSym &&
789 currentClassSym.isEnclosedBy(selectedTypeSym)) {
790 refs.mapInto(refs, OuterRef.class, direct -> new ExprRef(depth, direct));
791 return;
792 }
793 }
794
795 // Methods - the "value" of a non-static method is a reference to its instance
796 Symbol sym = tree.sym;
797 if (sym.kind == MTH) {
1145 pendingWarning = callStack.toArray(new DiagnosticPosition[0]);
1146 callStack.pop();
1147 }
1148
1149 // Copy pending warning, if any, to the warning list and reset
1150 private boolean copyPendingWarning() {
1151 if (pendingWarning == null)
1152 return false;
1153 warningList.add(pendingWarning);
1154 pendingWarning = null;
1155 return true;
1156 }
1157
1158 // Does the symbol correspond to a parameter or local variable (not a field)?
1159 private boolean isParamOrVar(Symbol sym) {
1160 return sym != null &&
1161 sym.kind == VAR &&
1162 (sym.owner.kind == MTH || sym.owner.kind == VAR);
1163 }
1164
1165 // When scanning nodes we can be in one of two modes:
1166 // (a) Looking for constructors - we do not recurse into any code blocks
1167 // (b) Analyzing a constructor - we are tracing its possible execution paths
1168 private boolean isAnalyzing() {
1169 return targetClass != null;
1170 }
1171
1172 // Debugging
1173
1174 // Invariant checks
1175 private boolean checkInvariants(boolean analyzing, boolean allowExpr) {
1176 Assert.check(analyzing == isAnalyzing());
1177 if (isAnalyzing()) {
1178 Assert.check(methodClass != null);
1179 Assert.check(targetClass != null);
1180 Assert.check(refs != null);
1181 Assert.check(depth >= 0);
1182 Assert.check(refs.stream().noneMatch(ref -> ref.getDepth() > depth));
1183 Assert.check(allowExpr || !refs.contains(ExprRef.direct(depth)));
1184 Assert.check(allowExpr || !refs.contains(ExprRef.indirect(depth)));
|