1/*
2 * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.comp;
27
28import java.util.ArrayList;
29
30import com.sun.source.tree.LambdaExpressionTree;
31import com.sun.tools.javac.code.Source;
32import com.sun.tools.javac.code.Type;
33import com.sun.tools.javac.code.Types;
34import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
35import com.sun.tools.javac.resources.CompilerProperties.Warnings;
36import com.sun.tools.javac.tree.JCTree;
37import com.sun.tools.javac.tree.JCTree.JCBlock;
38import com.sun.tools.javac.tree.JCTree.JCClassDecl;
39import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
40import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
41import com.sun.tools.javac.tree.JCTree.JCForLoop;
42import com.sun.tools.javac.tree.JCTree.JCIf;
43import com.sun.tools.javac.tree.JCTree.JCLambda;
44import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
45import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
46import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
47import com.sun.tools.javac.tree.JCTree.JCNewClass;
48import com.sun.tools.javac.tree.JCTree.JCStatement;
49import com.sun.tools.javac.tree.JCTree.JCSwitch;
50import com.sun.tools.javac.tree.JCTree.JCTypeApply;
51import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
52import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
53import com.sun.tools.javac.tree.JCTree.Tag;
54import com.sun.tools.javac.tree.TreeCopier;
55import com.sun.tools.javac.tree.TreeInfo;
56import com.sun.tools.javac.tree.TreeMaker;
57import com.sun.tools.javac.tree.TreeScanner;
58import com.sun.tools.javac.util.Context;
59import com.sun.tools.javac.util.DefinedBy;
60import com.sun.tools.javac.util.DefinedBy.Api;
61import com.sun.tools.javac.util.JCDiagnostic;
62import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
63import com.sun.tools.javac.util.List;
64import com.sun.tools.javac.util.ListBuffer;
65import com.sun.tools.javac.util.Log;
66import com.sun.tools.javac.util.Names;
67import com.sun.tools.javac.util.Options;
68
69import java.util.EnumSet;
70import java.util.HashMap;
71import java.util.Map;
72import java.util.function.Predicate;
73
74import com.sun.source.tree.NewClassTree;
75import com.sun.tools.javac.code.Flags;
76import com.sun.tools.javac.code.Kinds.Kind;
77import com.sun.tools.javac.code.Symbol.ClassSymbol;
78import com.sun.tools.javac.tree.JCTree.JCTry;
79import com.sun.tools.javac.tree.JCTree.JCUnary;
80import com.sun.tools.javac.util.Assert;
81import com.sun.tools.javac.util.DiagnosticSource;
82
83import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
84import static com.sun.tools.javac.code.TypeTag.CLASS;
85import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
86import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
87import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
88import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
89import static com.sun.tools.javac.tree.JCTree.Tag.NULLCHK;
90import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
91import static com.sun.tools.javac.tree.JCTree.Tag.VARDEF;
92
93/**
94 * Helper class for defining custom code analysis, such as finding instance creation expression
95 * that can benefit from diamond syntax.
96 */
97public class Analyzer {
98    protected static final Context.Key<Analyzer> analyzerKey = new Context.Key<>();
99
100    final Types types;
101    final Log log;
102    final Attr attr;
103    final DeferredAttr deferredAttr;
104    final ArgumentAttr argumentAttr;
105    final TreeMaker make;
106    final Names names;
107    private final boolean allowDiamondWithAnonymousClassCreation;
108
109    final EnumSet<AnalyzerMode> analyzerModes;
110
111    public static Analyzer instance(Context context) {
112        Analyzer instance = context.get(analyzerKey);
113        if (instance == null)
114            instance = new Analyzer(context);
115        return instance;
116    }
117
118    protected Analyzer(Context context) {
119        context.put(analyzerKey, this);
120        types = Types.instance(context);
121        log = Log.instance(context);
122        attr = Attr.instance(context);
123        deferredAttr = DeferredAttr.instance(context);
124        argumentAttr = ArgumentAttr.instance(context);
125        make = TreeMaker.instance(context);
126        names = Names.instance(context);
127        Options options = Options.instance(context);
128        String findOpt = options.get("find");
129        //parse modes
130        Source source = Source.instance(context);
131        allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
132        analyzerModes = AnalyzerMode.getAnalyzerModes(findOpt, source);
133    }
134
135    /**
136     * This enum defines supported analyzer modes, as well as defining the logic for decoding
137     * the {@code -XDfind} option.
138     */
139    enum AnalyzerMode {
140        DIAMOND("diamond", Source::allowDiamond),
141        LAMBDA("lambda", Source::allowLambda),
142        METHOD("method", Source::allowGraphInference);
143
144        final String opt;
145        final Predicate<Source> sourceFilter;
146
147        AnalyzerMode(String opt, Predicate<Source> sourceFilter) {
148            this.opt = opt;
149            this.sourceFilter = sourceFilter;
150        }
151
152        /**
153         * This method is used to parse the {@code find} option.
154         * Possible modes are separated by colon; a mode can be excluded by
155         * prepending '-' to its name. Finally, the special mode 'all' can be used to
156         * add all modes to the resulting enum.
157         */
158        static EnumSet<AnalyzerMode> getAnalyzerModes(String opt, Source source) {
159            if (opt == null) {
160                return EnumSet.noneOf(AnalyzerMode.class);
161            }
162            List<String> modes = List.from(opt.split(","));
163            EnumSet<AnalyzerMode> res = EnumSet.noneOf(AnalyzerMode.class);
164            if (modes.contains("all")) {
165                res = EnumSet.allOf(AnalyzerMode.class);
166            }
167            for (AnalyzerMode mode : values()) {
168                if (modes.contains(mode.opt)) {
169                    res.add(mode);
170                } else if (modes.contains("-" + mode.opt) || !mode.sourceFilter.test(source)) {
171                    res.remove(mode);
172                }
173            }
174            return res;
175        }
176    }
177
178    /**
179     * A statement analyzer is a work-unit that matches certain AST nodes (of given type {@code S}),
180     * rewrites them to different AST nodes (of type {@code T}) and then generates some meaningful
181     * messages in case the analysis has been successful.
182     */
183    abstract class StatementAnalyzer<S extends JCTree, T extends JCTree> {
184
185        AnalyzerMode mode;
186        JCTree.Tag tag;
187
188        StatementAnalyzer(AnalyzerMode mode, Tag tag) {
189            this.mode = mode;
190            this.tag = tag;
191        }
192
193        /**
194         * Is this analyzer allowed to run?
195         */
196        boolean isEnabled() {
197            return analyzerModes.contains(mode);
198        }
199
200        /**
201         * Should this analyzer be rewriting the given tree?
202         */
203        abstract boolean match(S tree);
204
205        /**
206         * Rewrite a given AST node into a new one
207         */
208        abstract T map(S oldTree, S newTree);
209
210        /**
211         * Entry-point for comparing results and generating diagnostics.
212         */
213        abstract void process(S oldTree, T newTree, boolean hasErrors);
214
215    }
216
217    /**
218     * This analyzer checks if generic instance creation expression can use diamond syntax.
219     */
220    class DiamondInitializer extends StatementAnalyzer<JCNewClass, JCNewClass> {
221
222        DiamondInitializer() {
223            super(AnalyzerMode.DIAMOND, NEWCLASS);
224        }
225
226        @Override
227        boolean match(JCNewClass tree) {
228            return tree.clazz.hasTag(TYPEAPPLY) &&
229                    !TreeInfo.isDiamond(tree) &&
230                    (tree.def == null || allowDiamondWithAnonymousClassCreation);
231        }
232
233        @Override
234        JCNewClass map(JCNewClass oldTree, JCNewClass newTree) {
235            if (newTree.clazz.hasTag(TYPEAPPLY)) {
236                ((JCTypeApply)newTree.clazz).arguments = List.nil();
237            }
238            return newTree;
239        }
240
241        @Override
242        void process(JCNewClass oldTree, JCNewClass newTree, boolean hasErrors) {
243            if (!hasErrors) {
244                List<Type> inferredArgs, explicitArgs;
245                if (oldTree.def != null) {
246                    inferredArgs = newTree.def.implementing.nonEmpty()
247                                      ? newTree.def.implementing.get(0).type.getTypeArguments()
248                                      : newTree.def.extending.type.getTypeArguments();
249                    explicitArgs = oldTree.def.implementing.nonEmpty()
250                                      ? oldTree.def.implementing.get(0).type.getTypeArguments()
251                                      : oldTree.def.extending.type.getTypeArguments();
252                } else {
253                    inferredArgs = newTree.type.getTypeArguments();
254                    explicitArgs = oldTree.type.getTypeArguments();
255                }
256                for (Type t : inferredArgs) {
257                    if (!types.isSameType(t, explicitArgs.head)) {
258                        return;
259                    }
260                    explicitArgs = explicitArgs.tail;
261                }
262                //exact match
263                log.warning(oldTree.clazz, Warnings.DiamondRedundantArgs);
264            }
265        }
266    }
267
268    /**
269     * This analyzer checks if anonymous instance creation expression can replaced by lambda.
270     */
271    class LambdaAnalyzer extends StatementAnalyzer<JCNewClass, JCLambda> {
272
273        LambdaAnalyzer() {
274            super(AnalyzerMode.LAMBDA, NEWCLASS);
275        }
276
277        @Override
278        boolean match (JCNewClass tree){
279            Type clazztype = tree.clazz.type;
280            return tree.def != null &&
281                    clazztype.hasTag(CLASS) &&
282                    types.isFunctionalInterface(clazztype.tsym) &&
283                    decls(tree.def).length() == 1;
284        }
285        //where
286            private List<JCTree> decls(JCClassDecl decl) {
287                ListBuffer<JCTree> decls = new ListBuffer<>();
288                for (JCTree t : decl.defs) {
289                    if (t.hasTag(METHODDEF)) {
290                        JCMethodDecl md = (JCMethodDecl)t;
291                        if ((md.getModifiers().flags & GENERATEDCONSTR) == 0) {
292                            decls.add(md);
293                        }
294                    } else {
295                        decls.add(t);
296                    }
297                }
298                return decls.toList();
299            }
300
301        @Override
302        JCLambda map (JCNewClass oldTree, JCNewClass newTree){
303            JCMethodDecl md = (JCMethodDecl)decls(newTree.def).head;
304            List<JCVariableDecl> params = md.params;
305            JCBlock body = md.body;
306            return make.Lambda(params, body);
307        }
308        @Override
309        void process (JCNewClass oldTree, JCLambda newTree, boolean hasErrors){
310            if (!hasErrors) {
311                log.warning(oldTree.def, Warnings.PotentialLambdaFound);
312            }
313        }
314    }
315
316    /**
317     * This analyzer checks if generic method call has redundant type arguments.
318     */
319    class RedundantTypeArgAnalyzer extends StatementAnalyzer<JCMethodInvocation, JCMethodInvocation> {
320
321        RedundantTypeArgAnalyzer() {
322            super(AnalyzerMode.METHOD, APPLY);
323        }
324
325        @Override
326        boolean match (JCMethodInvocation tree){
327            return tree.typeargs != null &&
328                    tree.typeargs.nonEmpty();
329        }
330        @Override
331        JCMethodInvocation map (JCMethodInvocation oldTree, JCMethodInvocation newTree){
332            newTree.typeargs = List.nil();
333            return newTree;
334        }
335        @Override
336        void process (JCMethodInvocation oldTree, JCMethodInvocation newTree, boolean hasErrors){
337            if (!hasErrors) {
338                //exact match
339                log.warning(oldTree, Warnings.MethodRedundantTypeargs);
340            }
341        }
342    }
343
344    @SuppressWarnings({"unchecked", "rawtypes"})
345    StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
346            new DiamondInitializer(),
347            new LambdaAnalyzer(),
348            new RedundantTypeArgAnalyzer()
349    };
350
351    /**
352     * Create a copy of Env if needed.
353     */
354    Env<AttrContext> copyEnvIfNeeded(JCTree tree, Env<AttrContext> env) {
355        if (!analyzerModes.isEmpty() &&
356                !env.info.isSpeculative &&
357                TreeInfo.isStatement(tree) &&
358                !tree.hasTag(LABELLED)) {
359            Env<AttrContext> analyzeEnv =
360                    env.dup(env.tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
361            analyzeEnv.info.returnResult = analyzeEnv.info.returnResult != null ?
362                    attr.new ResultInfo(analyzeEnv.info.returnResult.pkind,
363                                        analyzeEnv.info.returnResult.pt) : null;
364            return analyzeEnv;
365        } else {
366            return null;
367        }
368    }
369
370    /**
371     * Analyze an AST node if needed.
372     */
373    void analyzeIfNeeded(JCTree tree, Env<AttrContext> env) {
374        if (env != null) {
375            JCStatement stmt = (JCStatement)tree;
376            analyze(stmt, env);
377        }
378    }
379
380    /**
381     * Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
382     * and speculatively type-check the rewritten code to compare results against previously attributed code.
383     */
384    void analyze(JCStatement statement, Env<AttrContext> env) {
385        AnalysisContext context = new AnalysisContext(statement, env);
386        StatementScanner statementScanner = new StatementScanner(context);
387        statementScanner.scan(statement);
388
389        if (!context.treesToAnalyzer.isEmpty()) {
390            deferredAnalysisHelper.queue(context);
391        }
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            }
467
468            TreeMapper treeMapper = new TreeMapper(context);
469            //TODO: to further refine the analysis, try all rewriting combinations
470            deferredAttr.attribSpeculative(treeToAnalyze, context.env, attr.statInfo, treeMapper,
471                    t -> new AnalyzeDeferredDiagHandler(context), argumentAttr.withLocalCacheContext());
472            context.treeMap.entrySet().forEach(e -> {
473                context.treesToAnalyzer.get(e.getKey())
474                        .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
475            });
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);
486    }
487
488    /**
489     * Simple deferred diagnostic handler which filters out all messages and keep track of errors.
490     */
491    class AnalyzeDeferredDiagHandler extends Log.DeferredDiagnosticHandler {
492        AnalysisContext context;
493
494        public AnalyzeDeferredDiagHandler(AnalysisContext context) {
495            super(log, d -> {
496                if (d.getType() == DiagnosticType.ERROR) {
497                    context.errors.add(d);
498                }
499                return true;
500            });
501            this.context = context;
502        }
503    }
504
505    /**
506     * This class is used to pass around contextual information bewteen analyzer classes, such as
507     * trees to be rewritten, errors occurred during the speculative attribution step, etc.
508     */
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
527        /** Map from trees to analyzers. */
528        Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
529
530        /** Map from original AST nodes to rewritten AST nodes */
531        Map<JCTree, JCTree> treeMap = new HashMap<>();
532
533        /** Errors in rewritten tree */
534        ListBuffer<JCDiagnostic> errors = new ListBuffer<>();
535    }
536
537    /**
538     * Subclass of {@link com.sun.tools.javac.tree.TreeScanner} which visit AST-nodes w/o crossing
539     * statement boundaries.
540     */
541    class StatementScanner extends TreeScanner {
542
543        /** context */
544        AnalysisContext context;
545
546        StatementScanner(AnalysisContext context) {
547            this.context = context;
548        }
549
550        @Override
551        @SuppressWarnings("unchecked")
552        public void scan(JCTree tree) {
553            if (tree != null) {
554                for (StatementAnalyzer<JCTree, JCTree> analyzer : analyzers) {
555                    if (analyzer.isEnabled() &&
556                            tree.hasTag(analyzer.tag) &&
557                            analyzer.match(tree)) {
558                        context.treesToAnalyzer.put(tree, analyzer);
559                        break; //TODO: cover cases where multiple matching analyzers are found
560                    }
561                }
562            }
563            super.scan(tree);
564        }
565
566        @Override
567        public void visitClassDef(JCClassDecl tree) {
568            //do nothing (prevents seeing same stuff twice)
569        }
570
571        @Override
572        public void visitMethodDef(JCMethodDecl tree) {
573            //do nothing (prevents seeing same stuff twice)
574        }
575
576        @Override
577        public void visitBlock(JCBlock tree) {
578            //do nothing (prevents seeing same stuff twice)
579        }
580
581        @Override
582        public void visitSwitch(JCSwitch tree) {
583            scan(tree.getExpression());
584        }
585
586        @Override
587        public void visitForLoop(JCForLoop tree) {
588            //skip body and var decl (to prevents same statements to be analyzed twice)
589            scan(tree.getCondition());
590            scan(tree.getUpdate());
591        }
592
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
602        public void visitForeachLoop(JCEnhancedForLoop tree) {
603            //skip body (to prevents same statements to be analyzed twice)
604            scan(tree.getExpression());
605        }
606
607        @Override
608        public void visitWhileLoop(JCWhileLoop tree) {
609            //skip body (to prevents same statements to be analyzed twice)
610            scan(tree.getCondition());
611        }
612
613        @Override
614        public void visitDoLoop(JCDoWhileLoop tree) {
615            //skip body (to prevents same statements to be analyzed twice)
616            scan(tree.getCondition());
617        }
618
619        @Override
620        public void visitIf(JCIf tree) {
621            //skip body (to prevents same statements to be analyzed twice)
622            scan(tree.getCondition());
623        }
624    }
625
626    /**
627     * Subclass of TreeCopier that maps nodes matched by analyzers onto new AST nodes.
628     */
629    class TreeMapper extends TreeCopier<Void> {
630
631        AnalysisContext context;
632
633        TreeMapper(AnalysisContext context) {
634            super(make);
635            this.context = context;
636        }
637
638        @Override
639        @SuppressWarnings("unchecked")
640        public <Z extends JCTree> Z copy(Z tree, Void _unused) {
641            Z newTree = super.copy(tree, _unused);
642            StatementAnalyzer<JCTree, JCTree> analyzer = context.treesToAnalyzer.get(tree);
643            if (analyzer != null) {
644                newTree = (Z)analyzer.map(tree, newTree);
645                context.treeMap.put(tree, newTree);
646            }
647            return newTree;
648        }
649
650        @Override @DefinedBy(Api.COMPILER_TREE)
651        public JCTree visitLambdaExpression(LambdaExpressionTree node, Void _unused) {
652            JCLambda oldLambda = (JCLambda)node;
653            JCLambda newLambda = (JCLambda)super.visitLambdaExpression(node, _unused);
654            if (oldLambda.paramKind == ParameterKind.IMPLICIT) {
655                //reset implicit lambda parameters (whose type might have been set during attr)
656                newLambda.paramKind = ParameterKind.IMPLICIT;
657                newLambda.params.forEach(p -> p.vartype = null);
658            }
659            return newLambda;
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        }
673    }
674}
675