< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java

Print this page

 489         scan(tree.init);
 490         if (isParamOrVar(tree.sym))
 491             refs.replaceExprs(depth, direct -> new VarRef(tree.sym, direct));
 492         else
 493             refs.discardExprs(depth);           // we don't track fields yet
 494     }
 495 
 496 //
 497 // Visitor methods - Methods
 498 //
 499 
 500     @Override
 501     public void visitMethodDef(JCMethodDecl tree) {
 502         Assert.check(false);        // we should never get here
 503     }
 504 
 505     @Override
 506     public void visitApply(JCMethodInvocation invoke) {
 507 
 508         // Get method symbol
 509         MethodSymbol sym = (MethodSymbol)TreeInfo.symbolFor(invoke.meth);
 510 
 511         // Recurse on method expression
 512         scan(invoke.meth);
 513         boolean direct = refs.remove(ExprRef.direct(depth));
 514         boolean indirect = refs.remove(ExprRef.indirect(depth));
 515 
 516         // Determine if method receiver represents a possible reference
 517         RefSet<ThisRef> receiverRefs = RefSet.newEmpty();
 518         if (sym != null && !sym.isStatic()) {
 519             if (direct)
 520                 receiverRefs.add(ThisRef.direct());
 521             if (indirect)
 522                 receiverRefs.add(ThisRef.indirect());
 523         }
 524 
 525         // If "super()": ignore - we don't try to track into superclasses
 526         if (TreeInfo.name(invoke.meth) == names._super)
 527             return;
 528 
 529         // "Invoke" the method
 530         invoke(invoke, sym, invoke.args, receiverRefs);
 531     }
 532 
 533     private void invoke(JCTree site, MethodSymbol sym, List<JCExpression> args, RefSet<?> receiverRefs) {
 534 
 535         // Skip if ignoring warnings for a constructor invoked via 'this()'
 536         if (suppressed.contains(sym))
 537             return;
 538 
 539         // Ignore final methods in java.lang.Object (getClass(), notify(), etc.)
 540         if (sym != null &&
 541             sym.owner.kind == TYP &&
 542             sym.owner.type.tsym == syms.objectType.tsym &&
 543             sym.isFinal()) {
 544             return;
 545         }
 546 
 547         // Analyze method if possible, otherwise assume nothing
 548         MethodInfo methodInfo = methodMap.get(sym);
 549         if (methodInfo != null && methodInfo.invokable())
 550             invokeInvokable(site, args, receiverRefs, methodInfo);
 551         else
 552             invokeUnknown(site, args, receiverRefs);
 553     }

 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) {

1141         pendingWarning = callStack.toArray(new DiagnosticPosition[0]);
1142         callStack.pop();
1143     }
1144 
1145     // Copy pending warning, if any, to the warning list and reset
1146     private boolean copyPendingWarning() {
1147         if (pendingWarning == null)
1148             return false;
1149         warningList.add(pendingWarning);
1150         pendingWarning = null;
1151         return true;
1152     }
1153 
1154     // Does the symbol correspond to a parameter or local variable (not a field)?
1155     private boolean isParamOrVar(Symbol sym) {
1156         return sym != null &&
1157             sym.kind == VAR &&
1158             (sym.owner.kind == MTH || sym.owner.kind == VAR);
1159     }
1160 
1161     /** Check if the given tree is an explicit reference to the 'this' instance of the
1162      *  class currently being compiled. This is true if tree is:
1163      *  - An unqualified 'this' identifier
1164      *  - A 'super' identifier qualified by a class name whose type is 'currentClass' or a supertype
1165      *  - A 'this' identifier qualified by a class name whose type is 'currentClass' or a supertype
1166      *    but also NOT an enclosing outer class of 'currentClass'.
1167      */
1168     private boolean isExplicitThisReference(Types types, Type.ClassType currentClass, JCTree tree) {
1169         switch (tree.getTag()) {
1170             case PARENS:
1171                 return isExplicitThisReference(types, currentClass, TreeInfo.skipParens(tree));
1172             case IDENT:
1173             {
1174                 JCIdent ident = (JCIdent)tree;
1175                 Names names = ident.name.table.names;
1176                 return ident.name == names._this;
1177             }
1178             case SELECT:
1179             {
1180                 JCFieldAccess select = (JCFieldAccess)tree;
1181                 Type selectedType = types.erasure(select.selected.type);
1182                 if (!selectedType.hasTag(CLASS))
1183                     return false;
1184                 ClassSymbol currentClassSym = (ClassSymbol)((Type.ClassType)types.erasure(currentClass)).tsym;
1185                 ClassSymbol selectedClassSym = (ClassSymbol)((Type.ClassType)selectedType).tsym;
1186                 Names names = select.name.table.names;
1187                 return currentClassSym.isSubClass(selectedClassSym, types) &&
1188                         (select.name == names._super ||
1189                         (select.name == names._this &&
1190                             (currentClassSym == selectedClassSym ||
1191                             !currentClassSym.isEnclosedBy(selectedClassSym))));
1192             }
1193             default:
1194                 return false;
1195         }
1196     }
1197 
1198     // When scanning nodes we can be in one of two modes:
1199     //  (a) Looking for constructors - we do not recurse into any code blocks
1200     //  (b) Analyzing a constructor - we are tracing its possible execution paths
1201     private boolean isAnalyzing() {
1202         return targetClass != null;
1203     }
1204 
1205 // Debugging
1206 
1207     // Invariant checks
1208     private boolean checkInvariants(boolean analyzing, boolean allowExpr) {
1209         Assert.check(analyzing == isAnalyzing());
1210         if (isAnalyzing()) {
1211             Assert.check(methodClass != null);
1212             Assert.check(targetClass != null);
1213             Assert.check(refs != null);
1214             Assert.check(depth >= 0);
1215             Assert.check(refs.stream().noneMatch(ref -> ref.getDepth() > depth));
1216             Assert.check(allowExpr || !refs.contains(ExprRef.direct(depth)));
1217             Assert.check(allowExpr || !refs.contains(ExprRef.indirect(depth)));

 489         scan(tree.init);
 490         if (isParamOrVar(tree.sym))
 491             refs.replaceExprs(depth, direct -> new VarRef(tree.sym, direct));
 492         else
 493             refs.discardExprs(depth);           // we don't track fields yet
 494     }
 495 
 496 //
 497 // Visitor methods - Methods
 498 //
 499 
 500     @Override
 501     public void visitMethodDef(JCMethodDecl tree) {
 502         Assert.check(false);        // we should never get here
 503     }
 504 
 505     @Override
 506     public void visitApply(JCMethodInvocation invoke) {
 507 
 508         // Get method symbol
 509         Symbol sym = TreeInfo.symbolFor(invoke.meth);
 510 
 511         // Recurse on method expression
 512         scan(invoke.meth);
 513         boolean direct = refs.remove(ExprRef.direct(depth));
 514         boolean indirect = refs.remove(ExprRef.indirect(depth));
 515 
 516         // Determine if method receiver represents a possible reference
 517         RefSet<ThisRef> receiverRefs = RefSet.newEmpty();
 518         if (sym != null && !sym.isStatic()) {
 519             if (direct)
 520                 receiverRefs.add(ThisRef.direct());
 521             if (indirect)
 522                 receiverRefs.add(ThisRef.indirect());
 523         }
 524 
 525         // If "super()": ignore - we don't try to track into superclasses
 526         if (TreeInfo.name(invoke.meth) == names._super)
 527             return;
 528 
 529         // "Invoke" the method
 530         invoke(invoke, sym, invoke.args, receiverRefs);
 531     }
 532 
 533     private void invoke(JCTree site, Symbol sym, List<JCExpression> args, RefSet<?> receiverRefs) {
 534 
 535         // Skip if ignoring warnings for a constructor invoked via 'this()'
 536         if (suppressed.contains(sym))
 537             return;
 538 
 539         // Ignore final methods in java.lang.Object (getClass(), notify(), etc.)
 540         if (sym != null &&
 541             sym.owner.kind == TYP &&
 542             sym.owner.type.tsym == syms.objectType.tsym &&
 543             sym.isFinal()) {
 544             return;
 545         }
 546 
 547         // Analyze method if possible, otherwise assume nothing
 548         MethodInfo methodInfo = methodMap.get(sym);
 549         if (methodInfo != null && methodInfo.invokable())
 550             invokeInvokable(site, args, receiverRefs, methodInfo);
 551         else
 552             invokeUnknown(site, args, receiverRefs);
 553     }

 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) {

1141         pendingWarning = callStack.toArray(new DiagnosticPosition[0]);
1142         callStack.pop();
1143     }
1144 
1145     // Copy pending warning, if any, to the warning list and reset
1146     private boolean copyPendingWarning() {
1147         if (pendingWarning == null)
1148             return false;
1149         warningList.add(pendingWarning);
1150         pendingWarning = null;
1151         return true;
1152     }
1153 
1154     // Does the symbol correspond to a parameter or local variable (not a field)?
1155     private boolean isParamOrVar(Symbol sym) {
1156         return sym != null &&
1157             sym.kind == VAR &&
1158             (sym.owner.kind == MTH || sym.owner.kind == VAR);
1159     }
1160 





































1161     // When scanning nodes we can be in one of two modes:
1162     //  (a) Looking for constructors - we do not recurse into any code blocks
1163     //  (b) Analyzing a constructor - we are tracing its possible execution paths
1164     private boolean isAnalyzing() {
1165         return targetClass != null;
1166     }
1167 
1168 // Debugging
1169 
1170     // Invariant checks
1171     private boolean checkInvariants(boolean analyzing, boolean allowExpr) {
1172         Assert.check(analyzing == isAnalyzing());
1173         if (isAnalyzing()) {
1174             Assert.check(methodClass != null);
1175             Assert.check(targetClass != null);
1176             Assert.check(refs != null);
1177             Assert.check(depth >= 0);
1178             Assert.check(refs.stream().noneMatch(ref -> ref.getDepth() > depth));
1179             Assert.check(allowExpr || !refs.contains(ExprRef.direct(depth)));
1180             Assert.check(allowExpr || !refs.contains(ExprRef.indirect(depth)));
< prev index next >