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