@Override public void recordInterfaces( JSType type, JSType relatedType, DisambiguateProperties<JSType>.Property p) { ObjectType objType = ObjectType.cast(type); if (objType != null) { FunctionType constructor; if (objType instanceof FunctionType) { constructor = (FunctionType) objType; } else if (objType instanceof FunctionPrototypeType) { constructor = ((FunctionPrototypeType) objType).getOwnerFunction(); } else { constructor = objType.getConstructor(); } while (constructor != null) { for (ObjectType itype : constructor.getImplementedInterfaces()) { JSType top = getTypeWithProperty(p.name, itype); if (top != null) { p.addType(itype, top, relatedType); } else { recordInterfaces(itype, relatedType, p); } // If this interface invalidated this property, return now. if (p.skipRenaming) return; } if (constructor.isInterface() || constructor.isConstructor()) { constructor = constructor.getSuperClassConstructor(); } else { constructor = null; } } } }
@Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction().getInstanceType(); } } return null; }
/** * 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) { 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) && call.checkArrowEquivalenceHelper(that.call, eqMethod); }
/** @param fnNode A node for a function for which to generate a type annotation */ private String getFunctionAnnotation(Node fnNode) { Preconditions.checkState(fnNode.isFunction()); StringBuilder sb = new StringBuilder("/**\n"); JSType type = fnNode.getJSType(); if (type == null || type.isUnknownType()) { return ""; } FunctionType funType = type.toMaybeFunctionType(); // We need to use the child nodes of the function as the nodes for the // parameters of the function type do not have the real parameter names. // FUNCTION // NAME // LP // NAME param1 // NAME param2 if (fnNode != null) { Node paramNode = NodeUtil.getFunctionParameters(fnNode).getFirstChild(); // Param types for (Node n : funType.getParameters()) { // Bail out if the paramNode is not there. if (paramNode == null) { break; } sb.append(" * "); appendAnnotation(sb, "param", getParameterNodeJSDocType(n)); sb.append(" ").append(paramNode.getString()).append("\n"); paramNode = paramNode.getNext(); } } // Return type JSType retType = funType.getReturnType(); if (retType != null && !retType.isUnknownType() && !retType.isEmptyType()) { sb.append(" * "); appendAnnotation(sb, "return", retType.toAnnotationString()); sb.append("\n"); } // Constructor/interface if (funType.isConstructor() || funType.isInterface()) { FunctionType superConstructor = funType.getSuperClassConstructor(); if (superConstructor != null) { ObjectType superInstance = funType.getSuperClassConstructor().getInstanceType(); if (!superInstance.toString().equals("Object")) { sb.append(" * "); appendAnnotation(sb, "extends", superInstance.toAnnotationString()); sb.append("\n"); } } if (funType.isInterface()) { for (ObjectType interfaceType : funType.getExtendedInterfaces()) { sb.append(" * "); appendAnnotation(sb, "extends", interfaceType.toAnnotationString()); sb.append("\n"); } } // Avoid duplicates, add implemented type to a set first Set<String> interfaces = Sets.newTreeSet(); for (ObjectType interfaze : funType.getImplementedInterfaces()) { interfaces.add(interfaze.toAnnotationString()); } for (String interfaze : interfaces) { sb.append(" * "); appendAnnotation(sb, "implements", interfaze); sb.append("\n"); } if (funType.isConstructor()) { sb.append(" * @constructor\n"); } else if (funType.isInterface()) { sb.append(" * @interface\n"); } } if (fnNode != null && fnNode.getBooleanProp(Node.IS_DISPATCHER)) { sb.append(" * @javadispatch\n"); } sb.append(" */\n"); return sb.toString(); }