src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Repair.java
author Dusan Balek <dbalek@netbeans.org>
Fri, 04 Aug 2017 18:19:59 +0200
changeset 5957 1d4d9f967eaa
parent 5950 993a3fed49b2
permissions -rw-r--r--
Issue #271053 - StringIndexOutOfBoundsException: String index out of range - fixed.
dbalek@43
     1
/*
dbalek@43
     2
 * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
dbalek@43
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
dbalek@43
     4
 *
dbalek@43
     5
 * This code is free software; you can redistribute it and/or modify it
dbalek@43
     6
 * under the terms of the GNU General Public License version 2 only, as
dbalek@43
     7
 * published by the Free Software Foundation.  Sun designates this
dbalek@43
     8
 * particular file as subject to the "Classpath" exception as provided
dbalek@43
     9
 * by Sun in the LICENSE file that accompanied this code.
dbalek@43
    10
 *
dbalek@43
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
dbalek@43
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
dbalek@43
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
dbalek@43
    14
 * version 2 for more details (a copy is included in the LICENSE file that
dbalek@43
    15
 * accompanied this code).
dbalek@43
    16
 *
dbalek@43
    17
 * You should have received a copy of the GNU General Public License version
dbalek@43
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
dbalek@43
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
dbalek@43
    20
 *
dbalek@43
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
dbalek@43
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
dbalek@43
    23
 * have any questions.
dbalek@43
    24
 */
dbalek@43
    25
package com.sun.tools.javac.comp;
dbalek@43
    26
sdedic@3534
    27
import com.sun.source.tree.CaseTree;
sdedic@3534
    28
import com.sun.source.tree.TreeVisitor;
dbalek@70
    29
import com.sun.tools.javac.code.Flags;
dbalek@168
    30
import com.sun.tools.javac.code.Kinds;
dbalek@168
    31
import com.sun.tools.javac.code.Scope;
dbalek@104
    32
import com.sun.tools.javac.code.Source;
dbalek@48
    33
import com.sun.tools.javac.code.Symbol;
dbalek@50
    34
import com.sun.tools.javac.code.Symbol.ClassSymbol;
dbalek@168
    35
import com.sun.tools.javac.code.Symbol.MethodSymbol;
dbalek@43
    36
import com.sun.tools.javac.code.Symtab;
dbalek@50
    37
import com.sun.tools.javac.code.Type;
dbalek@43
    38
import com.sun.tools.javac.code.Type.ClassType;
dbalek@2330
    39
import com.sun.tools.javac.code.TypeTag;
dbalek@50
    40
import com.sun.tools.javac.code.Types;
dbalek@1754
    41
import com.sun.tools.javac.jvm.Pool;
dbalek@2330
    42
import com.sun.tools.javac.parser.Tokens;
dbalek@43
    43
import com.sun.tools.javac.tree.JCTree;
dbalek@162
    44
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
dbalek@154
    45
import com.sun.tools.javac.tree.JCTree.JCBinary;
dbalek@50
    46
import com.sun.tools.javac.tree.JCTree.JCBlock;
dbalek@52
    47
import com.sun.tools.javac.tree.JCTree.JCCase;
dbalek@50
    48
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
dbalek@43
    49
import com.sun.tools.javac.tree.JCTree.JCErroneous;
dbalek@43
    50
import com.sun.tools.javac.tree.JCTree.JCExpression;
dbalek@2870
    51
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
dbalek@70
    52
import com.sun.tools.javac.tree.JCTree.JCImport;
dbalek@43
    53
import com.sun.tools.javac.tree.JCTree.JCLiteral;
dbalek@52
    54
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
dbalek@48
    55
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
dbalek@43
    56
import com.sun.tools.javac.tree.JCTree.JCNewClass;
dbalek@43
    57
import com.sun.tools.javac.tree.JCTree.JCStatement;
sdedic@3534
    58
import com.sun.tools.javac.tree.JCTree.JCSwitch;
dbalek@119
    59
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
dbalek@154
    60
import com.sun.tools.javac.tree.JCTree.JCUnary;
dbalek@44
    61
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
dbalek@48
    62
import com.sun.tools.javac.tree.TreeInfo;
dbalek@43
    63
import com.sun.tools.javac.tree.TreeMaker;
sdedic@3534
    64
import com.sun.tools.javac.tree.TreeScanner;
dbalek@43
    65
import com.sun.tools.javac.tree.TreeTranslator;
dbalek@43
    66
import com.sun.tools.javac.util.Context;
dbalek@72
    67
import com.sun.tools.javac.util.JCDiagnostic;
dbalek@43
    68
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
dbalek@43
    69
import com.sun.tools.javac.util.List;
dbalek@50
    70
import com.sun.tools.javac.util.Log;
dbalek@440
    71
import com.sun.tools.javac.util.MissingPlatformError;
dbalek@406
    72
import com.sun.tools.javac.util.Name;
dbalek@43
    73
import java.util.HashSet;
dbalek@43
    74
import java.util.Set;
dbalek@103
    75
import java.util.logging.Logger;
tzezula@1740
    76
import javax.lang.model.element.ElementKind;
tzezula@1740
    77
import javax.tools.JavaFileObject;
dbalek@43
    78
dbalek@2330
    79
dbalek@43
    80
/**
dbalek@43
    81
 *
dbalek@43
    82
 * @author Dusan Balek
dbalek@43
    83
 */
dbalek@43
    84
