src/com/google/javascript/jscomp/AmbiguateProperties.java
/**
   * Adds subtypes - and implementors, in the case of interfaces - of the type
   * to its JSTypeBitSet of related types. Union types are decomposed into their
   * alternative types.
   *
   * <p>The 'is related to' relationship is best understood graphically. Draw an
   * arrow from each instance type to the prototype of each of its
   * subclass. Draw an arrow from each prototype to its instance type. Draw an
   * arrow from each interface to its implementors. A type is related to another
   * if there is a directed path in the graph from the type to other. Thus, the
   * 'is related to' relationship is reflexive and transitive.
   *
   * <p>Example with Foo extends Bar which extends Baz and Bar implements I:
   * <pre>{@code
   * Foo -> Bar.prototype -> Bar -> Baz.prototype -> Baz
   *                          ^
   *                          |
   *                          I
   * }</pre>
   *
   * <p>Note that we don't need to correctly handle the relationships between
   * functions, because the function type is invalidating (i.e. its properties
   * won't be ambiguated).
   */
Adds subtypes - and implementors, in the case of interfaces - of the type
to its JSTypeBitSet of related types. Union types are decomposed into their
alternative types.

The 'is related to' relationship is best understood graphically. Draw an
arrow from each instance type to the prototype of each of its
subclass. Draw an arrow from each prototype to its instance type. Draw an
arrow from each interface to its implementors. A type is related to another
if there is a directed path in the graph from the type to other. Thus, the
'is related to' relationship is reflexive and transitive.

Example with Foo extends Bar which extends Baz and Bar implements I:
{@code
Foo -> Bar.prototype -> Bar -> Baz.prototype -> Baz
^
|
I
}

Note that we don't need to correctly handle the relationships between
functions, because the function type is invalidating .
Adds subtypes - and implementors in the case of interfaces - of the type to its JSTypeBitSet of related types . Union types are decomposed into their alternative types . The ' is related to ' relationship is best understood graphically . Draw an arrow from each instance type to the prototype of each of its subclass . Draw an arrow from each prototype to its instance type . Draw an arrow from each interface to its implementors . A type is related to another if there is a directed path in the graph from the type to other . Thus the ' is related to ' relationship is reflexive and transitive . Example with Foo extends Bar which extends Baz and Bar implements I : { @code Foo - > Bar . prototype - > Bar - > Baz . prototype - > Baz ^ | I } Note that we don ' t need to correctly handle the relationships between functions because the function type is invalidating .
private void computeRelatedTypes(JSType type) {
    if (type.isUnionType()) {
      type = type.restrictByNotNullOrUndefined();
      if (type.isUnionType()) {
        for (JSType alt : type.getUnionMembers()) {
           computeRelatedTypes(alt);
        }
        return;
      }
    }
    if (relatedBitsets.containsKey(type)) {
      return;
    }
    JSTypeBitSet related = new JSTypeBitSet(intForType.size());
    relatedBitsets.put(type, related);
    related.set(getIntForType(type));
    if (type.isFunctionPrototypeType()) {
      FunctionType maybeCtor = type.toMaybeObjectType().getOwnerFunction();
      if (maybeCtor.isConstructor() || maybeCtor.isInterface()) {
        addRelatedInstance(maybeCtor, related);
      }
      return;
    }
    FunctionType constructor = type.toMaybeObjectType().getConstructor();
    if (constructor != null) {
      for (FunctionType subType : constructor.getDirectSubTypes()) {
        addRelatedInstance(subType, related);
      }
    }
  }
private void computeRelatedTypes ( JSType type ) { if ( type . isUnionType ( ) ) { type = type . restrictByNotNullOrUndefined ( ) ; if ( type . isUnionType ( ) ) { for ( JSType alt : type . getUnionMembers ( ) ) { computeRelatedTypes ( alt ) ; } return ; } } if ( relatedBitsets . containsKey ( type ) ) { return ; } JSTypeBitSet related = new JSTypeBitSet ( intForType . size ( ) ) ; relatedBitsets . put ( type , related ) ; related . set ( getIntForType ( type ) ) ; if ( type . isFunctionPrototypeType ( ) ) { FunctionType maybeCtor = type . toMaybeObjectType ( ) . getOwnerFunction ( ) ; if ( maybeCtor . isConstructor ( ) || maybeCtor . isInterface ( ) ) { addRelatedInstance ( maybeCtor , related ) ; } return ; } FunctionType constructor = type . toMaybeObjectType ( ) . getConstructor ( ) ; if ( constructor != null ) { for ( FunctionType subType : constructor . getDirectSubTypes ( ) ) { addRelatedInstance ( subType , related ) ; } } }
Adds subtypes - and implementors, in the case of interfaces - of the type
 to its JSTypeBitSet of related types.
Adds subtypes - and implementors in the case of interfaces - of the type to its JSTypeBitSet of related types .
// We only need to generate the bit set once. // A prototype is related to its instance. // A class/interface is related to its subclasses/implementors.