Package com.google.gwt.dev.jjs.impl

Source Code of com.google.gwt.dev.jjs.impl.BuildTypeMap

/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.jjs.impl;

import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.js.JsniMethod;
import com.google.gwt.dev.js.JsParser;
import com.google.gwt.dev.js.JsParserException;
import com.google.gwt.dev.js.JsParserException.SourceDetail;
import com.google.gwt.dev.js.ast.JsExprStmt;
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsStatements;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.problem.ProblemHandler;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
* This is a Builder for {@link TypeMap}. The whole point of this pass is to
* create raw unfinished, unlinked AST nodes for types, methods, fields, and
* parameters, and to map the original JDT nodes to these AST nodes. That way
* when GenerateJavaDom runs, it just uses the TypeMap output from this Builder
* to retrieve whatever referenceable nodes it needs without worrying about
* whether they need to be created. Building our AST from JDT starts here.
*/
public class BuildTypeMap {

  /**
   * Creates JNodes for every method, field, initializer, parameter, and local
   * and memorizes the mapping from the JDT Binding to the corresponding JNode
   * for each thing created. Note that this pass also 1) sets up the super
   * type(s) for any member or local types created in BuildTypeMapVisitor (see
   * the comments there about why it had to be deferred). 2) adds each
   * user-defined type to a flat list. 3) Creates JNodes for all methods and
   * variables and memorizes the mapping from the JDT Binding to the
   * corresponding JNode for each created method and variable. 4) Maps all
   * synthetic arguments and fields for nested and local classes. 5) Slurps in
   * JSNI code for native methods as an opaque string.
   *
   * Note that methods and fields are not added to their classes here, that
   * isn't done until {@link GenerateJavaDom}.
   */
  private static class BuildDeclMapVisitor extends ASTVisitor {

    private static SourceInfo makeSourceInfo(
        AbstractMethodDeclaration methodDecl) {
      CompilationResult compResult = methodDecl.compilationResult;
      int[] indexes = compResult.lineSeparatorPositions;
      String fileName = String.valueOf(compResult.fileName);
      int startLine = ProblemHandler.searchLineNumber(indexes,
          methodDecl.sourceStart);
      return new SourceInfo(methodDecl.sourceStart, methodDecl.bodyEnd,
          startLine, fileName);
    }

