@Override public String getReferenceName() { if (className != null) { return className; } else if (ownerFunction != null) { return ownerFunction.getReferenceName() + ".prototype"; } else { return null; } }
@Override public String getReferenceName() { if (className != null) { return className; } else if (ownerFunction != null) { return ownerFunction.getReferenceName() + ".prototype"; } else { return null; } }
private boolean isDelegateProxy() { // TODO(bradfordcsmith): There should be a better way to determine that we have a proxy type. return hasReferenceName() && getReferenceName().endsWith(DELEGATE_SUFFIX); } }
@Override public String getReferenceName() { return getConstructor().getReferenceName(); }
@Override public String getReferenceName() { return getConstructor().getReferenceName(); }
/** * Two function types are equal if their signatures match. Since they don't have signatures, two * interfaces are equal if their names match. */ final boolean checkFunctionEquivalenceHelper( FunctionType that, EquivalenceMethod eqMethod, EqCache eqCache) { if (this == that) { return true; } if (kind != that.kind) { return false; } switch (kind) { case CONSTRUCTOR: return false; // constructors use identity semantics, which we already checked for above. case INTERFACE: return getReferenceName().equals(that.getReferenceName()); case ORDINARY: return typeOfThis.checkEquivalenceHelper(that.typeOfThis, eqMethod, eqCache) && call.checkArrowEquivalenceHelper(that.call, eqMethod, eqCache); default: throw new AssertionError(); } }
@Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode(); }
@Override String toStringHelper(boolean forAnnotations) { if (constructor.hasReferenceName()) { return constructor.getReferenceName(); } else { return super.toStringHelper(forAnnotations); } }
@Override int recursionUnsafeHashCode() { int hc = kind.hashCode(); switch (kind) { case CONSTRUCTOR: return 31 * hc + System.identityHashCode(this); // constructors use identity semantics case INTERFACE: return 31 * hc + getReferenceName().hashCode(); case ORDINARY: hc = 31 * hc + typeOfThis.hashCode(); hc = 31 * hc + call.hashCode(); return hc; default: throw new AssertionError(); } }
@Override StringBuilder appendTo(StringBuilder sb, boolean forAnnotations) { if (!constructor.hasReferenceName()) { return super.appendTo(sb, forAnnotations); } else if (forAnnotations) { return sb.append(constructor.getNormalizedReferenceName()); } String name = constructor.getReferenceName(); if (name.isEmpty()) { Node n = constructor.getSource(); return sb.append("<anonymous@") .append(n != null ? n.getSourceFileName() : "unknown") .append(":") .append(n != null ? n.getLineno() : 0) .append(">"); } return sb.append(name); }
/** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ boolean checkFunctionEquivalenceHelper( FunctionType that, EquivalenceMethod eqMethod, EqCache eqCache) { if (isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (isInterface()) { if (that.isInterface()) { return getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return typeOfThis.checkEquivalenceHelper(that.typeOfThis, eqMethod, eqCache) && call.checkArrowEquivalenceHelper(that.call, eqMethod, eqCache); }
/** * Gets the {@code prototype} property of this function type. This is equivalent to {@code * (ObjectType) getPropertyType("prototype")}. */ public final ObjectType getPrototype() { // lazy initialization of the prototype field if (prototypeSlot == null) { String refName = getReferenceName(); if (refName == null) { // Someone is trying to access the prototype of a structural function. // We don't want to give real properties to this prototype, because // then it would propagate to all structural functions. setPrototypeNoCheck(registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE), null); } else { setPrototype( new PrototypeObjectType( registry, getReferenceName() + ".prototype", registry.getNativeObjectType(OBJECT_TYPE), isNativeObjectType(), null), null); } } return (ObjectType) prototypeSlot.getType(); }
/** Create a new constructor with the parameters and return type stripped. */ public FunctionType forgetParameterAndReturnTypes() { FunctionType result = new FunctionType( registry, getReferenceName(), source, registry.createArrowType(null, null), getInstanceType(), null, true, false); result.setPrototypeBasedOn(getInstanceType()); return result; }
/** * Gets the {@code prototype} property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public ObjectType getPrototype() { // lazy initialization of the prototype field if (prototypeSlot == null) { String refName = getReferenceName(); if (refName == null) { // Someone is trying to access the prototype of a structural function. // We don't want to give real properties to this prototype, because // then it would propagate to all structural functions. setPrototypeNoCheck( registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE), null); } else { setPrototype( new PrototypeObjectType( registry, getReferenceName() + ".prototype", registry.getNativeObjectType(OBJECT_TYPE), isNativeObjectType(), null), null); } } return (ObjectType) prototypeSlot.getType(); }
/** Copies all the information from another function type. */ public FunctionBuilder copyFromOtherFunction(FunctionType otherType) { this.name = otherType.getReferenceName(); this.sourceNode = otherType.getSource(); this.parametersNode = otherType.getParametersNode(); this.returnType = otherType.getReturnType(); this.typeOfThis = otherType.getTypeOfThis(); this.templateTypeMap = otherType.getTemplateTypeMap(); this.isConstructor = otherType.isConstructor(); this.isNativeType = otherType.isNativeObjectType(); return this; }
/** * Look for the super class implementation up the tree. */ private void recordSuperClassPrototypePropUse( FunctionType classType, String prop, Reference ref) { FunctionType superClass = classType.getSuperClassConstructor(); while (superClass != null) { if (superClass.getPrototype().hasOwnProperty(prop)) { graph.connect(getNamedContainingFunction(), ref, graph.defineNameIfNotExists( superClass.getReferenceName() + ".prototype." + prop, false)); return; } else { superClass = superClass.getSuperClassConstructor(); } } }
/** Create a new constructor with the parameters and return type stripped. */ public final FunctionType forgetParameterAndReturnTypes() { FunctionType result = new FunctionBuilder(registry) .withName(getReferenceName()) .withSourceNode(source) .withTypeOfThis(getInstanceType()) .withKind(kind) .build(); result.setPrototypeBasedOn(getInstanceType()); return result; }
void setPrototypeBasedOn(ObjectType baseType, Node propertyNode) { // This is a bit weird. We need to successfully handle these // two cases: // Foo.prototype = new Bar(); // and // Foo.prototype = {baz: 3}; // In the first case, we do not want new properties to get // added to Bar. In the second case, we do want new properties // to get added to the type of the anonymous object. // // We handle this by breaking it into two cases: // // In the first case, we create a new PrototypeObjectType and set // its implicit prototype to the type being assigned. This ensures // that Bar will not get any properties of Foo.prototype, but properties // later assigned to Bar will get inherited properly. // // In the second case, we just use the anonymous object as the prototype. if (baseType.hasReferenceName() || isNativeObjectType() || baseType.isFunctionPrototypeType()) { baseType = new PrototypeObjectType( registry, getReferenceName() + ".prototype", baseType); } setPrototype(baseType, propertyNode); }
/** * Conservatively assumes that all subclass implementation of this property * might be called. */ private void recordSubclassPrototypePropUse( FunctionType classType, String prop, Reference ref) { if (classType.getPrototype().hasOwnProperty(prop)) { graph.connect(getNamedContainingFunction(), ref, graph.defineNameIfNotExists( classType.getReferenceName() + ".prototype." + prop, false)); } if (classType.getSubTypes() != null) { for (FunctionType subclass : classType.getSubTypes()) { recordSubclassPrototypePropUse(subclass, prop, ref); } } }
/** Copies all the information from another function type. */ public FunctionBuilder copyFromOtherFunction(FunctionType otherType) { int isNative = otherType.isNativeObjectType() ? IS_NATIVE : 0; int isAbstract = otherType.isAbstract() ? IS_ABSTRACT : 0; int inferredReturnType = otherType.isReturnTypeInferred() ? INFERRED_RETURN_TYPE : 0; this.name = otherType.getReferenceName(); this.sourceNode = otherType.getSource(); this.parametersNode = otherType.getParametersNode(); this.returnType = otherType.getReturnType(); this.typeOfThis = otherType.getTypeOfThis(); this.templateTypeMap = otherType.getTemplateTypeMap(); this.kind = otherType.getKind(); this.properties = isNative | isAbstract | inferredReturnType; return this; }