private ObjectType getTypeWithProperty ( String field , JSType type ) { if ( type == null ) { return null ; } ObjectType foundType = gtwpCacheGet ( field , type ) ; if ( foundType != null ) { return foundType . equals ( bottomObjectType ) ? null : foundType ; } if ( type . isEnumElementType ( ) ) { foundType = getTypeWithProperty ( field , type . getEnumeratedTypeOfEnumElement ( ) ) ; gtwpCachePut ( field , type , foundType == null ? bottomObjectType : foundType ) ; return foundType ; } if ( ! type . isObjectType ( ) ) { if ( type . isBoxableScalar ( ) ) { foundType = getTypeWithProperty ( field , type . autobox ( ) ) ; gtwpCachePut ( field , type , foundType == null ? bottomObjectType : foundType ) ; return foundType ; } else { gtwpCachePut ( field , type , bottomObjectType ) ; return null ; } } // Ignore the prototype itself at all times. if ( "prototype" . equals ( field ) ) { gtwpCachePut ( field , type , bottomObjectType ) ; return null ; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overridden properties look // like references to the initial property, so they are renamed alike. ObjectType objType = type . toMaybeObjectType ( ) ; if ( objType != null && objType . getConstructor ( ) != null && objType . getConstructor ( ) . isInterface ( ) ) { ObjectType topInterface = objType . getTopDefiningInterface ( field ) ; if ( topInterface != null && topInterface . getConstructor ( ) != null ) { foundType = topInterface . getImplicitPrototype ( ) ; } } else { while ( objType != null && ! Objects . equals ( objType . getImplicitPrototype ( ) , objType ) ) { if ( objType . hasOwnProperty ( field ) ) { foundType = objType ; } objType = objType . getImplicitPrototype ( ) ; } } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. if ( foundType == null ) { JSType subtypeWithProp = type . getGreatestSubtypeWithProperty ( field ) ; ObjectType maybeType = subtypeWithProp == null ? null : subtypeWithProp . toMaybeObjectType ( ) ; // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. if ( maybeType != null && maybeType . hasOwnProperty ( field ) ) { foundType = maybeType ; } } // Unwrap templatized types, they are not unique at runtime. if ( foundType != null && foundType . isGenericObjectType ( ) ) { foundType = foundType . getRawType ( ) ; } // Since disambiguation just looks at names, we must return a uniquely named type rather // than an "equivalent" type. In particular, we must manually unwrap named types // so that the returned type has the correct name. if ( foundType != null && foundType . isNamedType ( ) ) { foundType = foundType . toMaybeNamedType ( ) . getReferencedType ( ) . toMaybeObjectType ( ) ; } gtwpCachePut ( field , type , foundType == null ? bottomObjectType : foundType ) ; return foundType ; }
Returns the type in the chain from the given type that contains the given field or null if it is not found anywhere . Can return a subtype of the input type .