langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java
changeset 45862 c6827bac317d
parent 45605 8d019eee3515
equal deleted inserted replaced
45861:a82ccda077c9 45862:c6827bac317d
    22  * or visit www.oracle.com if you need additional information or have any
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package com.sun.tools.javac.comp;
    26 package com.sun.tools.javac.comp;
       
    27 
       
    28 import java.util.ArrayList;
    27 
    29 
    28 import com.sun.source.tree.LambdaExpressionTree;
    30 import com.sun.source.tree.LambdaExpressionTree;
    29 import com.sun.tools.javac.code.Source;
    31 import com.sun.tools.javac.code.Source;
    30 import com.sun.tools.javac.code.Type;
    32 import com.sun.tools.javac.code.Type;
    31 import com.sun.tools.javac.code.Types;
    33 import com.sun.tools.javac.code.Types;
    67 import java.util.EnumSet;
    69 import java.util.EnumSet;
    68 import java.util.HashMap;
    70 import java.util.HashMap;
    69 import java.util.Map;
    71 import java.util.Map;
    70 import java.util.function.Predicate;
    72 import java.util.function.Predicate;
    71 
    73 
       
    74 import com.sun.source.tree.NewClassTree;
       
    75 import com.sun.tools.javac.code.Flags;
       
    76 import com.sun.tools.javac.code.Kinds.Kind;
       
    77 import com.sun.tools.javac.code.Symbol.ClassSymbol;
       
    78 import com.sun.tools.javac.tree.JCTree.JCTry;
       
    79 import com.sun.tools.javac.tree.JCTree.JCUnary;
       
    80 import com.sun.tools.javac.util.Assert;
       
    81 import com.sun.tools.javac.util.DiagnosticSource;
       
    82 
    72 import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
    83 import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
    73 import static com.sun.tools.javac.code.Flags.SYNTHETIC;
       
    74 import static com.sun.tools.javac.code.TypeTag.CLASS;
    84 import static com.sun.tools.javac.code.TypeTag.CLASS;
    75 import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
    85 import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
       
    86 import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
    76 import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
    87 import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
    77 import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
    88 import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
       
    89 import static com.sun.tools.javac.tree.JCTree.Tag.NULLCHK;
    78 import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
    90 import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
       
    91 import static com.sun.tools.javac.tree.JCTree.Tag.VARDEF;
    79 
    92 
    80 /**
    93 /**
    81  * Helper class for defining custom code analysis, such as finding instance creation expression
    94  * Helper class for defining custom code analysis, such as finding instance creation expression
    82  * that can benefit from diamond syntax.
    95  * that can benefit from diamond syntax.
    83  */
    96  */
   339      * Create a copy of Env if needed.
   352      * Create a copy of Env if needed.
   340      */
   353      */
   341     Env<AttrContext> copyEnvIfNeeded(JCTree tree, Env<AttrContext> env) {
   354     Env<AttrContext> copyEnvIfNeeded(JCTree tree, Env<AttrContext> env) {
   342         if (!analyzerModes.isEmpty() &&
   355         if (!analyzerModes.isEmpty() &&
   343                 !env.info.isSpeculative &&
   356                 !env.info.isSpeculative &&
   344                 TreeInfo.isStatement(tree)) {
   357                 TreeInfo.isStatement(tree) &&
       
   358                 !tree.hasTag(LABELLED)) {
   345             Env<AttrContext> analyzeEnv =
   359             Env<AttrContext> analyzeEnv =
   346                     env.dup(env.tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
   360                     env.dup(env.tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
   347             analyzeEnv.info.returnResult = analyzeEnv.info.returnResult != null ?
   361             analyzeEnv.info.returnResult = analyzeEnv.info.returnResult != null ?
   348                     attr.new ResultInfo(analyzeEnv.info.returnResult.pkind,
   362                     attr.new ResultInfo(analyzeEnv.info.returnResult.pkind,
   349                                         analyzeEnv.info.returnResult.pt) : null;
   363                                         analyzeEnv.info.returnResult.pt) : null;
   366     /**
   380     /**
   367      * Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
   381      * Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
   368      * and speculatively type-check the rewritten code to compare results against previously attributed code.
   382      * and speculatively type-check the rewritten code to compare results against previously attributed code.
   369      */
   383      */
   370     void analyze(JCStatement statement, Env<AttrContext> env) {
   384     void analyze(JCStatement statement, Env<AttrContext> env) {
   371         AnalysisContext context = new AnalysisContext();
   385         AnalysisContext context = new AnalysisContext(statement, env);
   372         StatementScanner statementScanner = new StatementScanner(context);
   386         StatementScanner statementScanner = new StatementScanner(context);
   373         statementScanner.scan(statement);
   387         statementScanner.scan(statement);
   374 
   388 
   375         if (!context.treesToAnalyzer.isEmpty()) {
   389         if (!context.treesToAnalyzer.isEmpty()) {
   376 
   390             deferredAnalysisHelper.queue(context);
   377             //add a block to hoist potential dangling variable declarations
   391         }
   378             JCBlock fakeBlock = make.Block(SYNTHETIC, List.of(statement));
   392     }
       
   393 
       
   394     /**
       
   395      * Helper interface to handle deferral of analysis tasks.
       
   396      */
       
   397     interface DeferredAnalysisHelper {
       
   398         /**
       
   399          * Add a new analysis task to the queue.
       
   400          */
       
   401         void queue(AnalysisContext context);
       
   402         /**
       
   403          * Flush queue with given attribution env.
       
   404          */
       
   405         void flush(Env<AttrContext> flushEnv);
       
   406     }
       
   407 
       
   408     /**
       
   409      * Dummy deferral handler.
       
   410      */
       
   411     DeferredAnalysisHelper flushDeferredHelper = new DeferredAnalysisHelper() {
       
   412         @Override
       
   413         public void queue(AnalysisContext context) {
       
   414             //do nothing
       
   415         }
       
   416 
       
   417         @Override
       
   418         public void flush(Env<AttrContext> flushEnv) {
       
   419             //do nothing
       
   420         }
       
   421     };
       
   422 
       
   423     /**
       
   424      * Simple deferral handler. All tasks belonging to the same outermost class are added to
       
   425      * the same queue. The queue is flushed after flow analysis (only if no error occurred).
       
   426      */
       
   427     DeferredAnalysisHelper queueDeferredHelper = new DeferredAnalysisHelper() {
       
   428 
       
   429         Map<ClassSymbol, ArrayList<AnalysisContext>> Q = new HashMap<>();
       
   430 
       
   431         @Override
       
   432         public void queue(AnalysisContext context) {
       
   433             ArrayList<AnalysisContext> s = Q.computeIfAbsent(context.env.enclClass.sym.outermostClass(), k -> new ArrayList<>());
       
   434             s.add(context);
       
   435         }
       
   436 
       
   437         @Override
       
   438         public void flush(Env<AttrContext> flushEnv) {
       
   439             if (!Q.isEmpty()) {
       
   440                 DeferredAnalysisHelper prevHelper = deferredAnalysisHelper;
       
   441                 try {
       
   442                     deferredAnalysisHelper = flushDeferredHelper;
       
   443                     ArrayList<AnalysisContext> s = Q.get(flushEnv.enclClass.sym.outermostClass());
       
   444                     while (s != null && !s.isEmpty()) {
       
   445                         doAnalysis(s.remove(0));
       
   446                     }
       
   447                 } finally {
       
   448                     deferredAnalysisHelper = prevHelper;
       
   449                 }
       
   450             }
       
   451         }
       
   452     };
       
   453 
       
   454     DeferredAnalysisHelper deferredAnalysisHelper = queueDeferredHelper;
       
   455 
       
   456     void doAnalysis(AnalysisContext context) {
       
   457         DiagnosticSource prevSource = log.currentSource();
       
   458         LocalCacheContext localCacheContext = argumentAttr.withLocalCacheContext();
       
   459         try {
       
   460             log.useSource(context.env.toplevel.getSourceFile());
       
   461 
       
   462             JCStatement treeToAnalyze = (JCStatement)context.tree;
       
   463             if (context.env.info.scope.owner.kind == Kind.TYP) {
       
   464                 //add a block to hoist potential dangling variable declarations
       
   465                 treeToAnalyze = make.Block(Flags.SYNTHETIC, List.of((JCStatement)context.tree));
       
   466             }
   379 
   467 
   380             TreeMapper treeMapper = new TreeMapper(context);
   468             TreeMapper treeMapper = new TreeMapper(context);
   381             //TODO: to further refine the analysis, try all rewriting combinations
   469             //TODO: to further refine the analysis, try all rewriting combinations
   382             deferredAttr.attribSpeculative(fakeBlock, env, attr.statInfo, treeMapper,
   470             deferredAttr.attribSpeculative(treeToAnalyze, context.env, attr.statInfo, treeMapper,
   383                     t -> new AnalyzeDeferredDiagHandler(context),
   471                     t -> new AnalyzeDeferredDiagHandler(context), argumentAttr.withLocalCacheContext());
   384                     argumentAttr.withLocalCacheContext());
       
   385             context.treeMap.entrySet().forEach(e -> {
   472             context.treeMap.entrySet().forEach(e -> {
   386                 context.treesToAnalyzer.get(e.getKey())
   473                 context.treesToAnalyzer.get(e.getKey())
   387                         .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
   474                         .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
   388             });
   475             });
   389         }
   476         } catch (Throwable ex) {
       
   477             Assert.error("Analyzer error when processing: " + context.tree);
       
   478         } finally {
       
   479             log.useSource(prevSource.getFile());
       
   480             localCacheContext.leave();
       
   481         }
       
   482     }
       
   483 
       
   484     public void flush(Env<AttrContext> flushEnv) {
       
   485         deferredAnalysisHelper.flush(flushEnv);
   390     }
   486     }
   391 
   487 
   392     /**
   488     /**
   393      * Simple deferred diagnostic handler which filters out all messages and keep track of errors.
   489      * Simple deferred diagnostic handler which filters out all messages and keep track of errors.
   394      */
   490      */
   409     /**
   505     /**
   410      * This class is used to pass around contextual information bewteen analyzer classes, such as
   506      * This class is used to pass around contextual information bewteen analyzer classes, such as
   411      * trees to be rewritten, errors occurred during the speculative attribution step, etc.
   507      * trees to be rewritten, errors occurred during the speculative attribution step, etc.
   412      */
   508      */
   413     class AnalysisContext {
   509     class AnalysisContext {
       
   510 
       
   511         JCTree tree;
       
   512 
       
   513         Env<AttrContext> env;
       
   514 
       
   515         AnalysisContext(JCTree tree, Env<AttrContext> env) {
       
   516             this.tree = tree;
       
   517             this.env = attr.copyEnv(env);
       
   518             /*  this is a temporary workaround that should be removed once we have a truly independent
       
   519              *  clone operation
       
   520              */
       
   521             if (tree.hasTag(VARDEF)) {
       
   522                 // avoid redefinition clashes
       
   523                 this.env.info.scope.remove(((JCVariableDecl)tree).sym);
       
   524             }
       
   525         }
       
   526 
   414         /** Map from trees to analyzers. */
   527         /** Map from trees to analyzers. */
   415         Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
   528         Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
   416 
   529 
   417         /** Map from original AST nodes to rewritten AST nodes */
   530         /** Map from original AST nodes to rewritten AST nodes */
   418         Map<JCTree, JCTree> treeMap = new HashMap<>();
   531         Map<JCTree, JCTree> treeMap = new HashMap<>();
   450             super.scan(tree);
   563             super.scan(tree);
   451         }
   564         }
   452 
   565 
   453         @Override
   566         @Override
   454         public void visitClassDef(JCClassDecl tree) {
   567         public void visitClassDef(JCClassDecl tree) {
   455             //do nothing (prevents seeing same stuff twice
   568             //do nothing (prevents seeing same stuff twice)
   456         }
   569         }
   457 
   570 
   458         @Override
   571         @Override
   459         public void visitMethodDef(JCMethodDecl tree) {
   572         public void visitMethodDef(JCMethodDecl tree) {
   460             //do nothing (prevents seeing same stuff twice
   573             //do nothing (prevents seeing same stuff twice)
   461         }
   574         }
   462 
   575 
   463         @Override
   576         @Override
   464         public void visitBlock(JCBlock tree) {
   577         public void visitBlock(JCBlock tree) {
   465             //do nothing (prevents seeing same stuff twice
   578             //do nothing (prevents seeing same stuff twice)
   466         }
   579         }
   467 
   580 
   468         @Override
   581         @Override
   469         public void visitSwitch(JCSwitch tree) {
   582         public void visitSwitch(JCSwitch tree) {
   470             scan(tree.getExpression());
   583             scan(tree.getExpression());
   471         }
   584         }
   472 
   585 
   473         @Override
   586         @Override
   474         public void visitForLoop(JCForLoop tree) {
   587         public void visitForLoop(JCForLoop tree) {
   475             scan(tree.getInitializer());
   588             //skip body and var decl (to prevents same statements to be analyzed twice)
   476             scan(tree.getCondition());
   589             scan(tree.getCondition());
   477             scan(tree.getUpdate());
   590             scan(tree.getUpdate());
   478         }
   591         }
   479 
   592 
   480         @Override
   593         @Override
       
   594         public void visitTry(JCTry tree) {
       
   595             //skip resources (to prevents same statements to be analyzed twice)
       
   596             scan(tree.getBlock());
       
   597             scan(tree.getCatches());
       
   598             scan(tree.getFinallyBlock());
       
   599         }
       
   600 
       
   601         @Override
   481         public void visitForeachLoop(JCEnhancedForLoop tree) {
   602         public void visitForeachLoop(JCEnhancedForLoop tree) {
       
   603             //skip body (to prevents same statements to be analyzed twice)
   482             scan(tree.getExpression());
   604             scan(tree.getExpression());
   483         }
   605         }
   484 
   606 
   485         @Override
   607         @Override
   486         public void visitWhileLoop(JCWhileLoop tree) {
   608         public void visitWhileLoop(JCWhileLoop tree) {
       
   609             //skip body (to prevents same statements to be analyzed twice)
   487             scan(tree.getCondition());
   610             scan(tree.getCondition());
   488         }
   611         }
   489 
   612 
   490         @Override
   613         @Override
   491         public void visitDoLoop(JCDoWhileLoop tree) {
   614         public void visitDoLoop(JCDoWhileLoop tree) {
       
   615             //skip body (to prevents same statements to be analyzed twice)
   492             scan(tree.getCondition());
   616             scan(tree.getCondition());
   493         }
   617         }
   494 
   618 
   495         @Override
   619         @Override
   496         public void visitIf(JCIf tree) {
   620         public void visitIf(JCIf tree) {
       
   621             //skip body (to prevents same statements to be analyzed twice)
   497             scan(tree.getCondition());
   622             scan(tree.getCondition());
   498         }
   623         }
   499     }
   624     }
   500 
   625 
   501     /**
   626     /**
   531                 newLambda.paramKind = ParameterKind.IMPLICIT;
   656                 newLambda.paramKind = ParameterKind.IMPLICIT;
   532                 newLambda.params.forEach(p -> p.vartype = null);
   657                 newLambda.params.forEach(p -> p.vartype = null);
   533             }
   658             }
   534             return newLambda;
   659             return newLambda;
   535         }
   660         }
       
   661 
       
   662         @Override @DefinedBy(Api.COMPILER_TREE)
       
   663         public JCTree visitNewClass(NewClassTree node, Void aVoid) {
       
   664             JCNewClass oldNewClazz = (JCNewClass)node;
       
   665             JCNewClass newNewClazz = (JCNewClass)super.visitNewClass(node, aVoid);
       
   666             if (!oldNewClazz.args.isEmpty() && oldNewClazz.args.head.hasTag(NULLCHK)) {
       
   667                 //workaround to Attr generating trees
       
   668                 newNewClazz.encl = ((JCUnary)newNewClazz.args.head).arg;
       
   669                 newNewClazz.args = newNewClazz.args.tail;
       
   670             }
       
   671             return newNewClazz;
       
   672         }
   536     }
   673     }
   537 }
   674 }