< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java

Print this page
*** 48,10 ***
--- 48,11 ---
  import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
  
  import javax.lang.model.element.ElementKind;
  import javax.tools.JavaFileObject;
  
+ import java.util.function.Function;
  import java.util.function.Predicate;
  import java.util.function.ToIntFunction;
  
  import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.RIGHT;

*** 111,29 ***
          for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
              if (isConstructor(l.head)) return true;
          return false;
      }
  
-     /** Is there a constructor invocation in the given list of trees?
-      */
-     public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names) {
-         for (JCTree tree : trees) {
-             if (tree.hasTag(EXEC)) {
-                 JCExpressionStatement stat = (JCExpressionStatement)tree;
-                 if (stat.expr.hasTag(APPLY)) {
-                     JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
-                     Name methName = TreeInfo.name(apply.meth);
-                     if (methName == names._this ||
-                         methName == names._super) {
-                         return methName;
-                     }
-                 }
-             }
-         }
-         return names.empty;
-     }
- 
      public static boolean isMultiCatch(JCCatch catchClause) {
          return catchClause.param.vartype.hasTag(TYPEUNION);
      }
  
      /** Is statement an initializer for a synthetic field?
--- 112,10 ---

*** 168,22 ***
              }
          }
          return null;
      }
  
-     /** Is this a call to this or super?
-      */
-     public static boolean isSelfCall(JCTree tree) {
-         Name name = calledMethodName(tree);
-         if (name != null) {
-             Names names = name.table.names;
-             return name==names._this || name==names._super;
-         } else {
-             return false;
-         }
-     }
- 
      /** Is this tree a 'this' identifier?
       */
      public static boolean isThisQualifier(JCTree tree) {
          switch (tree.getTag()) {
              case PARENS:
--- 150,10 ---

*** 210,10 ***
--- 180,45 ---
              default:
                  return false;
          }
      }
  
