/* * Copyright 2013 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.javac.JsInteropUtil; import com.google.gwt.dev.jjs.ast.JArrayType; import com.google.gwt.dev.jjs.ast.JClassType; import com.google.gwt.dev.jjs.ast.JPrimitiveType; 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.thirdparty.guava.common.collect.ImmutableMap; import java.util.Map; /** * TypeCategory classifies Java types into different categories. <p> * * These are used in Cast checking and array implementation. */ public enum TypeCategory { /* * Enum list is kept in sync with the one in Array.java. * * TYPE_JAVA_LANG_* is kept in sync with JProgram.DispatchType. * * TypeCategory.castInstanceOfQualifier is kept in sync with Cast.java. * * Also note that we have separate categories for boxed types (e.g. JAVA_LANG_DOUBLE vs. * PRIMITIVE_NUMBER), as we need the separation of the two for array initialization purposes (e.g. * initialize to zero vs. null). */ TYPE_JAVA_OBJECT("", true, false), TYPE_JAVA_OBJECT_OR_JSO("AllowJso", true, false), TYPE_JSO("Jso"), TYPE_ARRAY("Array"), TYPE_JSO_ARRAY("JsoArray", true, false), TYPE_JAVA_LANG_OBJECT("AllowJso", true, false), TYPE_JAVA_LANG_STRING("String"), TYPE_JAVA_LANG_DOUBLE("Double"), TYPE_JAVA_LANG_BOOLEAN("Boolean"), TYPE_JS_NATIVE("Native", false, true), TYPE_JS_UNKNOWN_NATIVE("UnknownNative"), TYPE_JS_FUNCTION("Function"), TYPE_JS_OBJECT("JsObject"), TYPE_JS_ARRAY("JsArray"), // Primitive types are meant to be consecutive. TYPE_PRIMITIVE_LONG, TYPE_PRIMITIVE_NUMBER, TYPE_PRIMITIVE_BOOLEAN; private final String castInstanceOfQualifier; private final boolean requiresTypeId; private final boolean requiresConstructor; TypeCategory() { this(null, false, false); } TypeCategory(String castInstanceOfQualifier) { this(castInstanceOfQualifier, false, false); } TypeCategory( String castInstanceOfQualifier, boolean requiresTypeId, boolean requiresConstructor) { this.castInstanceOfQualifier = castInstanceOfQualifier; this.requiresTypeId = requiresTypeId; this.requiresConstructor = requiresConstructor; } public String castInstanceOfQualifier() { return castInstanceOfQualifier; } public boolean requiresTypeId() { return requiresTypeId; } public boolean requiresJsConstructor() { return requiresConstructor; } /** * Determines the type category for a specific type. */ public static TypeCategory typeCategoryForType(JType type, JProgram program) { if (type.isPrimitiveType()) { if (type == JPrimitiveType.BOOLEAN) { return TypeCategory.TYPE_PRIMITIVE_BOOLEAN; } else if (type == JPrimitiveType.LONG) { return TypeCategory.TYPE_PRIMITIVE_LONG; } else { return TypeCategory.TYPE_PRIMITIVE_NUMBER; } } assert type instanceof JReferenceType; type = type.getUnderlyingType(); if (type == program.getTypeJavaLangObjectArray()) { return TypeCategory.TYPE_ARRAY; } else if (isJsoArray(type)) { return TypeCategory.TYPE_JSO_ARRAY; } else if (getJsSpecialType(type) != null) { return getJsSpecialType(type); } else if (program.isUntypedArrayType(type)) { return TypeCategory.TYPE_JS_ARRAY; } else if (type == program.getTypeJavaLangObject()) { return TypeCategory.TYPE_JAVA_LANG_OBJECT; } else if (program.getRepresentedAsNativeTypesDispatchMap().containsKey(type)) { return program.getRepresentedAsNativeTypesDispatchMap().get(type).getTypeCategory(); } else if (program.typeOracle.isEffectivelyJavaScriptObject(type)) { return TypeCategory.TYPE_JSO; } else if (program.typeOracle.isDualJsoInterface(type)) { return TypeCategory.TYPE_JAVA_OBJECT_OR_JSO; } else if (program.typeOracle.isNoOpCast(type)) { return TypeCategory.TYPE_JS_UNKNOWN_NATIVE; } else if (type instanceof JClassType && type.isJsNative()) { return TypeCategory.TYPE_JS_NATIVE; } else if (type.isJsFunction() || type.isJsFunctionImplementation()) { return TypeCategory.TYPE_JS_FUNCTION; } return TypeCategory.TYPE_JAVA_OBJECT; } private static Map<String, TypeCategory> specialGlobalNames = ImmutableMap.<String,TypeCategory>builder() .put("Object", TYPE_JS_OBJECT) .put("Function", TYPE_JS_FUNCTION) .put("Array", TYPE_JS_ARRAY) .put("Number", TYPE_JAVA_LANG_DOUBLE) .put("String", TYPE_JAVA_LANG_STRING) .build(); private static TypeCategory getJsSpecialType(JType type) { if (!(type instanceof JClassType) || !type.isJsNative()) { return null; } JClassType classType = (JClassType) type; if (!JsInteropUtil.isGlobal(classType.getJsNamespace())) { return null; } return specialGlobalNames.get(classType.getJsName()); } private static boolean isJsoArray(JType type) { if (!type.isArrayType()) { return false; } JArrayType arrayType = (JArrayType) type; return arrayType.getLeafType().isJsoType(); } }