public class Repair extends TreeTranslator {
dbalek@43
    85
dbalek@43
    86
    /** The context key for the Repair phase. */
dbalek@43
    87
    protected static final Context.Key<Repair> repairKey = new Context.Key<Repair>();
dbalek@43
    88
    private static final String ERR_MESSAGE = "Uncompilable source code";
dbalek@142
    89
    private static final Logger LOGGER = Logger.getLogger(Repair.class.getName());
dbalek@43
    90
dbalek@43
    91
    /** Get the instance for this context. */
dbalek@43
    92
    public static Repair instance(Context context) {
dbalek@43
    93
        Repair instance = context.get(repairKey);
dbalek@43
    94
        if (instance == null) {
dbalek@43
    95
            instance = new Repair(context);
dbalek@43
    96
        }
dbalek@43
    97
        return instance;
dbalek@43
    98
    }
dbalek@43
    99
dbalek@43
   100
    private Symtab syms;
dbalek@43
   101
    private Resolve rs;
dbalek@50
   102
    private Enter enter;
dbalek@50
   103
    private Types types;
dbalek@50
   104
    private Log log;
dbalek@43
   105
    private TreeMaker make;
dbalek@440
   106
    private JCDiagnostic.Factory diags;
dbalek@2904
   107
    private boolean allowLambda;
dbalek@43
   108
    
dbalek@43
   109
    private Env<AttrContext> attrEnv;
dbalek@43
   110
    private boolean hasError;
dbalek@72
   111
    private JCDiagnostic err;
dbalek@88
   112
    private JCTree classLevelErrTree;
dbalek@88
   113
    private String classLevelErrMessage;
dbalek@1222
   114
    private String errMessage;
dbalek@80
   115
    private JCBlock staticInit;
dbalek@50
   116
    private List<JCTree> parents;
dbalek@177
   117
    private Set<ClassSymbol> repairedClasses = new HashSet<ClassSymbol>();
dbalek@406
   118
    private boolean isErrClass;
dbalek@808
   119
    private boolean insideErrEnum;
tzezula@1740
   120
    private Name fixedTopLevelName;
dbalek@5948
   121
    private Symbol runtimeExceptionDefaultConstructor = null;
dbalek@5948
   122
    private Symbol runtimeExceptionConstructor = null;
dbalek@43
   123
    
dbalek@43
   124
    private Repair(Context context) {
dbalek@43
   125
        context.put(repairKey, this);
dbalek@43
   126
        syms = Symtab.instance(context);
dbalek@43
   127
        rs = Resolve.instance(context);
dbalek@50
   128
        enter = Enter.instance(context);
dbalek@50
   129
        types = Types.instance(context);
dbalek@50
   130
        log = Log.instance(context);
dbalek@440
   131
        diags = JCDiagnostic.Factory.instance(context);
dbalek@104
   132
        Source source = Source.instance(context);
dbalek@2904
   133
        allowLambda = source.allowLambda();
dbalek@43
   134
    }
dbalek@43
   135
dbalek@43
   136
    @Override
dbalek@43
   137
    public <T extends JCTree> T translate(T tree) {
dbalek@50
   138
        if (tree == null)
dbalek@50
   139
            return null;
dbalek@1754
   140
        if (tree.type != null && tree.type.constValue() instanceof String && ((String)tree.type.constValue()).length() >= Pool.MAX_STRING_LENGTH) {
dbalek@1754
   141
            log.error(tree.pos(), "limit.string"); //NOI18N
dbalek@1754
   142
        }
dbalek@53
   143
        parents = parents.prepend(tree);
dbalek@48
   144
        try {
dbalek@53
   145
            if (hasError)
dbalek@53
   146
                return super.translate(tree);
dbalek@72
   147
            if ((err = log.getErrDiag(tree)) != null)
dbalek@53
   148
                hasError = true;
dbalek@45
   149
            tree = super.translate(tree);
dbalek@48
   150
        } finally {
dbalek@48
   151
            parents = parents.tail;            
dbalek@45
   152
        }
dbalek@1604
   153
        if (tree.type != null && tree.type.isErroneous() || tree.type == syms.unknownType) {
dbalek@417
   154
            JCTree parent = parents.head;
dbalek@2330
   155
            if (parent == null || !parent.hasTag(JCTree.Tag.CLASSDEF)) {
dbalek@417
   156
                hasError = true;
dbalek@1222
   157
                if (err == null && errMessage == null)
dbalek@1222
   158
                    errMessage = "Erroneous tree type: " + tree.type;
dbalek@1222
   159
            }
dbalek@417
   160
        }
dbalek@53
   161
        if (!(hasError && tree instanceof JCStatement))
dbalek@53
   162
            return tree;
dbalek@2330
   163
        if (tree.hasTag(JCTree.Tag.CASE))
dbalek@63
   164
            return tree;
sdedic@3534
   165
        if (tree.hasTag(JCTree.Tag.CLASSDEF)) {
dbalek@53
   166
            JCTree parent = parents.head;
sdedic@3534
   167
            if (parent == null || (!parent.hasTag(JCTree.Tag.BLOCK) && !parent.hasTag(JCTree.Tag.CASE))) {
dbalek@53
   168
                return tree;
sdedic@3534
   169
            }
sdedic@3534
   170
        }
sdedic@3534
   171
        if (tree.hasTag(JCTree.Tag.VARDEF)) {
sdedic@3534
   172
            JCTree parent = parents.head;
sdedic@3534
   173
            if (parent == null) {
sdedic@3534
   174
                return tree;
sdedic@3534
   175
            }
sdedic@3534
   176
            // special case: in switch-case, generate throw and terminate the case only if the variable is not used
sdedic@3534
   177
            // in subsequent switch cases. Otherwise return the tree unchanged with error flags, the whole switch
sdedic@3534
   178
            // statement will be aborted and replaced by throw.
sdedic@3534
   179
            if (parent.hasTag(JCTree.Tag.CASE)) {
sdedic@3534
   180
                if (!parents.tail.isEmpty()) {
sdedic@3534
   181
                    JCTree t = parents.tail.head;
sdedic@3534
   182
                    if (t.hasTag(JCTree.Tag.SWITCH) && varUsedInOtherCaseBranch((JCVariableDecl)tree, (JCSwitch)t, (JCCase)parent)) {
sdedic@3534
   183
                        // assume the whole switch will be replaced by throw statement.
sdedic@3534
   184
                        return tree;
sdedic@3534
   185
                    }
sdedic@3534
   186
                }
sdedic@3534
   187
            } else if (!parent.hasTag(JCTree.Tag.BLOCK)) {
sdedic@3534
   188
                return tree;
sdedic@3534
   189
            }
dbalek@53
   190
        }
dbalek@1222
   191
        String msg = err != null ? err.getMessage(null) : errMessage;
dbalek@53
   192
        hasError = false;
dbalek@72
   193
        err = null;
dbalek@1222
   194
        errMessage = null;
dbalek@2330
   195
        if (tree.hasTag(JCTree.Tag.BLOCK)) {
dbalek@72
   196
            ((JCBlock)tree).stats = List.of(generateErrStat(tree.pos(), msg));
dbalek@53
   197
            return tree;
dbalek@53
   198
        }
dbalek@72
   199
        return (T)generateErrStat(tree.pos(), msg);
dbalek@43
   200
    }
sdedic@3534
   201
    
sdedic@3534
   202
    private boolean varUsedInOtherCaseBranch(final JCTree.JCVariableDecl varDecl, JCSwitch sw, JCCase defCase) {
sdedic@3534
   203
        List<JCCase> cases = sw.getCases();
sdedic@3534
   204
        int index = cases.indexOf(defCase);
sdedic@3534
   205
        if (index == -1) {
sdedic@3534
   206
            // not sure, eliminate whole switch
sdedic@3534
   207
            return true;
sdedic@3534
   208
        }
sdedic@3534
   209
        class SwitchVariableFinder extends TreeScanner {
sdedic@3534
   210
            private boolean used;
dbalek@43
   211
sdedic@3534
   212
            @Override
sdedic@3534
   213
            public void visitIdent(JCTree.JCIdent tree) {
sdedic@3534
   214
                used |= tree.sym == varDecl.sym;
sdedic@3534
   215
                super.visitIdent(tree);
sdedic@3534
   216
            }
sdedic@3534
   217
        }
sdedic@3534
   218
        SwitchVariableFinder finder = new SwitchVariableFinder();
sdedic@3534
   219
        for (int i = index + 1; i < cases.size(); i++) {
sdedic@3534
   220
            JCTree testCase = cases.get(i);
sdedic@3534
   221
            finder.scan(testCase);
sdedic@3534
   222
            if (finder.used) {
sdedic@3534
   223
                return true;
sdedic@3534
   224
            }
sdedic@3534
   225
        }
sdedic@3534
   226
        return false;
sdedic@3534
   227
    }
sdedic@3534
   228
    
dbalek@43
   229
    @Override
dbalek@70
   230
    public void visitImport(JCImport tree) {
dbalek@70
   231
        super.visitImport(tree);
dbalek@88
   232
        if (hasError && err != null) {
dbalek@88
   233
            classLevelErrTree = err.getTree();
dbalek@88
   234
            classLevelErrMessage = err.getMessage(null);
dbalek@88
   235
        }
dbalek@70
   236
    }
dbalek@70
   237
dbalek@70
   238
    @Override
dbalek@119
   239
    public void visitTypeParameter(JCTypeParameter tree) {
dbalek@119
   240
        super.visitTypeParameter(tree);
dbalek@2330
   241
        if (tree.type != null && tree.type.hasTag(TypeTag.TYPEVAR)) {
dbalek@4426
   242
            Type.TypeVar tv = (Type.TypeVar)tree.type;
dbalek@1604
   243
            if (tv.bound != null && tv.bound.isErroneous() || tv.bound == syms.unknownType) {
dbalek@1222
   244
                if (err == null && errMessage == null)
dbalek@1222
   245
                    errMessage = "Erroneous type var bound: " + tv.bound;
dbalek@119
   246
                tv.bound = syms.objectType;
dbalek@119
   247
                hasError = true;
dbalek@119
   248
            }
dbalek@119
   249
        }
dbalek@119
   250
    }
dbalek@119
   251
dbalek@119
   252
    @Override
dbalek@50
   253
    public void visitClassDef(JCClassDecl tree) {
dbalek@50
   254
        translateClass(tree.sym);
dbalek@50
   255
        result = tree;
dbalek@50
   256
    }
dbalek@50
   257
dbalek@50
   258
    @Override
dbalek@44
   259
    public void visitVarDef(JCVariableDecl tree) {
dbalek@50
   260
        super.visitVarDef(tree);
dbalek@53
   261
        if (hasError) {
dbalek@50
   262
            JCTree parent = parents != null ? parents.tail.head : null;
dbalek@2330
   263
            if (parent != null && parent.hasTag(JCTree.Tag.CLASSDEF)) {
dbalek@1222
   264
                tree.init = err != null ? generateErrExpr(err.getTree(), err.getMessage(null)) : generateErrExpr(tree.init, errMessage);
dbalek@53
   265
                hasError = false;
dbalek@72
   266
                err = null;
dbalek@1222
   267
                errMessage = null;
dbalek@1754
   268
                if (tree.sym != null)
dbalek@1754
   269
                    tree.sym.setData(null);
dbalek@53
   270
            }
dbalek@803
   271
        } else if (tree.sym == null) {
dbalek@803
   272
            JCTree parent = parents != null ? parents.tail.head : null;
dbalek@2330
   273
            if (parent != null && !parent.hasTag(JCTree.Tag.CLASSDEF)) {
dbalek@803
   274
                hasError = true;
dbalek@1222
   275
                if (err == null && errMessage == null)
dbalek@1222
   276
                    errMessage = "Null tree sym: " + tree;
dbalek@1222
   277
           }
dbalek@50
   278
        }
dbalek@50
   279
    }
dbalek@50
   280
dbalek@50
   281
    @Override
dbalek@52
   282
    public void visitMethodDef(JCMethodDecl tree) {
dbalek@137
   283
        boolean hadDuplicateSymError = hasError && err != null && "compiler.err.already.defined".equals(err.getCode()); //NOI18N
dbalek@122
   284
        tree.mods = translate(tree.mods);
dbalek@122
   285
        tree.restype = translate(tree.restype);
dbalek@122
   286
        tree.typarams = translateTypeParams(tree.typarams);
dbalek@122
   287
        tree.params = translateVarDefs(tree.params);
dbalek@122
   288
        tree.thrown = translate(tree.thrown);
dbalek@122
   289
        tree.defaultValue = translate(tree.defaultValue);
dbalek@122
   290
        tree.body = translate(tree.body);
dbalek@122
   291
        result = tree;
dbalek@406
   292
        if (isErrClass && tree.body != null) {
dbalek@406
   293
            JCMethodInvocation app = TreeInfo.firstConstructorCall(tree);
dbalek@406
   294
            Name meth = app != null ? TreeInfo.name(app.meth) : null;
dbalek@2868
   295
            if (meth != null && (meth == meth.table.names._this || meth == meth.table.names._super))
dbalek@428
   296
                tree.body.stats.tail = List.<JCStatement>nil();
dbalek@406
   297
            else
dbalek@406
   298
                tree.body.stats = List.<JCStatement>nil();
dbalek@406
   299
        }
dbalek@137
   300
        if (hasError && !hadDuplicateSymError) {
dbalek@470
   301
            if (tree.body != null) {
dbalek@470
   302
                if (tree.sym != null)
dbalek@470
   303
                    tree.sym.flags_field &= ~(Flags.ABSTRACT | Flags.NATIVE);
dbalek@1222
   304
                tree.body.stats = List.of(generateErrStat(tree.pos(), err != null ? err.getMessage(null) : errMessage));
dbalek@470
   305
            } else if (tree.sym == null || (tree.sym.flags_field & Flags.ABSTRACT) == 0) {
dbalek@470
   306
                tree.body = make.Block(0, List.<JCStatement>nil());
dbalek@1222
   307
                tree.body.stats = List.of(generateErrStat(tree.pos(), err != null ? err.getMessage(null) : errMessage));
dbalek@470
   308
            }
dbalek@470
   309
            if (tree.sym != null)
dbalek@118
   310
                tree.sym.defaultValue = null;
dbalek@118
   311
            tree.defaultValue = null;
dbalek@53
   312
            hasError = false;
dbalek@72
   313
            err = null;
dbalek@1222
   314
            errMessage = null;
dbalek@53
   315
        }
dbalek@52
   316
    }
dbalek@52
   317
dbalek@52
   318
    @Override
dbalek@50
   319
    public void visitBlock(JCBlock tree) {
dbalek@80
   320
        if (tree.isStatic() && staticInit == null)
dbalek@80
   321
            staticInit = tree;
dbalek@53
   322
        List<JCStatement> last = null;
dbalek@53
   323
        for (List<JCStatement> l = tree.stats; l.nonEmpty(); l = l.tail) {
dbalek@53
   324
            l.head = translate(l.head);
dbalek@2330
   325
            if (last == null && l.head.hasTag(JCTree.Tag.THROW))
dbalek@53
   326
                last = l;
dbalek@47
   327
        }
dbalek@53
   328
        if (last != null)
dbalek@53
   329
            last.tail = List.nil();
dbalek@44
   330
        result = tree;
dbalek@44
   331
    }
dbalek@44
   332
dbalek@44
   333
    @Override
dbalek@48
   334
    public void visitApply(JCMethodInvocation tree) {
dbalek@48
   335
        Symbol meth = TreeInfo.symbol(tree.meth);
dbalek@104
   336
        if (meth == null) {
dbalek@142
   337
            LOGGER.warning("Repair.visitApply tree [" + tree + "] has null symbol."); //NOI18N
dbalek@48
   338
            hasError = true;
dbalek@1222
   339
            if (err == null && errMessage == null)
dbalek@1222
   340
                errMessage = "Null tree sym: " + tree.meth;
dbalek@1222
   341
        } else if (meth.type == null) {
dbalek@103
   342
            hasError = true;
dbalek@1222
   343
            if (err == null && errMessage == null)
dbalek@1222
   344
                errMessage = "Null sym type: " + meth;
dbalek@1604
   345
        } else if (meth.type.isErroneous() || meth.type == syms.unknownType) {
dbalek@1222
   346
            hasError = true;
dbalek@1222
   347
            if (err == null && errMessage == null)
dbalek@1222
   348
                errMessage = "Erroneous sym type: " + meth.type;
dbalek@103
   349
        }
dbalek@53
   350
        super.visitApply(tree);
dbalek@50
   351
    }
dbalek@50
   352
dbalek@50
   353
    @Override
dbalek@50
   354
    public void visitNewClass(JCNewClass tree) {
dbalek@50
   355
        Symbol ctor = tree.constructor;
dbalek@104
   356
        if (ctor == null) {
dbalek@142
   357
            LOGGER.warning("Repair.visitNewClass tree [" + tree + "] has null constructor symbol."); //NOI18N
dbalek@50
   358
            hasError = true;
dbalek@1222
   359
            if (err == null && errMessage == null)
dbalek@3775
   360
                errMessage = "Null tree ctor";
dbalek@1222
   361
        } else if (tree.constructorType == null) {
dbalek@104
   362
            hasError = true;
dbalek@1222
   363
            if (err == null && errMessage == null)
dbalek@1222
   364
                errMessage = "Null ctor sym type: " + ctor;
dbalek@1604
   365
        } else if (tree.constructorType.isErroneous() || tree.constructorType == syms.unknownType) {
dbalek@1222
   366
            hasError = true;
dbalek@1222
   367
            if (err == null && errMessage == null)
dbalek@1222
   368
                errMessage = "Erroneous ctor sym type: " + tree.constructorType;
dbalek@3775
   369
        }
dbalek@53
   370
        super.visitNewClass(tree);
dbalek@48
   371
    }
dbalek@48
   372
dbalek@48
   373
    @Override
dbalek@154
   374
    public void visitUnary(JCUnary tree) {
dbalek@154
   375
        Symbol operator = tree.operator;
dbalek@154
   376
        if (operator == null) {
dbalek@154
   377
            LOGGER.warning("Repair.visitUnary tree [" + tree + "] has null operator symbol."); //NOI18N
dbalek@154
   378
            hasError = true;
dbalek@1222
   379
            if (err == null && errMessage == null)
dbalek@1222
   380
                errMessage = "Null operator: " + tree;
dbalek@154
   381
        }
dbalek@154
   382
        super.visitUnary(tree);
dbalek@154
   383
    }
dbalek@154
   384
dbalek@154
   385
    @Override
dbalek@154
   386
    public void visitBinary(JCBinary tree) {
dbalek@154
   387
        Symbol operator = tree.operator;
dbalek@154
   388
        if (operator == null) {
dbalek@154
   389
            LOGGER.warning("Repair.visitBinary tree [" + tree + "] has null operator symbol."); //NOI18N
dbalek@154
   390
            hasError = true;
dbalek@1222
   391
            if (err == null && errMessage == null)
dbalek@1222
   392
                errMessage = "Null operator: " + tree;
dbalek@154
   393
        }
dbalek@154
   394
        super.visitBinary(tree);
dbalek@154
   395
    }
dbalek@154
   396
dbalek@154
   397
    @Override
dbalek@162
   398
    public void visitAssignop(JCAssignOp tree) {
dbalek@162
   399
        Symbol operator = tree.operator;
dbalek@162
   400
        if (operator == null) {
dbalek@162
   401
            LOGGER.warning("Repair.visitAssignop tree [" + tree + "] has null operator symbol."); //NOI18N
dbalek@162
   402
            hasError = true;
dbalek@1222
   403
            if (err == null && errMessage == null)
dbalek@1222
   404
                errMessage = "Null operator: " + tree;
dbalek@162
   405
        }
dbalek@162
   406
        super.visitAssignop(tree);
dbalek@162
   407
    }
dbalek@162
   408
dbalek@162
   409
    @Override
dbalek@52
   410
    public void visitCase(JCCase tree) {
dbalek@52
   411
        tree.pat = translate(tree.pat);
dbalek@3765
   412
        if (!hasError && tree.pat != null && (tree.pat.type == null
dbalek@3763
   413
                || (tree.pat.type.tsym.flags() & Flags.ENUM) == 0
dbalek@3763
   414
                && tree.pat.type.constValue() == null)) {
dbalek@3763
   415
            LOGGER.warning("Repair.visitCase tree [" + tree + "] has wrong expression type [" + tree.pat.type + "]."); //NOI18N
dbalek@3763
   416
            hasError = true;
dbalek@3763
   417
            if (err == null && errMessage == null)
dbalek@3763
   418
                errMessage = "Wrong expression type: " + tree;
dbalek@3763
   419
        }
dbalek@52
   420
        List<JCStatement> last = null;
dbalek@52
   421
        for (List<JCStatement> l = tree.stats; l.nonEmpty(); l = l.tail) {
dbalek@52
   422
            l.head = translate(l.head);
dbalek@2330
   423
            if (last == null && l.head.hasTag(JCTree.Tag.THROW))
dbalek@52
   424
                last = l;
dbalek@52
   425
        }
dbalek@52
   426
        if (last != null)
dbalek@52
   427
            last.tail = List.nil();
dbalek@52
   428
        result = tree;
dbalek@52
   429
    }
dbalek@52
   430
dbalek@52
   431
    @Override
dbalek@2904
   432
    public void visitLambda(JCTree.JCLambda tree) {        
dbalek@2904
   433
        if (!allowLambda) {
dbalek@2904
   434
            hasError = true;
dbalek@2904
   435
        }
dbalek@2904
   436
        super.visitLambda(tree);
dbalek@2904
   437
    }
dbalek@2904
   438
dbalek@2904
   439
    @Override
dbalek@2920
   440
    public void visitReference(JCTree.JCMemberReference tree) {
dbalek@2920
   441
        if (!allowLambda) {
dbalek@2920
   442
            hasError = true;
dbalek@2920
   443
        }
dbalek@2920
   444
        super.visitReference(tree);
dbalek@2920
   445
    }
dbalek@2920
   446
dbalek@2920
   447
    @Override
dbalek@45
   448
    public void visitErroneous(JCErroneous tree) {
dbalek@45
   449
        hasError = true;
dbalek@43
   450
        result = tree;
dbalek@43
   451
    }
dbalek@2920
   452
dbalek@72
   453
    private JCStatement generateErrStat(DiagnosticPosition pos, String msg) {
dbalek@5948
   454
        return generateErrStat(make, pos, msg);
dbalek@5948
   455
    }
dbalek@5948
   456
    
dbalek@5948
   457
    JCStatement generateErrStat(TreeMaker make, DiagnosticPosition pos, String msg) {
dbalek@43
   458
        make.at(pos);
dbalek@43
   459
        ClassType ctype = (ClassType)syms.runtimeExceptionType;
dbalek@5948
   460
        if (runtimeExceptionConstructor != null && runtimeExceptionConstructor.kind == Kinds.Kind.MTH) {
dbalek@440
   461
            JCLiteral literal = make.Literal(msg != null ? ERR_MESSAGE + " - " + msg : ERR_MESSAGE); //NOI18N
dbalek@440
   462
            JCNewClass tree = make.NewClass(null, null, make.QualIdent(ctype.tsym), List.<JCExpression>of(literal), null);
dbalek@440
   463
            tree.type = ctype;
dbalek@5948
   464
            tree.constructor = runtimeExceptionConstructor;
dbalek@440
   465
            return make.Throw(tree);
dbalek@440
   466
        }
dbalek@5948
   467
        if (runtimeExceptionDefaultConstructor != null && runtimeExceptionDefaultConstructor.kind == Kinds.Kind.MTH) {
dbalek@440
   468
            JCNewClass tree = make.NewClass(null, null, make.QualIdent(ctype.tsym), List.<JCExpression>nil(), null);
dbalek@440
   469
            tree.type = ctype;
dbalek@5948
   470
            tree.constructor = runtimeExceptionDefaultConstructor;
dbalek@440
   471
            return make.Throw(tree);
dbalek@440
   472
        }
dbalek@440
   473
        throw new MissingPlatformError (diags.fragment("fatal.err.cant.locate.ctor", ctype)); //NOI18N
dbalek@43
   474
    }
dbalek@43
   475
    
dbalek@72
   476
    private JCExpression generateErrExpr(DiagnosticPosition pos, String msg) {
dbalek@5948
   477
        return generateErrExpr(make, pos, msg);
dbalek@5948
   478
    }
dbalek@5948
   479
dbalek@5948
   480
    JCExpression generateErrExpr(TreeMaker make, DiagnosticPosition pos, String msg) {
dbalek@72
   481
        make.at(pos);
dbalek@5948
   482
        JCExpression expr = make.Erroneous(List.<JCStatement>of(generateErrStat(make, pos, msg)));
dbalek@44
   483
        expr.type = syms.errType;
dbalek@44
   484
        return expr;
dbalek@44
   485
    }
dbalek@44
   486
    
dbalek@72
   487
    private JCBlock generateErrStaticInit(DiagnosticPosition pos, String msg) {
dbalek@70
   488
        make.at(pos);
dbalek@72
   489
        return make.Block(Flags.STATIC, List.<JCStatement>of(generateErrStat(pos, msg)));
dbalek@70
   490
    }
dbalek@70
   491
dbalek@168
   492
    private JCMethodDecl generateErrMethod(MethodSymbol sym) {
dbalek@168
   493
        make.at(null);
dbalek@168
   494
        return make.MethodDef(sym, make.Block(0, List.<JCStatement>of(generateErrStat(null, null))));
dbalek@168
   495
    }
dbalek@2870
   496
    
dbalek@2870
   497
    private JCExpressionStatement generateFakeConstructorCall(MethodSymbol ctor) {
dbalek@2870
   498
        make.at(null);
dbalek@2870
   499
        JCTree.JCIdent ident = make.Ident(syms.objectType.tsym.name.table.names._this);
dbalek@2870
   500
        ident.sym = ctor;
dbalek@2870
   501
        ident.type = ctor.type;
dbalek@2870
   502
        List<JCExpression> args = List.nil();
dbalek@2870
   503
        for (Symbol.VarSymbol param : ((MethodSymbol)ctor).params().reverse()) {
dbalek@2870
   504
            args = args.prepend(make.Ident(param));
dbalek@2870
   505
        }
dbalek@2870
   506
        JCMethodInvocation meth = make.Apply(List.<JCExpression>nil(), ident, args);
dbalek@2870
   507
        meth.type = ctor.type.getReturnType();
dbalek@2870
   508
        return make.Exec(meth);
dbalek@2870
   509
    }
dbalek@168
   510
dbalek@50
   511
    private void translateClass(ClassSymbol c) {
dbalek@53
   512
        if (c == null)
dbalek@53
   513
            return;
dbalek@50
   514
        Type st = types.supertype(c.type);
dbalek@2330
   515
        if (st != null && st.hasTag(TypeTag.CLASS))
dbalek@50
   516
            translateClass((ClassSymbol)st.tsym);
dbalek@164
   517
        LOGGER.finest("Repair.translateClass: " + c); //NOI18N
dbalek@177
   518
        if (repairedClasses.contains(c)) {
dbalek@164
   519
            LOGGER.finest("Repair.translateClass: Should be already done"); //NOI18N
dbalek@50
   520
            return;
dbalek@164
   521
        }
dbalek@164
   522
        Env<AttrContext> myEnv = enter.typeEnvs.get(c);
dbalek@164
   523
        if (myEnv == null) {
dbalek@164
   524
            LOGGER.finest("Repair.translateClass: Context not found"); //NOI18N
dbalek@164
   525
            return;
dbalek@164
   526
        }
dbalek@164
   527
        LOGGER.finest("Repair.translateClass: Repairing " + c); //NOI18N
dbalek@177
   528
        repairedClasses.add(c);
dbalek@50
   529
        Env<AttrContext> oldEnv = attrEnv;
dbalek@50
   530
        try {
dbalek@50
   531
            attrEnv = myEnv;
dbalek@50
   532
            TreeMaker oldMake = make;
dbalek@50
   533
            make = make.forToplevel(attrEnv.toplevel);
dbalek@53
   534
            boolean oldHasError = hasError;
dbalek@406
   535
            boolean oldIsErrClass = isErrClass;
dbalek@808
   536
            boolean oldInsideErrEnum = insideErrEnum;
dbalek@72
   537
            JCDiagnostic oldErr = err;
dbalek@88
   538
            JCTree oldClassLevelErrTree = classLevelErrTree;
dbalek@88
   539
            String oldClassLevelErrMessage = classLevelErrMessage;
dbalek@80
   540
            JCBlock oldStaticinit = staticInit;
dbalek@50
   541
            try {
dbalek@70
   542
                for (JCImport imp : attrEnv.toplevel.getImports()) {
dbalek@70
   543
                    translate(imp);
dbalek@88
   544
                    if (classLevelErrTree != null)
dbalek@70
   545
                        break;
dbalek@70
   546
                }
dbalek@72
   547
                hasError = false;
dbalek@5869
   548
                isErrClass |= c.type.isErroneous() || c.type == syms.unknownType;
dbalek@72
   549
                err = null;
dbalek@80
   550
                staticInit = null;
dbalek@50
   551
                JCClassDecl tree = (JCClassDecl)attrEnv.tree;
tzezula@1740
   552
                final Symbol enclosingElement = c.getEnclosingElement();
tzezula@1740
   553
                if (c.name == c.name.table.names.error &&
tzezula@1740
   554
                    enclosingElement.getKind() == ElementKind.PACKAGE) {
tzezula@1740
   555
                    final JavaFileObject source = c.sourcefile;
tzezula@1740
   556
                    final String path = source.toUri().getPath();
tzezula@1740
   557
                    int start = path.lastIndexOf('/');
tzezula@1740
   558
                    int end = path.lastIndexOf('.');
dbalek@5957
   559
                    if (end > start) {
dbalek@5957
   560
                        fixedTopLevelName = c.name.table.fromString(path.substring(start+1, end));
dbalek@5957
   561
                        c.name = fixedTopLevelName;
dbalek@5957
   562
                    }
tzezula@1740
   563
                    c.fullname = Symbol.TypeSymbol.formFullName(c.name, enclosingElement);
tzezula@1740
   564
                    c.flatname = c.fullname;
tzezula@1740
   565
                    tree.name = c.name;
tzezula@1740
   566
                    isErrClass = true;
tzezula@1740
   567
                    hasError = true;
tzezula@1740
   568
                    err = diags.error(
dbalek@4426
   569
                            null,
tzezula@1740
   570
                            log.currentSource(),
tzezula@1740
   571
                            tree,
tzezula@1740
   572
                            "expected",         //NOI18N
dbalek@2330
   573
                            Tokens.TokenKind.IDENTIFIER);
tzezula@1740
   574
                } else if (fixedTopLevelName != null) {
tzezula@1740
   575
                    c.fullname = Symbol.TypeSymbol.formFullName(c.name, enclosingElement);
tzezula@1740
   576
                    c.flatname = Symbol.TypeSymbol.formFlatName(c.name, enclosingElement);
tzezula@1740
   577
                }
dbalek@53
   578
                tree.mods = translate(tree.mods);
dbalek@53
   579
                tree.typarams = translateTypeParams(tree.typarams);
dbalek@53
   580
                tree.extending = translate(tree.extending);
dbalek@53
   581
                tree.implementing = translate(tree.implementing);
dbalek@428
   582
                if (!hasError && (err = log.getErrDiag(tree)) != null) {
dbalek@428
   583
                    hasError = true;
dbalek@428
   584
                    isErrClass = true;
dbalek@428
   585
                }
dbalek@4426
   586
                if ((isErrClass || insideErrEnum)
dbalek@480
   587
                        && ((c.flags_field & Flags.ENUM) != 0 || (tree.mods.flags & Flags.ENUM) != 0)) {
dbalek@808
   588
                    insideErrEnum = true;
dbalek@472
   589
                    hasError = true;
dbalek@472
   590
                    isErrClass = true;
dbalek@472
   591
                    classLevelErrTree = tree;
dbalek@472
   592
                }
dbalek@96
   593
                if (hasError && err != null) {
dbalek@452
   594
                    isErrClass = true;
dbalek@96
   595
                    classLevelErrTree = err.getTree();
dbalek@96
   596
                    classLevelErrMessage = err.getMessage(null);
dbalek@1604
   597
                } else if ((c.type.isErroneous() || c.type == syms.unknownType) && oldHasError && oldErr != null) {
dbalek@189
   598
                    classLevelErrTree = oldErr.getTree();
dbalek@189
   599
                    classLevelErrMessage = oldErr.getMessage(null);
dbalek@96
   600
                }
dbalek@53
   601
                if (tree.defs != null) {
dbalek@168
   602
                    HashSet<MethodSymbol> nonAbstractMethods = new HashSet<MethodSymbol>();
dbalek@4426
   603
                    for (Symbol sym : tree.sym.members_field.getSymbols()) {
dbalek@4426
   604
                        if (sym.kind == Kinds.Kind.MTH && (sym.flags_field & Flags.ABSTRACT) == 0 && sym.name != sym.name.table.names.clinit)
dbalek@4426
   605
                            nonAbstractMethods.add((MethodSymbol)sym);
dbalek@168
   606
                    }
dbalek@80
   607
                    List<JCTree> last = null;
dbalek@80
   608
                    for (List<JCTree> l = tree.defs; l != null && l.nonEmpty(); l = l.tail) {
dbalek@2330
   609
                        if (l.head.hasTag(JCTree.Tag.METHODDEF))
dbalek@168
   610
                            nonAbstractMethods.remove(((JCMethodDecl)l.head).sym);
dbalek@53
   611
                        hasError = false;
dbalek@72
   612
                        err = null;
dbalek@2330
   613
                        if (l.head.hasTag(JCTree.Tag.CLASSDEF) && ((JCClassDecl)l.head).name == c.name.table.names.error) {
dbalek@4426
   614
                            tree.sym.members_field.remove(((JCClassDecl)l.head).sym);
tzezula@1740
   615
                            if (last != null)
tzezula@1740
   616
                                last.tail = l.tail;
tzezula@1740
   617
                            else
tzezula@1740
   618
                                tree.defs = l.tail;
dbalek@80
   619
                        } else {
tzezula@1740
   620
                            l.head = translate(l.head);
dbalek@2330
   621
                            if ((l.head.hasTag(JCTree.Tag.METHODDEF) && ((JCMethodDecl)l.head).sym == null)
dbalek@2330
   622
                                    || (l.head.hasTag(JCTree.Tag.VARDEF) && ((JCVariableDecl)l.head).sym == null)) {
tzezula@1740
   623
                                hasError = true;
dbalek@2719
   624
                            } else if (c.type != syms.objectType && l.head.hasTag(JCTree.Tag.METHODDEF)
dbalek@2719
   625
                                    && ((JCMethodDecl)l.head).body != null
dbalek@2719
   626
                                    && ((JCMethodDecl)l.head).name == ((JCMethodDecl)l.head).name.table.names.init
dbalek@2718
   627
                                    && TreeInfo.firstConstructorCall(l.head) == null) {
dbalek@2870
   628
                                ((JCMethodDecl)l.head).body.stats = ((JCMethodDecl)l.head).body.stats.append(generateFakeConstructorCall(((JCMethodDecl)l.head).sym));
tzezula@1740
   629
                            }
tzezula@1740
   630
                            if (hasError) {
dbalek@2330
   631
                                if (l.head.hasTag(JCTree.Tag.CLASSDEF) && tree.sym.members_field.includes(((JCClassDecl)l.head).sym)) {
tzezula@1740
   632
                                    last = l;
tzezula@1740
   633
                                } else {
tzezula@1740
   634
                                    if (last != null)
tzezula@1740
   635
                                        last.tail = l.tail;
tzezula@1740
   636
                                    else
tzezula@1740
   637
                                        tree.defs = l.tail;
tzezula@1740
   638
                                }
tzezula@1740
   639
                                if (classLevelErrTree == null) {
tzezula@1740
   640
                                    if (err != null) {
tzezula@1740
   641
                                        classLevelErrTree = err.getTree();
tzezula@1740
   642
                                        classLevelErrMessage = err.getMessage(null);
tzezula@1740
   643
                                    } else {
tzezula@1740
   644
                                        classLevelErrTree = l.head;
tzezula@1740
   645
                                    }
tzezula@1740
   646
                                }
tzezula@1740
   647
                            } else {
tzezula@1740
   648
                                last = l;
tzezula@1740
   649
                            }
dbalek@80
   650
                        }
dbalek@53
   651
                    }
dbalek@88
   652
                    if (classLevelErrTree != null) {
dbalek@80
   653
                        if (staticInit != null)
dbalek@88
   654
                            staticInit.stats = List.of(generateErrStat(classLevelErrTree, classLevelErrMessage));
dbalek@80
   655
                        else
dbalek@88
   656
                            tree.defs = tree.defs.prepend(generateErrStaticInit(classLevelErrTree, classLevelErrMessage));
dbalek@80
   657
                    }
dbalek@168
   658
                    for (MethodSymbol symbol : nonAbstractMethods) {
dbalek@1759
   659
                        if ((symbol.flags() & Flags.BRIDGE) != 0) {
dbalek@1759
   660
                            continue;
dbalek@1759
   661
                        }
dbalek@407
   662
                        if ((symbol.owner.flags() & Flags.ENUM) != 0) {
dbalek@407
   663
                            if ((symbol.name == symbol.name.table.names.values
dbalek@407
   664
                                    && symbol.type.asMethodType().argtypes.isEmpty())
dbalek@407
   665
                                    || (symbol.name == symbol.name.table.names.valueOf
dbalek@1759
   666
                                    && types.isSameType(symbol.type.asMethodType().argtypes.head, enter.syms.stringType)
dbalek@407
   667
                                    && symbol.type.asMethodType().argtypes.tail.isEmpty())) {
dbalek@407
   668
                                continue;
dbalek@407
   669
                            }
dbalek@407
   670
                        }
dbalek@168
   671
                        tree.defs = tree.defs.prepend(generateErrMethod(symbol));
dbalek@168
   672
                    }
dbalek@53
   673
                }
dbalek@50
   674
            } finally {
dbalek@80
   675
                staticInit = oldStaticinit;
dbalek@88
   676
                classLevelErrTree = oldClassLevelErrTree;
dbalek@88
   677
                classLevelErrMessage = oldClassLevelErrMessage;
dbalek@72
   678
                err = oldErr;
dbalek@406
   679
                isErrClass = oldIsErrClass;
dbalek@808
   680
                insideErrEnum = oldInsideErrEnum;
dbalek@53
   681
                hasError = oldHasError;
dbalek@50
   682
                make = oldMake;
dbalek@50
   683
            }
dbalek@50
   684
        } finally {
dbalek@50
   685
            attrEnv = oldEnv;
dbalek@50
   686
        }
dbalek@43
   687
    }
dbalek@50
   688
dbalek@43
   689
    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree tree, TreeMaker localMake) {
dbalek@43
   690
        try {
dbalek@43
   691
            attrEnv = env;
dbalek@43
   692
            make = localMake;
dbalek@43
   693
            hasError = false;
dbalek@808
   694
            insideErrEnum = false;
dbalek@45
   695
            parents = List.nil();
dbalek@5948
   696
            if (runtimeExceptionConstructor == null) {
dbalek@5948
   697
                runtimeExceptionConstructor = rs.resolveConstructor(tree, attrEnv, syms.runtimeExceptionType, List.of(syms.stringType), null);
dbalek@5948
   698
            }
dbalek@5948
   699
            if (runtimeExceptionDefaultConstructor == null) {
dbalek@5948
   700
                runtimeExceptionDefaultConstructor = rs.resolveConstructor(tree, attrEnv, syms.runtimeExceptionType, List.<Type>nil(), null);
dbalek@5948
   701
            }
dbalek@43
   702
            return translate(tree);
dbalek@43
   703
        } finally {
dbalek@43
   704
            attrEnv = null;
dbalek@43
   705
            make = null;
tzezula@1740
   706
            fixedTopLevelName = null;
dbalek@43
   707
        }
dbalek@43
   708
    }
dbalek@62
   709
    
dbalek@62
   710
    public void flush() {
dbalek@177
   711
        repairedClasses.clear();
dbalek@62
   712
    }
dbalek@43
   713
}