+     /** Check if the given tree is an explicit reference to the 'this' instance of the
+      *  class currently being compiled. This is true if tree is:
+      *  - An unqualified 'this' identifier
+      *  - A 'super' identifier qualified by a class name whose type is 'currentClass' or a supertype
+      *  - A 'this' identifier qualified by a class name whose type is 'currentClass' or a supertype
+      *    but also NOT an enclosing outer class of 'currentClass'.
+      */
+     public static boolean isExplicitThisReference(Types types, Type.ClassType currentClass, JCTree tree) {
+         switch (tree.getTag()) {
+             case PARENS:
+                 return isExplicitThisReference(types, currentClass, skipParens(tree));
+             case IDENT: {
+                 JCIdent ident = (JCIdent)tree;
+                 Names names = ident.name.table.names;
+                 return ident.name == names._this || ident.name == names._super;
+             }
+             case SELECT: {
+                 JCFieldAccess select = (JCFieldAccess)tree;
+                 Type selectedType = types.erasure(select.selected.type);
+                 if (!selectedType.hasTag(TypeTag.CLASS))
+                     return false;
+                 Symbol.ClassSymbol currentClassSym = (Symbol.ClassSymbol)((Type.ClassType)types.erasure(currentClass)).tsym;
+                 Symbol.ClassSymbol selectedClassSym = (Symbol.ClassSymbol)((Type.ClassType)selectedType).tsym;
+                 Names names = select.name.table.names;
+                 return currentClassSym.isSubClass(selectedClassSym, types) &&
+                         (select.name == names._super ||
+                                 (select.name == names._this &&
+                                         (currentClassSym == selectedClassSym ||
+                                                 !currentClassSym.isEnclosedBy(selectedClassSym))));
+             }
+             default:
+                 return false;
+         }
+     }
+ 
      /** Is this a call to super?
       */
      public static boolean isSuperCall(JCTree tree) {
          Name name = calledMethodName(tree);
          if (name != null) {

*** 236,36 ***
          return recordFields(tree).stream()
                  .map(vd -> vd.type)
                  .collect(List.collector());
      }
  
!     /** Is this a constructor whose first (non-synthetic) statement is not
!      *  of the form this(...)?
       */
!     public static boolean isInitialConstructor(JCTree tree) {
!         JCMethodInvocation app = firstConstructorCall(tree);
!         if (app == null) return false;
!         Name meth = name(app.meth);
-         return meth == null || meth != meth.table.names._this;
      }
  
!     /** Return the first call in a constructor definition. */
!     public static JCMethodInvocation firstConstructorCall(JCTree tree) {
!         if (!tree.hasTag(METHODDEF)) return null;
!         JCMethodDecl md = (JCMethodDecl) tree;
!         Names names = md.name.table.names;
!         if (md.name != names.init) return null;
!         if (md.body == null) return null;
!         List<JCStatement> stats = md.body.stats;
!         // Synthetic initializations can appear before the super call.
!         while (stats.nonEmpty() && isSyntheticInit(stats.head))
!             stats = stats.tail;
!         if (stats.isEmpty()) return null;
!         if (!stats.head.hasTag(EXEC)) return null;
!         JCExpressionStatement exec = (JCExpressionStatement) stats.head;
!         if (!exec.expr.hasTag(APPLY)) return null;
!         return (JCMethodInvocation)exec.expr;
      }
  
      /** Return true if a tree represents a diamond new expr. */
      public static boolean isDiamond(JCTree tree) {
          switch(tree.getTag()) {
--- 241,107 ---
          return recordFields(tree).stream()
                  .map(vd -> vd.type)
                  .collect(List.collector());
      }
  
!     /** Is the given method a constructor containing a super() or this() call?
!       */
+     public static boolean hasAnyConstructorCall(JCMethodDecl tree) {
+         return hasConstructorCall(tree, null);
+     }
+ 
+     /** Is the given method a constructor containing a super() and/or this() call?
+       * The "target" is either names._this, names._super, or null for either/both.
+       */
+     public static boolean hasConstructorCall(JCMethodDecl tree, Name target) {
+         JCMethodInvocation app = findConstructorCall(tree);
+         return app != null && (target == null || target == name(app.meth));
+     }
+ 
+     /** Find the first super() or init() call in the given constructor.
       */
!     public static JCMethodInvocation findConstructorCall(JCMethodDecl md) {
!         if (!TreeInfo.isConstructor(md) || md.body == null)
!             return null;
!         return new ConstructorCallFinder(md.name.table.names).find(md).head;
      }
  
!     /** Finds all calls to this() and/or super() in a given constructor.
!      *  We can't assume they will be "top level" statements, because
!      *  some synthetic calls to super() are added inside { } blocks.
!      *  So we must recurse through the method's entire syntax tree.
!      */
!     private static class ConstructorCallFinder extends TreeScanner {
! 
!         final ListBuffer<JCMethodInvocation> calls = new ListBuffer<>();
!         final Names names;
! 
!         ConstructorCallFinder(Names names) {
!             this.names = names;
!         }
! 
!         List<JCMethodInvocation> find(JCMethodDecl meth) {
!             scan(meth);
+             return calls.toList();
+         }
+ 
+         @Override
+         public void visitApply(JCMethodInvocation invoke) {
+             Name name = TreeInfo.name(invoke.meth);
+             if ((name == names._this || name == names._super))
+                 calls.append(invoke);
+             super.visitApply(invoke);
+         }
+ 
+         @Override
+         public void visitClassDef(JCClassDecl tree) {
+             // don't descend any further
+         }
+ 
+         @Override
+         public void visitLambda(JCLambda tree) {
+             // don't descend any further
+         }
+     }
+ 
+     /** Finds super() invocations and translates them using the given mapping.
+      */
+     public static void mapSuperCalls(JCBlock block, Function<? super JCExpressionStatement, ? extends JCStatement> mapper) {
+         block.stats = block.stats.map(new TreeInfo.SuperCallTranslator(mapper)::translate);
+     }
+ 
+     /** Finds all super() invocations and translates them somehow.
+      */
+     private static class SuperCallTranslator extends TreeTranslator {
+ 
+         final Function<? super JCExpressionStatement, ? extends JCStatement> translator;
+ 
+         /** Constructor.
+          *
+          * @param translator translates super() invocations, returning replacement statement or null for no change
+          */
+         SuperCallTranslator(Function<? super JCExpressionStatement, ? extends JCStatement> translator) {
+             this.translator = translator;
+         }
+ 
+         // Because it returns void, anywhere super() can legally appear must be a location where a JCStatement
+         // could also appear, so it's OK that we are replacing a JCExpressionStatement with a JCStatement here.
+         @Override
+         public void visitExec(JCExpressionStatement stat) {
+             if (!TreeInfo.isSuperCall(stat) || (result = this.translator.apply(stat)) == null)
+                 super.visitExec(stat);
+         }
+ 
+         @Override
+         public void visitClassDef(JCClassDecl tree) {
+             // don't descend any further
+         }
+ 
+         @Override
+         public void visitLambda(JCLambda tree) {
+             // don't descend any further
+         }
      }
  
      /** Return true if a tree represents a diamond new expr. */
      public static boolean isDiamond(JCTree tree) {
          switch(tree.getTag()) {
< prev index next >