All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.uibinder.rebind.FieldReference Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2009 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.uibinder.rebind;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;

import java.util.LinkedHashSet;

/**
 * Represents a {field.reference}. Collects all the types a
 * particular reference has been asked to return, and can validate that it
 * actually does so.
 */
public class FieldReference {
  private final FieldManager fieldManager;

  private final String debugString;
  private final String[] elements;
  private final LinkedHashSet leftHandTypes = new LinkedHashSet();

  private final TypeOracle types;

  FieldReference(String reference, FieldManager fieldManager, TypeOracle types) {
    this.debugString = "{" + reference + "}";
    this.fieldManager = fieldManager;
    this.types = types;
    elements = reference.split("\\.");
  }

  public void addLeftHandType(JType type) {
    leftHandTypes.add(type);
  }

  public String getFieldName() {
    return elements[0];
  }

  @Override
  public String toString() {
    return debugString;
  }

  public void validate(MonitoredLogger logger) {
    JType myReturnType = findReturnType(logger);
    if (myReturnType == null) {
      return;
    }

    for (JType t : leftHandTypes) {
      ensureAssignable(t, myReturnType, logger);
    }
  }

  /**
   * Returns a failure message if the types don't mesh, or null on success.
   */
  private void ensureAssignable(JType leftHandType, JType rightHandType,
      MonitoredLogger logger) {

    if (leftHandType == rightHandType) {
      return;
    }

    if (handleMismatchedNumbers(leftHandType, rightHandType)) {
      return;
    }

    if (handleMismatchedNonNumericPrimitives(leftHandType, rightHandType,
        logger)) {
      return;
    }

    JClassType leftClass = leftHandType.isClassOrInterface();
    if (leftClass != null) {
      JClassType rightClass = rightHandType.isClassOrInterface();
      if ((rightClass == null) || !leftClass.isAssignableFrom(rightClass)) {
        logTypeMismatch(leftHandType, rightHandType, logger);
      }
    }

    /*
     * We're conservative and fall through here, allowing success. Not yet
     * confident that we know every error case, and are more worried about being
     * artificially restrictive.
     */
  }

  private JType findReturnType(MonitoredLogger logger) {
    FieldWriter field = fieldManager.lookup(elements[0]);
    if (field == null) {
      logger.error("No field named %s", elements[0]);
      return null;
    }

    return field.getReturnType(elements, logger);
  }

  private boolean handleMismatchedNonNumericPrimitives(JType leftHandType,
      JType rightHandType, MonitoredLogger logger) {
    JPrimitiveType leftPrimitive = leftHandType.isPrimitive();
    JPrimitiveType rightPrimitive = rightHandType.isPrimitive();

    if (leftPrimitive == null && rightPrimitive == null) {
      return false;
    }

    if (leftPrimitive != null) {
      JClassType autobox = types.findType(leftPrimitive.getQualifiedBoxedSourceName());
      if (rightHandType != autobox) {
        logger.error("Returns %s, can't be used as %s", rightHandType,
            leftHandType);
      }
    } else { // rightPrimitive != null
      JClassType autobox = types.findType(rightPrimitive.getQualifiedBoxedSourceName());
      if (leftHandType != autobox) {
        logger.error("Returns %s, can't be used as %s", rightHandType,
            leftHandType);
      }
    }

    return true;
  }

  private boolean handleMismatchedNumbers(JType leftHandType,
      JType rightHandType) {
    /*
     * int i = (int) 1.0 is okay
     * Integer i = (int) 1.0 is okay
     * int i = (int) Double.valueOf(1.0) is not
     */
    if (isNumber(leftHandType) && isNumber(rightHandType)
        && (rightHandType.isPrimitive() != null)) {
      return true; // They will be cast into submission
    }

    return false;
  }

  private boolean isNumber(JType t) {
    JClassType numberType = types.findType(Number.class.getCanonicalName());

    JClassType asClass = t.isClass();
    if (asClass != null) {
      return numberType.isAssignableFrom(asClass);
    }

    JPrimitiveType asPrimitive = t.isPrimitive();
    if (asPrimitive != null) {
      JClassType autoboxed = types.findType(asPrimitive.getQualifiedBoxedSourceName());
      return numberType.isAssignableFrom(autoboxed);
    }

    return false;
  }

  private void logTypeMismatch(JType leftHandType, JType rightHandType,
      MonitoredLogger logger) {
    logger.error("Returns %s, can't be used as %s", rightHandType, leftHandType);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy