예제 #1
0
 /**
  * Returns the given reference value that may or may not be null, ensuring that it is a
  * TypedReferenceValue, not a subclass.
  */
 private static ReferenceValue typedReferenceValue(
     TypedReferenceValue referenceValue, boolean mayBeNull) {
   return referenceValue.getClass() == TypedReferenceValue.class
       ? referenceValue.generalizeMayBeNull(mayBeNull)
       : new TypedReferenceValue(referenceValue.type, referenceValue.referencedClass, mayBeNull);
 }
예제 #2
0
  public ReferenceValue generalize(TypedReferenceValue other) {
    // If both types are identical, the generalization is the same too.
    if (this.equals(other)) {
      return this;
    }

    String thisType = this.type;
    String otherType = other.type;

    // If both types are nul, the generalization is null too.
    if (thisType == null && otherType == null) {
      return ValueFactory.REFERENCE_VALUE_NULL;
    }

    // If this type is null, the generalization is the other type, maybe null.
    if (thisType == null) {
      return other.generalizeMayBeNull(true);
    }

    // If the other type is null, the generalization is this type, maybe null.
    if (otherType == null) {
      return this.generalizeMayBeNull(true);
    }

    boolean mayBeNull = this.mayBeNull || other.mayBeNull;

    // If the two types are equal, the generalization remains the same, maybe null.
    if (thisType.equals(otherType)) {
      return typedReferenceValue(this, mayBeNull);
    }

    // Start taking into account the type dimensions.
    int thisDimensionCount = ClassUtil.internalArrayTypeDimensionCount(thisType);
    int otherDimensionCount = ClassUtil.internalArrayTypeDimensionCount(otherType);
    int commonDimensionCount = Math.min(thisDimensionCount, otherDimensionCount);

    if (thisDimensionCount == otherDimensionCount) {
      // See if we can take into account the referenced classes.
      Clazz thisReferencedClass = this.referencedClass;
      Clazz otherReferencedClass = other.referencedClass;

      if (thisReferencedClass != null && otherReferencedClass != null) {
        // Is one class simply an extension of the other one?
        if (thisReferencedClass.extendsOrImplements(otherReferencedClass)) {
          return typedReferenceValue(other, mayBeNull);
        }

        if (otherReferencedClass.extendsOrImplements(thisReferencedClass)) {
          return typedReferenceValue(this, mayBeNull);
        }

        // Do the classes have a non-trivial common superclass?
        Clazz commonClass = findCommonClass(thisReferencedClass, otherReferencedClass, false);

        if (commonClass.getName().equals(ClassConstants.NAME_JAVA_LANG_OBJECT)) {
          // Otherwise, do the classes have a common interface?
          Clazz commonInterface = findCommonClass(thisReferencedClass, otherReferencedClass, true);
          if (commonInterface != null) {
            commonClass = commonInterface;
          }
        }

        return new TypedReferenceValue(
            commonDimensionCount == 0
                ? commonClass.getName()
                : ClassUtil.internalArrayTypeFromClassName(
                    commonClass.getName(), commonDimensionCount),
            commonClass,
            mayBeNull);
      }
    } else if (thisDimensionCount > otherDimensionCount) {
      // See if the other type is an interface type of arrays.
      if (ClassUtil.isInternalArrayInterfaceName(
          ClassUtil.internalClassNameFromClassType(otherType))) {
        return typedReferenceValue(other, mayBeNull);
      }
    } else if (thisDimensionCount < otherDimensionCount) {
      // See if this type is an interface type of arrays.
      if (ClassUtil.isInternalArrayInterfaceName(
          ClassUtil.internalClassNameFromClassType(thisType))) {
        return typedReferenceValue(this, mayBeNull);
      }
    }

    // Reduce the common dimension count if either type is an array of
    // primitives type of this dimension.
    if (commonDimensionCount > 0
            && (ClassUtil.isInternalPrimitiveType(otherType.charAt(commonDimensionCount)))
        || ClassUtil.isInternalPrimitiveType(thisType.charAt(commonDimensionCount))) {
      commonDimensionCount--;
    }

    // Fall back on a basic Object or array of Objects type.
    return commonDimensionCount != 0
        ? new TypedReferenceValue(
            ClassUtil.internalArrayTypeFromClassName(
                ClassConstants.NAME_JAVA_LANG_OBJECT, commonDimensionCount),
            null,
            mayBeNull)
        : mayBeNull
            ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL
            : ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL;
  }