    private static InternalCompilerException translateException(
        AbstractMethodDeclaration amd, Throwable e) {
      InternalCompilerException ice;
      if (e instanceof InternalCompilerException) {
        ice = (InternalCompilerException) e;
      } else {
        ice = new InternalCompilerException("Error building type map", e);
      }
      ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd));
      return ice;
    }

    private String currentFileName;
    private int[] currentSeparatorPositions;
    private final JsParser jsParser = new JsParser();
    private final JsProgram jsProgram;
    private JProgram program;
    private ArrayList/* <TypeDeclaration> */typeDecls = new ArrayList/* <TypeDeclaration> */();

    private final TypeMap typeMap;

    public BuildDeclMapVisitor(TypeMap typeMap, JsProgram jsProgram) {
      this.typeMap = typeMap;
      program = this.typeMap.getProgram();
      this.jsProgram = jsProgram;
    }

    public TypeDeclaration[] getTypeDeclarataions() {
      return (TypeDeclaration[]) typeDecls.toArray(new TypeDeclaration[typeDecls.size()]);
    }

    public boolean visit(Argument argument, BlockScope scope) {
      try {
        if (scope == scope.methodScope()) {
          return true;
        }

        SourceInfo info = makeSourceInfo(argument);
        LocalVariableBinding b = argument.binding;
        JType localType = (JType) typeMap.get(b.type);
        JMethod enclosingMethod = findEnclosingMethod(scope);
        JLocal newLocal = program.createLocal(info, argument.name, localType,
            b.isFinal(), enclosingMethod);
        typeMap.put(b, newLocal);
        return true;
      } catch (Throwable e) {
        throw translateException(argument, e);
      }
    }

    /**
     * Weird: we used to have JConstructor (and JConstructorCall) in our AST,
     * but we got rid of them completely and instead model them as instance
     * methods whose qualifier is a naked no-argument new operation. See
     * {@link GenerateJavaAST.JavaASTGenerationVisitor#processConstructor(ConstructorDeclaration)}
     * for details.
     */
    public boolean visit(ConstructorDeclaration ctorDecl, ClassScope scope) {
      try {
        MethodBinding b = ctorDecl.binding;
        JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType());
        String name = enclosingType.getShortName();
        SourceInfo info = makeSourceInfo(ctorDecl);
        JMethod newMethod = program.createMethod(info, name.toCharArray(),
            enclosingType, enclosingType, false, false, true, b.isPrivate(),
            false);
        mapThrownExceptions(newMethod, ctorDecl);

        // user args
        mapParameters(newMethod, ctorDecl);
        // original params are now frozen

        int syntheticParamCount = 0;
        ReferenceBinding declaringClass = b.declaringClass;
        if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
          // add synthetic args for outer this and locals
          NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
          Set alreadyNamedVariables = new HashSet();
          if (nestedBinding.enclosingInstances != null) {
            for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
              SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
              String argName = String.valueOf(arg.name);
              if (alreadyNamedVariables.contains(argName)) {
                argName += "_" + i;
              }
              createParameter(arg, argName, newMethod);
              ++syntheticParamCount;
              alreadyNamedVariables.add(argName);
            }
          }

          if (nestedBinding.outerLocalVariables != null) {
            for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
              SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
              String argName = String.valueOf(arg.name);
              if (alreadyNamedVariables.contains(argName)) {
                argName += "_" + i;
              }
              createParameter(arg, argName, newMethod);
              ++syntheticParamCount;
              alreadyNamedVariables.add(argName);
            }
          }
        }

        typeMap.put(b, newMethod);
        return true;
      } catch (Throwable e) {
        throw translateException(ctorDecl, e);
      }
    }

    public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
      try {
        FieldBinding b = fieldDeclaration.binding;
        SourceInfo info = makeSourceInfo(fieldDeclaration);
        JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
        createField(info, b, enclosingType,
            fieldDeclaration.initialization != null);
        return true;
      } catch (Throwable e) {
        throw translateException(fieldDeclaration, e);
      }
    }

    public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
      try {
        LocalVariableBinding b = localDeclaration.binding;
        JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType);
        JMethod enclosingMethod = findEnclosingMethod(scope);
        SourceInfo info = makeSourceInfo(localDeclaration);
        JLocal newLocal = program.createLocal(info, localDeclaration.name,
            localType, b.isFinal(), enclosingMethod);
        typeMap.put(b, newLocal);
        return true;
      } catch (Throwable e) {
        throw translateException(localDeclaration, e);
      }
    }

    public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
      try {
        MethodBinding b = methodDeclaration.binding;
        SourceInfo info = makeSourceInfo(methodDeclaration);
        JType returnType = (JType) typeMap.get(methodDeclaration.returnType.resolvedType);
        JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
        JMethod newMethod = program.createMethod(info,
            methodDeclaration.selector, enclosingType, returnType,
            b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(),
            b.isNative());

        mapThrownExceptions(newMethod, methodDeclaration);
        mapParameters(newMethod, methodDeclaration);
        typeMap.put(b, newMethod);

        if (newMethod.isNative()) {
          // Handle JSNI block
          char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents();
          String jsniCode = String.valueOf(source, methodDeclaration.bodyStart,
              methodDeclaration.bodyEnd - methodDeclaration.bodyStart + 1);
          int startPos = jsniCode.indexOf("/*-{");
          int endPos = jsniCode.lastIndexOf("}-*/");
          if (startPos < 0 && endPos < 0) {
            GenerateJavaAST.reportJsniError(
                info,
                methodDeclaration,
                "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/");
            return true;
          }
          if (startPos < 0) {
            GenerateJavaAST.reportJsniError(info, methodDeclaration,
                "Unable to find start of native block; begin your JavaScript block with: /*-{");
            return true;
          }
          if (endPos < 0) {
            GenerateJavaAST.reportJsniError(
                info,
                methodDeclaration,
                "Unable to find end of native block; terminate your JavaScript block with: }-*/");
            return true;
          }

          startPos += 3; // move up to open brace
          endPos += 1; // move past close brace

          jsniCode = jsniCode.substring(startPos, endPos);

          // Here we parse it as an anonymous function, but we will give it a
          // name later when we generate the JavaScript during code generation.
          //
          String syntheticFnHeader = "function (";
          boolean first = true;
          for (int i = 0; i < newMethod.params.size(); ++i) {
            JParameter param = (JParameter) newMethod.params.get(i);
            if (first) {
              first = false;
            } else {
              syntheticFnHeader += ',';
            }
            syntheticFnHeader += param.getName();
          }
          syntheticFnHeader += ')';
          StringReader sr = new StringReader(syntheticFnHeader + '\n'
              + jsniCode);
          try {
            // start at -1 to avoid counting our synthetic header
            // TODO: get the character position start correct
            JsStatements result = jsParser.parse(jsProgram.getScope(), sr, -1);
            JsExprStmt jsExprStmt = (JsExprStmt) result.get(0);
            JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression();
            ((JsniMethod) newMethod).setFunc(jsFunction);
          } catch (IOException e) {
            throw new InternalCompilerException(
                "Internal error parsing JSNI in method '" + newMethod
                    + "' in type '" + enclosingType.getName() + "'", e);
          } catch (JsParserException e) {
            /*
             * count the number of characters to the problem (from the start of
             * the JSNI code)
             */
            SourceDetail detail = e.getSourceDetail();
            int line = detail.getLine();
            char[] chars = jsniCode.toCharArray();
            int i = 0, n = chars.length;
            while (line > 0) {
              // CHECKSTYLE_OFF
              switch (chars[i]) {
                case '\r':
                  // if skip an extra character if this is a CR/LF
                  if (i + 1 < n && chars[i + 1] == '\n') {
                    ++i;
                  }
                  // intentional fall-through
                case '\n':
                  --line;
                  // intentional fall-through
                default:
                  ++i;
              }
              // CHECKSTYLE_ON
            }

            // TODO: check this
            // Map into the original source stream;
            i += startPos + detail.getLineOffset();
            info = new SourceInfo(i, i,
                info.getStartLine() + detail.getLine(), info.getFileName());
            GenerateJavaAST.reportJsniError(info, methodDeclaration,
                e.getMessage());
          }
        }

        return true;
      } catch (Throwable e) {
        throw translateException(methodDeclaration, e);
      }
    }

    public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
      return process(localTypeDeclaration);
    }

    public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
      return process(memberTypeDeclaration);
    }

    public boolean visit(TypeDeclaration typeDeclaration,
        CompilationUnitScope scope) {
      return process(typeDeclaration);
    }

    private JField createField(SourceInfo info, FieldBinding binding,
        JReferenceType enclosingType, boolean hasInitializer) {
      JType type = (JType) typeMap.get(binding.type);
      JField field = program.createField(info, binding.name, enclosingType,
          type, binding.isStatic(), binding.isFinal(), hasInitializer);
      typeMap.put(binding, field);
      return field;
    }

    private JField createField(SyntheticArgumentBinding binding,
        JReferenceType enclosingType) {
      JType type = (JType) typeMap.get(binding.type);
      JField field = program.createField(null, binding.name, enclosingType,
          type, false, true, true);
      if (binding.matchingField != null) {
        typeMap.put(binding.matchingField, field);
      }
      typeMap.put(binding, field);
      return field;
    }

    private JParameter createParameter(LocalVariableBinding binding,
        JMethod enclosingMethod) {
      JType type = (JType) typeMap.get(binding.type);
      SourceInfo info = makeSourceInfo(binding.declaration);
      JParameter param = program.createParameter(info, binding.name, type,
          binding.isFinal(), enclosingMethod);
      typeMap.put(binding, param);
      return param;
    }

    private JParameter createParameter(SyntheticArgumentBinding arg,
        String argName, JMethod enclosingMethod) {
      JType type = (JType) typeMap.get(arg.type);
      JParameter param = program.createParameter(null, argName.toCharArray(),
          type, true, enclosingMethod);
      return param;
    }

    private JMethod findEnclosingMethod(BlockScope scope) {
      MethodScope methodScope = scope.methodScope();
      if (methodScope.isInsideInitializer()) {
        JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.classScope().referenceContext.binding);
        if (methodScope.isStatic) {
          // clinit
          return (JMethod) enclosingType.methods.get(0);
        } else {
          // init
          assert (enclosingType instanceof JClassType);
          return (JMethod) enclosingType.methods.get(1);
        }
      }

      AbstractMethodDeclaration referenceMethod = methodScope.referenceMethod();
      return (JMethod) typeMap.get(referenceMethod.binding);
    }

    private SourceInfo makeSourceInfo(Statement stmt) {
      int startLine = ProblemHandler.searchLineNumber(
          currentSeparatorPositions, stmt.sourceStart);
      return new SourceInfo(stmt.sourceStart, stmt.sourceEnd, startLine,
          currentFileName);
    }

    private void mapParameters(JMethod method, AbstractMethodDeclaration x) {
      MethodBinding b = x.binding;
      int paramCount = (b.parameters != null ? b.parameters.length : 0);
      if (paramCount > 0) {
        for (int i = 0, n = x.arguments.length; i < n; ++i) {
          createParameter(x.arguments[i].binding, method);
        }
      }
      method.freezeParamTypes();
    }

    private void mapThrownExceptions(JMethod method, AbstractMethodDeclaration x) {
      MethodBinding b = x.binding;
      if (b.thrownExceptions != null) {
        for (int i = 0; i < b.thrownExceptions.length; ++i) {
          ReferenceBinding refBinding = b.thrownExceptions[i];
          JClassType thrownException = (JClassType) typeMap.get(refBinding);
          method.thrownExceptions.add(thrownException);
        }
      }
    }

    /**
     * Add synthetic fields, setup super types. You'll notice that we DON'T have
     * any concept of "inner" or "outer" types in our AST. Truth is, we found it
     * easier to simply model everything as flat classes and emulate the nesting
     * behavior (and final local access on local classes). It's much closer to
     * how we'll eventually be generating JavaScript code (code generation is
     * more straightforward), it makes for fewer kinds of things to worry about
     * when optimizing (more aggressive optimizations), and it's how Java
     * actually implements the stuff under the hood anyway.
     */
    private boolean process(TypeDeclaration typeDeclaration) {
      CompilationResult compResult = typeDeclaration.compilationResult;
      currentSeparatorPositions = compResult.lineSeparatorPositions;
      currentFileName = String.valueOf(compResult.fileName);
      SourceTypeBinding binding = typeDeclaration.binding;
      if (binding.constantPoolName() == null) {
        /*
         * Weird case: if JDT determines that this local class is totally
         * uninstantiable, it won't bother allocating a local name.
         */
        return false;
      }
      JReferenceType type = (JReferenceType) typeMap.get(binding);
      try {
        if (binding.isNestedType() && !binding.isStatic()) {
          // add synthetic fields for outer this and locals
          assert (type instanceof JClassType);
          NestedTypeBinding nestedBinding = (NestedTypeBinding) binding;
          if (nestedBinding.enclosingInstances != null) {
            for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
              SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
              if (arg.matchingField != null) {
                createField(arg, type);
              }
            }
          }

          if (nestedBinding.outerLocalVariables != null) {
            for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
              SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
              createField(arg, type);
            }
          }
        }

        ReferenceBinding superClassBinding = binding.superclass();
        if (superClassBinding != null) {
          assert (binding.superclass().isClass());
          JClassType superClass = (JClassType) typeMap.get(superClassBinding);
          type.extnds = superClass;
        }

        ReferenceBinding[] superInterfaces = binding.superInterfaces();
        for (int i = 0; i < superInterfaces.length; ++i) {
          ReferenceBinding superInterfaceBinding = superInterfaces[i];
          assert (superInterfaceBinding.isInterface());
          JInterfaceType superInterface = (JInterfaceType) typeMap.get(superInterfaceBinding);
          type.implments.add(superInterface);
        }
        typeDecls.add(typeDeclaration);
        return true;
      } catch (InternalCompilerException ice) {
        ice.addNode(type);
        throw ice;
      } catch (Throwable e) {
        throw new InternalCompilerException(type, "Error building type map", e);
      }
    }

    private InternalCompilerException translateException(Statement stmt,
        Throwable e) {
      InternalCompilerException ice;
      if (e instanceof InternalCompilerException) {
        ice = (InternalCompilerException) e;
      } else {
        ice = new InternalCompilerException("Error building type map", e);
      }
      ice.addNode(stmt.getClass().getName(), stmt.toString(),
          makeSourceInfo(stmt));
      return ice;
    }
  }

  /**
   * Creates JNodes for every type and memorizes the mapping from the JDT
   * Binding to the corresponding JNode for each created type. Note that since
   * there could be forward references, it is not possible to set up super types;
   * it must be done is a subsequent pass.
   */
  private static class BuildTypeMapVisitor extends ASTVisitor {

    private static SourceInfo makeSourceInfo(TypeDeclaration typeDecl) {
      CompilationResult compResult = typeDecl.compilationResult;
      int[] indexes = compResult.lineSeparatorPositions;
      String fileName = String.valueOf(compResult.fileName);
      int startLine = ProblemHandler.searchLineNumber(indexes,
          typeDecl.sourceStart);
      return new SourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd, startLine,
          fileName);
    }

    private static InternalCompilerException translateException(
        TypeDeclaration typeDecl, Throwable e) {
      InternalCompilerException ice;
      if (e instanceof InternalCompilerException) {
        ice = (InternalCompilerException) e;
      } else {
        ice = new InternalCompilerException("Error building type map", e);
      }
      ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(),
          makeSourceInfo(typeDecl));
      return ice;
    }

    private final JProgram program;
    private final TypeMap typeMap;

    public BuildTypeMapVisitor(TypeMap typeMap) {
      this.typeMap = typeMap;
      program = this.typeMap.getProgram();
    }

    public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
      assert (localTypeDeclaration.kind() != IGenericType.INTERFACE_DECL);
      return process(localTypeDeclaration);
    }

    public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
      return process(memberTypeDeclaration);
    }

    public boolean visit(TypeDeclaration typeDeclaration,
        CompilationUnitScope scope) {
      return process(typeDeclaration);
    }

    private boolean process(TypeDeclaration typeDeclaration) {
      try {
        char[][] name = typeDeclaration.binding.compoundName;
        SourceTypeBinding binding = typeDeclaration.binding;
        if (binding instanceof LocalTypeBinding) {
          char[] localName = binding.constantPoolName();
          if (localName == null) {
            /*
             * Weird case: if JDT determines that this local class is totally
             * uninstantiable, it won't bother allocating a local name.
             */
            return false;
          }

          for (int i = 0, c = localName.length; i < c; ++i) {
            if (localName[i] == '/') {
              localName[i] = '.';
            }
          }
          name = new char[1][0];
          name[0] = localName;
        }

        SourceInfo info = makeSourceInfo(typeDeclaration);
        JReferenceType newType;
        if (binding.isClass()) {
          newType = program.createClass(info, name, binding.isAbstract(),
              binding.isFinal());
        } else if (binding.isInterface()) {
          newType = program.createInterface(info, name);
        } else {
          assert (false);
          return false;
        }

        /**
         * We emulate static initializers and instance initializers as methods.
         * As in other cases, this gives us: simpler AST, easier to optimize,
         * more like output JavaScript. Clinit is always in slot 0, init (if it
         * exists) is always in slot 1.
         */
        JMethod clinit = program.createMethod(null, "$clinit".toCharArray(),
            newType, program.getTypeVoid(), false, true, true, true, false);
        clinit.freezeParamTypes();

        if (newType instanceof JClassType) {
          JMethod init = program.createMethod(null, "$init".toCharArray(),
              newType, program.getTypeVoid(), false, false, true, true, false);
          init.freezeParamTypes();
        }

        typeMap.put(binding, newType);
        return true;
      } catch (Throwable e) {
        throw translateException(typeDeclaration, e);
      }
    }
  }

  public static TypeDeclaration[] exec(TypeMap typeMap,
      CompilationUnitDeclaration[] unitDecls, JsProgram jsProgram) {
    createPeersForTypes(unitDecls, typeMap);
    return createPeersForNonTypeDecls(unitDecls, typeMap, jsProgram);
  }

  private static TypeDeclaration[] createPeersForNonTypeDecls(
      CompilationUnitDeclaration[] unitDecls, TypeMap typeMap,
      JsProgram jsProgram) {
    // Traverse again to create our JNode peers for each method, field,
    // parameter, and local
    BuildDeclMapVisitor v2 = new BuildDeclMapVisitor(typeMap, jsProgram);
    for (int i = 0; i < unitDecls.length; ++i) {
      unitDecls[i].traverse(v2, unitDecls[i].scope);
    }
    return v2.getTypeDeclarataions();
  }

  private static void createPeersForTypes(
      CompilationUnitDeclaration[] unitDecls, TypeMap typeMap) {
    // Traverse once to create our JNode peers for each type
    BuildTypeMapVisitor v1 = new BuildTypeMapVisitor(typeMap);
    for (int i = 0; i < unitDecls.length; ++i) {
      unitDecls[i].traverse(v1, unitDecls[i].scope);
    }
  }

}
TOP

Related Classes of com.google.gwt.dev.jjs.impl.BuildTypeMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.