From eac732efe52b903958ab302f733831517e640368 Mon Sep 17 00:00:00 2001 From: aravindpg Date: Thu, 30 Jun 2016 12:51:06 -0700 Subject: [PATCH] [NTI] Partially abstract out type logic in CheckAccessControls. Lifts several rhino.JSType methods into TypeI, which are unimplemented in newtypes.JSType for now. This is groundwork for making CheckAccessControls able to use NTI. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=126332981 --- .../javascript/jscomp/AccessControlUtils.java | 46 ++--- .../jscomp/CheckAccessControls.java | 159 +++++++----------- .../javascript/jscomp/NewTypeInference.java | 5 +- .../javascript/jscomp/newtypes/JSType.java | 66 ++++++++ src/com/google/javascript/rhino/Node.java | 14 ++ .../google/javascript/rhino/ObjectTypeI.java | 21 +++ src/com/google/javascript/rhino/TypeI.java | 12 ++ .../javascript/rhino/jstype/JSType.java | 22 +++ .../javascript/rhino/jstype/ObjectType.java | 31 ++++ .../rhino/jstype/PrototypeObjectType.java | 5 + 10 files changed, 253 insertions(+), 128 deletions(-) diff --git a/src/com/google/javascript/jscomp/AccessControlUtils.java b/src/com/google/javascript/jscomp/AccessControlUtils.java index aa5d679cd18..53219d9173c 100644 --- a/src/com/google/javascript/jscomp/AccessControlUtils.java +++ b/src/com/google/javascript/jscomp/AccessControlUtils.java @@ -20,10 +20,9 @@ import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo.Visibility; import com.google.javascript.rhino.Node; +import com.google.javascript.rhino.ObjectTypeI; import com.google.javascript.rhino.StaticSourceFile; -import com.google.javascript.rhino.jstype.JSType; -import com.google.javascript.rhino.jstype.ObjectType; -import com.google.javascript.rhino.jstype.PrototypeObjectType; +import com.google.javascript.rhino.TypeI; import javax.annotation.Nullable; @@ -60,9 +59,8 @@ static Visibility getEffectiveNameVisibility(Node name, Var var, } Visibility defaultVisibilityForFile = fileVisibilityMap.get(var.getSourceFile()); - JSType type = name.getJSType(); - boolean createdFromGoogProvide = (type instanceof PrototypeObjectType - && ((PrototypeObjectType) type).isAnonymous()); + TypeI type = name.getTypeIIfOld(); + boolean createdFromGoogProvide = (type != null && type.isInstanceofObject()); // Ignore @fileoverview visibility when computing the effective visibility // for names created by goog.provide. // @@ -97,7 +95,7 @@ static Visibility getEffectiveNameVisibility(Node name, Var var, */ static Visibility getEffectivePropertyVisibility( Node property, - ObjectType referenceType, + ObjectTypeI referenceType, ImmutableMap fileVisibilityMap, @Nullable CodingConvention codingConvention) { String propertyName = property.getLastChild().getString(); @@ -108,7 +106,7 @@ static Visibility getEffectivePropertyVisibility( boolean isOverride = parent.getJSDocInfo() != null && parent.isAssign() && parent.getFirstChild() == property; - ObjectType objectType = getObjectType( + ObjectTypeI objectType = getObjectType( referenceType, isOverride, propertyName); if (isOverride) { Visibility overridden = getOverriddenPropertyVisibility( @@ -125,10 +123,10 @@ static Visibility getEffectivePropertyVisibility( * Returns the source file in which the given property is defined, * or null if it is not known. */ - @Nullable private static StaticSourceFile getDefiningSource( - Node getprop, @Nullable ObjectType referenceType, String propertyName) { + @Nullable static StaticSourceFile getDefiningSource( + Node getprop, @Nullable ObjectTypeI referenceType, String propertyName) { if (referenceType != null) { - Node propDefNode = referenceType.getPropertyNode(propertyName); + Node propDefNode = referenceType.getPropertyDefsite(propertyName); if (propDefNode != null) { return propDefNode.getStaticSourceFile(); } @@ -139,33 +137,22 @@ static Visibility getEffectivePropertyVisibility( /** * Returns the lowest property defined on a class with visibility information. */ - @Nullable private static ObjectType getObjectType( - @Nullable ObjectType referenceType, + @Nullable static ObjectTypeI getObjectType( + @Nullable ObjectTypeI referenceType, boolean isOverride, String propertyName) { if (referenceType == null) { return null; } - ObjectType objectType = isOverride - ? referenceType.getImplicitPrototype() - : referenceType; - for (; objectType != null; - objectType = objectType.getImplicitPrototype()) { - JSDocInfo docInfo = objectType.getOwnPropertyJSDocInfo(propertyName); - if (docInfo != null - && docInfo.getVisibility() != Visibility.INHERITED) { - return objectType; - } - } - return null; + return referenceType.getLowestSupertypeWithProperty(propertyName, isOverride); } /** * Returns the original visibility of an overridden property. */ private static Visibility getOverriddenPropertyVisibility( - ObjectType objectType, String propertyName) { + ObjectTypeI objectType, String propertyName) { return objectType != null ? objectType.getOwnPropertyJSDocInfo(propertyName).getVisibility() : Visibility.INHERITED; @@ -198,7 +185,7 @@ private static Visibility getEffectiveVisibilityForOverriddenProperty( */ private static Visibility getEffectiveVisibilityForNonOverriddenProperty( Node getprop, - ObjectType objectType, + ObjectTypeI objectType, @Nullable Visibility fileOverviewVisibility, @Nullable CodingConvention codingConvention) { String propertyName = getprop.getLastChild().getString(); @@ -209,9 +196,8 @@ private static Visibility getEffectiveVisibilityForNonOverriddenProperty( if (objectType != null) { raw = objectType.getOwnPropertyJSDocInfo(propertyName).getVisibility(); } - JSType type = getprop.getJSType(); - boolean createdFromGoogProvide = (type instanceof PrototypeObjectType - && ((PrototypeObjectType) type).isAnonymous()); + TypeI type = getprop.getTypeIIfOld(); + boolean createdFromGoogProvide = (type != null && type.isInstanceofObject()); // Ignore @fileoverview visibility when computing the effective visibility // for properties created by goog.provide. // diff --git a/src/com/google/javascript/jscomp/CheckAccessControls.java b/src/com/google/javascript/jscomp/CheckAccessControls.java index 6eb9a642d6c..75fbaeb908c 100644 --- a/src/com/google/javascript/jscomp/CheckAccessControls.java +++ b/src/com/google/javascript/jscomp/CheckAccessControls.java @@ -16,6 +16,7 @@ package com.google.javascript.jscomp; +import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; @@ -23,13 +24,13 @@ import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo.Visibility; import com.google.javascript.rhino.Node; +import com.google.javascript.rhino.ObjectTypeI; import com.google.javascript.rhino.StaticSourceFile; +import com.google.javascript.rhino.TypeI; import com.google.javascript.rhino.TypeIRegistry; import com.google.javascript.rhino.jstype.FunctionType; -import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.ObjectType; -import com.google.javascript.rhino.jstype.Property; import java.util.ArrayDeque; @@ -137,11 +138,11 @@ class CheckAccessControls implements ScopedCallback, HotSwapCompilerPass { // State about the current traversal. private int deprecatedDepth = 0; - private final ArrayDeque currentClassStack = new ArrayDeque<>(); - private final JSType noTypeSentinel; + private final ArrayDeque currentClassStack = new ArrayDeque<>(); + private final TypeI noTypeSentinel; private ImmutableMap defaultVisibilityForFiles; - private final Multimap initializedConstantProperties; + private final Multimap initializedConstantProperties; CheckAccessControls( @@ -180,8 +181,8 @@ public void enterScope(NodeTraversal t) { if (isDeprecatedFunction(n)) { deprecatedDepth++; } - JSType prevClass = getCurrentClass(); - JSType currentClass = prevClass == null + TypeI prevClass = getCurrentClass(); + TypeI currentClass = prevClass == null ? getClassOfMethod(n, parent) : prevClass; // ArrayDeques can't handle nulls, so we reuse the bottom type @@ -207,29 +208,29 @@ public void exitScope(NodeTraversal t) { * Gets the type of the class that "owns" a method, or null if * we know that its un-owned. */ - private JSType getClassOfMethod(Node n, Node parent) { + private TypeI getClassOfMethod(Node n, Node parent) { if (parent.isAssign()) { Node lValue = parent.getFirstChild(); if (NodeUtil.isGet(lValue)) { // We have an assignment of the form "a.b = ...". - JSType lValueType = lValue.getJSType(); - if (lValueType != null && lValueType.isNominalConstructor()) { + TypeI lValueType = lValue.getTypeI(); + if (lValueType != null && lValueType.isOriginalConstructor()) { // If a.b is a constructor, then everything in this function // belongs to the "a.b" type. return (lValueType.toMaybeFunctionType()).getInstanceType(); } else { // If a.b is not a constructor, then treat this as a method // of whatever type is on "a". - return normalizeClassType(lValue.getFirstChild().getJSType()); + return normalizeClassType(lValue.getFirstChild().getTypeI()); } } else { // We have an assignment of the form "a = ...", so pull the // type off the "a". - return normalizeClassType(lValue.getJSType()); + return normalizeClassType(lValue.getTypeI()); } } else if (NodeUtil.isFunctionDeclaration(n) || parent.isName()) { - return normalizeClassType(n.getJSType()); + return normalizeClassType(n.getTypeI()); } else if (parent.isStringKey() || parent.isGetterDef() || parent.isSetterDef()) { Node objectLitParent = parent.getGrandparent(); @@ -238,7 +239,7 @@ private JSType getClassOfMethod(Node n, Node parent) { } Node className = NodeUtil.getPrototypeClassName(objectLitParent.getFirstChild()); if (className != null) { - return normalizeClassType(className.getJSType()); + return normalizeClassType(className.getTypeI()); } } @@ -249,12 +250,14 @@ private JSType getClassOfMethod(Node n, Node parent) { * Normalize the type of a constructor, its instance, and its prototype * all down to the same type (the instance type). */ - private static JSType normalizeClassType(JSType type) { + private static TypeI normalizeClassType(TypeI type) { if (type == null || type.isUnknownType()) { return type; - } else if (type.isNominalConstructor()) { + } else if (type.isOriginalConstructor()) { return (type.toMaybeFunctionType()).getInstanceType(); - } else if (type.isFunctionPrototypeType()) { + } else if (type.isPrototypeObject()) { + // newtypes.JSType should never enter this codepath + Preconditions.checkState(type instanceof ObjectType); FunctionType owner = ((ObjectType) type).getOwnerFunction(); if (owner.isConstructor()) { return owner.getInstanceType(); @@ -291,6 +294,8 @@ public void visit(NodeTraversal t, Node n, Node parent) { case FUNCTION: checkFinalClassOverrides(t, n, parent); break; + default: + break; } } @@ -299,7 +304,7 @@ public void visit(NodeTraversal t, Node n, Node parent) { */ private void checkConstructorDeprecation(NodeTraversal t, Node n, Node parent) { - JSType type = n.getJSType(); + TypeI type = n.getTypeI(); if (type != null) { String deprecationInfo = getTypeDeprecationInfo(type); @@ -355,8 +360,7 @@ private void checkPropertyDeprecation(NodeTraversal t, Node n, Node parent) { return; } - ObjectType objectType = - ObjectType.cast(dereference(n.getFirstChild().getJSType())); + ObjectTypeI objectType = castToObject(dereference(n.getFirstChild().getTypeI())); String propertyName = n.getLastChild().getString(); if (objectType != null) { @@ -537,9 +541,9 @@ private void checkOverriddenPropertyVisibilityMismatch( * Checks if a constructor is trying to override a final class. */ private void checkFinalClassOverrides(NodeTraversal t, Node fn, Node parent) { - JSType type = fn.getJSType().toMaybeFunctionType(); + TypeI type = fn.getTypeI().toMaybeFunctionType(); if (type != null && type.isConstructor()) { - JSType finalParentClass = getFinalParentClass(getClassOfMethod(fn, parent)); + TypeI finalParentClass = getFinalParentClass(getClassOfMethod(fn, parent)); if (finalParentClass != null) { compiler.report( t.makeError(fn, EXTEND_FINAL_CLASS, @@ -564,8 +568,7 @@ private void checkConstantProperty(NodeTraversal t, return; } - ObjectType objectType = - ObjectType.cast(dereference(getprop.getFirstChild().getJSType())); + ObjectTypeI objectType = castToObject(dereference(getprop.getFirstChild().getTypeI())); String propertyName = getprop.getLastChild().getString(); @@ -593,7 +596,7 @@ private void checkConstantProperty(NodeTraversal t, return; } - ObjectType oType = objectType; + ObjectTypeI oType = objectType; while (oType != null) { if (initializedConstantProperties.containsEntry( oType, propertyName)) { @@ -602,7 +605,7 @@ private void checkConstantProperty(NodeTraversal t, propertyName)); break; } - oType = oType.getImplicitPrototype(); + oType = oType.getPrototypeObject(); } initializedConstantProperties.put(objectType, @@ -610,7 +613,7 @@ private void checkConstantProperty(NodeTraversal t, // Add the prototype when we're looking at an instance object if (objectType.isInstanceType()) { - ObjectType prototype = objectType.getImplicitPrototype(); + ObjectTypeI prototype = objectType.getPrototypeObject(); if (prototype != null && prototype.hasProperty(propertyName)) { initializedConstantProperties.put(prototype, propertyName); } @@ -631,8 +634,7 @@ private void checkPropertyVisibility(NodeTraversal t, return; } - ObjectType referenceType = - ObjectType.cast(dereference(getprop.getFirstChild().getJSType())); + ObjectTypeI referenceType = castToObject(dereference(getprop.getFirstChild().getTypeI())); String propertyName = getprop.getLastChild().getString(); boolean isPrivateByConvention = isPrivateByConvention(propertyName); @@ -643,7 +645,7 @@ && propertyIsDeclaredButNotPrivate(getprop, parent)) { return; } - StaticSourceFile definingSource = getDefiningSource( + StaticSourceFile definingSource = AccessControlUtils.getDefiningSource( getprop, referenceType, propertyName); boolean isClassType = false; @@ -654,7 +656,7 @@ && propertyIsDeclaredButNotPrivate(getprop, parent)) { && parent.isAssign() && parent.getFirstChild() == getprop; - ObjectType objectType = getObjectType( + ObjectTypeI objectType = AccessControlUtils.getObjectType( referenceType, isOverride, propertyName); Visibility fileOverviewVisibility = @@ -675,14 +677,13 @@ && propertyIsDeclaredButNotPrivate(getprop, parent)) { } if (objectType != null) { - Property p = objectType.getOwnSlot(propertyName); - Node node = p.getNode(); + Node node = objectType.getOwnPropertyDefsite(propertyName); if (node == null) { // Assume the property is public. return; } definingSource = node.getStaticSourceFile(); - isClassType = p.getJSDocInfo().isConstructor(); + isClassType = objectType.getOwnPropertyJSDocInfo(propertyName).isConstructor(); } else if (isPrivateByConvention) { // We can only check visibility references if we know what file // it was defined in. @@ -733,50 +734,13 @@ private static boolean propertyIsDeclaredButNotPrivate(Node getprop, Node parent return false; } - @Nullable private static StaticSourceFile getDefiningSource( - Node getprop, - @Nullable ObjectType referenceType, - String propertyName) { - if (referenceType != null) { - Node propDefNode = referenceType.getPropertyNode(propertyName); - if (propDefNode != null) { - return propDefNode.getStaticSourceFile(); - } - } - return getprop.getStaticSourceFile(); - } - - @Nullable private static ObjectType getObjectType( - @Nullable ObjectType referenceType, - boolean isOverride, - String propertyName) { - if (referenceType == null) { - return null; - } - - // Find the lowest property defined on a class with visibility - // information. - ObjectType objectType = isOverride - ? referenceType.getImplicitPrototype() - : referenceType; - for (; objectType != null; - objectType = objectType.getImplicitPrototype()) { - JSDocInfo docInfo = objectType.getOwnPropertyJSDocInfo(propertyName); - if (docInfo != null - && docInfo.getVisibility() != Visibility.INHERITED) { - return objectType; - } - } - return null; - } - private void checkOverriddenPropertyVisibility( NodeTraversal t, Node getprop, Node parent, Visibility visibility, Visibility fileOverviewVisibility, - ObjectType objectType, + ObjectTypeI objectType, boolean sameInput) { // Check an ASSIGN statement that's trying to override a property // on a superclass. @@ -811,7 +775,7 @@ private void checkNonOverriddenPropertyVisibility( Node parent, Visibility visibility, boolean isClassType, - JSType objectType, + ObjectTypeI objectType, StaticSourceFile referenceSource, StaticSourceFile definingSource) { // private access is always allowed in the same file. @@ -821,7 +785,7 @@ private void checkNonOverriddenPropertyVisibility( return; } - JSType ownerType = normalizeClassType(objectType); + TypeI ownerType = normalizeClassType(objectType); switch (visibility) { case PACKAGE: @@ -857,8 +821,8 @@ private void checkPackagePropertyVisibility( } } - @Nullable private JSType getCurrentClass() { - JSType cur = currentClassStack.peekFirst(); + @Nullable private TypeI getCurrentClass() { + TypeI cur = currentClassStack.peekFirst(); return cur == noTypeSentinel ? null : cur; @@ -869,8 +833,8 @@ private void checkPrivatePropertyVisibility( Node getprop, Node parent, boolean isClassType, - JSType ownerType) { - JSType currentClass = getCurrentClass(); + TypeI ownerType) { + TypeI currentClass = getCurrentClass(); if (currentClass != null && ownerType.isEquivalentTo(currentClass)) { return; } @@ -881,7 +845,7 @@ private void checkPrivatePropertyVisibility( // private access is not allowed outside the file from a different // enclosing class. - JSType accessedType = getprop.getFirstChild().getJSType(); + TypeI accessedType = getprop.getFirstChild().getTypeI(); String propertyName = getprop.getLastChild().getString(); String readableTypeName = ownerType.equals(accessedType) ? typeRegistry.getReadableTypeName(getprop.getFirstChild()) @@ -896,14 +860,14 @@ private void checkPrivatePropertyVisibility( private void checkProtectedPropertyVisibility( NodeTraversal t, Node getprop, - JSType ownerType) { + TypeI ownerType) { // There are 3 types of legal accesses of a protected property: // 1) Accesses in the same file // 2) Overriding the property in a subclass // 3) Accessing the property from inside a subclass // The first two have already been checked for. - JSType currentClass = getCurrentClass(); - if (currentClass == null || !currentClass.isSubtype(ownerType)) { + TypeI currentClass = getCurrentClass(); + if (currentClass == null || !currentClass.isSubtypeOf(ownerType)) { String propertyName = getprop.getLastChild().getString(); compiler.report( t.makeError(getprop, BAD_PROTECTED_PROPERTY_ACCESS, @@ -994,7 +958,7 @@ private boolean canAccessDeprecatedTypes(NodeTraversal t) { */ private static boolean isDeprecatedFunction(Node n) { if (n.isFunction()) { - JSType type = n.getJSType(); + TypeI type = n.getTypeI(); if (type != null) { return getTypeDeprecationInfo(type) != null; } @@ -1008,7 +972,7 @@ private static boolean isDeprecatedFunction(Node n) { * as being deprecated. Returns empty string if the type is deprecated * but no reason was given. Returns null if the type is not deprecated. */ - private static String getTypeDeprecationInfo(JSType type) { + private static String getTypeDeprecationInfo(TypeI type) { if (type == null) { return null; } @@ -1020,9 +984,9 @@ private static String getTypeDeprecationInfo(JSType type) { } return ""; } - ObjectType objType = ObjectType.cast(type); + ObjectTypeI objType = castToObject(type); if (objType != null) { - ObjectType implicitProto = objType.getImplicitPrototype(); + ObjectTypeI implicitProto = objType.getPrototypeObject(); if (implicitProto != null) { return getTypeDeprecationInfo(implicitProto); } @@ -1034,14 +998,14 @@ private static String getTypeDeprecationInfo(JSType type) { * Returns if a property is declared constant. */ private boolean isPropertyDeclaredConstant( - ObjectType objectType, String prop) { + ObjectTypeI objectType, String prop) { if (enforceCodingConventions && compiler.getCodingConvention().isConstant(prop)) { return true; } for (; objectType != null; - objectType = objectType.getImplicitPrototype()) { + objectType = objectType.getPrototypeObject()) { JSDocInfo docInfo = objectType.getOwnPropertyJSDocInfo(prop); if (docInfo != null && docInfo.isConstant()) { return true; @@ -1055,7 +1019,7 @@ private boolean isPropertyDeclaredConstant( * as being deprecated. Returns empty string if the property is deprecated * but no reason was given. Returns null if the property is not deprecated. */ - private static String getPropertyDeprecationInfo(ObjectType type, + private static String getPropertyDeprecationInfo(ObjectTypeI type, String prop) { JSDocInfo info = type.getOwnPropertyJSDocInfo(prop); if (info != null && info.isDeprecated()) { @@ -1065,7 +1029,7 @@ private static String getPropertyDeprecationInfo(ObjectType type, return ""; } - ObjectType implicitProto = type.getImplicitPrototype(); + ObjectTypeI implicitProto = type.getPrototypeObject(); if (implicitProto != null) { return getPropertyDeprecationInfo(implicitProto, prop); } @@ -1075,18 +1039,18 @@ private static String getPropertyDeprecationInfo(ObjectType type, /** * Dereference a type, autoboxing it and filtering out null. */ - private static JSType dereference(JSType type) { - return type == null ? null : type.dereference(); + private static ObjectTypeI dereference(TypeI type) { + return type == null ? null : type.autoboxAndGetObject(); } /** * Returns the super class of the given type that has a constructor. */ - private static JSType getFinalParentClass(JSType type) { + private static ObjectTypeI getFinalParentClass(TypeI type) { if (type != null) { - ObjectType iproto = ObjectType.cast(type).getImplicitPrototype(); + ObjectTypeI iproto = castToObject(type).getPrototypeObject(); while (iproto != null && iproto.getConstructor() == null) { - iproto = iproto.getImplicitPrototype(); + iproto = iproto.getPrototypeObject(); } if (iproto != null) { Node source = iproto.getConstructor().getSource(); @@ -1098,4 +1062,9 @@ private static JSType getFinalParentClass(JSType type) { } return null; } + + @Nullable + private static ObjectTypeI castToObject(@Nullable TypeI type) { + return type == null ? null : type.toMaybeObjectType(); + } } diff --git a/src/com/google/javascript/jscomp/NewTypeInference.java b/src/com/google/javascript/jscomp/NewTypeInference.java index c5d4819681d..3a8762a8f67 100644 --- a/src/com/google/javascript/jscomp/NewTypeInference.java +++ b/src/com/google/javascript/jscomp/NewTypeInference.java @@ -3790,9 +3790,8 @@ private JSType markAndGetTypeOfPreanalyzedNode(Node qnameNode, TypeEnv env, bool } private void maybeSetTypeI(Node n, JSType t) { - TypeI ti = n.getTypeI(); - Preconditions.checkState(ti == null || ti instanceof JSType); - JSType oldType = (JSType) ti; + TypeI oldType = n.getTypeI(); + Preconditions.checkState(oldType == null || oldType instanceof JSType); // When creating a function summary, we set a precise type on the function's // name node. Since we're visiting inner scopes first, the name node is // revisited after the function's scope is analyzed, and its type then can diff --git a/src/com/google/javascript/jscomp/newtypes/JSType.java b/src/com/google/javascript/jscomp/newtypes/JSType.java index bc52f813fa2..b35a9c38975 100644 --- a/src/com/google/javascript/jscomp/newtypes/JSType.java +++ b/src/com/google/javascript/jscomp/newtypes/JSType.java @@ -24,6 +24,7 @@ import com.google.common.collect.Sets; import com.google.javascript.jscomp.parsing.parser.util.format.SimpleFormat; import com.google.javascript.rhino.FunctionTypeI; +import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.ObjectTypeI; import com.google.javascript.rhino.TypeI; @@ -1505,6 +1506,11 @@ public boolean isConstructor() { return ft != null && ft.isUniqueConstructor(); } + @Override + public boolean isOriginalConstructor() { + throw new UnsupportedOperationException("isOriginalConstructor not implemented yet."); + } + @Override public boolean isEquivalentTo(TypeI type) { return equals(type); @@ -1540,6 +1546,11 @@ public ObjectTypeI toMaybeObjectType() { return isSingletonObj() ? this : null; } + @Override + public JSType autoboxAndGetObject() { + throw new UnsupportedOperationException("autoboxAndGetObject not implemented yet"); + } + @Override public boolean equals(Object o) { if (o == null) { @@ -1560,6 +1571,11 @@ public int hashCode() { return Objects.hash(getMask(), getObjs(), getEnums(), getTypeVar()); } + @Override + public String getDisplayName() { + throw new UnsupportedOperationException("getDisplayName not implemented yet"); + } + @Override public TypeI convertMethodToFunction() { throw new UnsupportedOperationException("convertMethodToFunction not implemented yet"); @@ -1613,6 +1629,56 @@ public TypeI getReturnType() { public FunctionTypeI getConstructor() { throw new UnsupportedOperationException("getConstructor not implemented yet"); } + + @Override + public JSType getPrototypeObject() { + throw new UnsupportedOperationException("getPrototypeObject not implemented yet"); + } + + @Override + public JSDocInfo getJSDocInfo() { + throw new UnsupportedOperationException("getJSDocInfo not implemented yet"); + } + + @Override + public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { + throw new UnsupportedOperationException("getOwnPropertyJSDocInfo not implemented yet"); + } + + @Override + public Node getOwnPropertyDefsite(String propertyName) { + throw new UnsupportedOperationException("getOwnPropertyDefsite not implemented yet"); + } + + @Override + public Node getPropertyDefsite(String propertyName) { + throw new UnsupportedOperationException("getPropertyDefsite not implemented yet"); + } + + @Override + public JSType getLowestSupertypeWithProperty(String propertyName, boolean isOverride) { + throw new UnsupportedOperationException("getLowestSupertypeWithProperty not implemented yet"); + } + + @Override + public boolean isPrototypeObject() { + throw new UnsupportedOperationException("isPrototypeObject not implemented yet"); + } + + @Override + public boolean isInstanceofObject() { + throw new UnsupportedOperationException("isObjectLiteral not implemented yet"); + } + + @Override + public boolean isInstanceType() { + throw new UnsupportedOperationException("isInstanceType not implemented yet"); + } + + @Override + public boolean hasProperty(String propertyName) { + throw new UnsupportedOperationException("hasProperty not implemented yet"); + } } final class UnionType extends JSType { diff --git a/src/com/google/javascript/rhino/Node.java b/src/com/google/javascript/rhino/Node.java index 56d4c33fb28..ecb2201cf4a 100644 --- a/src/com/google/javascript/rhino/Node.java +++ b/src/com/google/javascript/rhino/Node.java @@ -2186,6 +2186,20 @@ public void setTypeI(TypeI type) { this.typei = type; } + /** + * Gets the OTI {@link JSType} associated with this node if any, and null otherwise.

+ * + * NTI and OTI don't annotate the exact same AST nodes with types. (For example, OTI + * doesn't annotate dead code.) When OTI runs after NTI, the checks that use type + * information must only see the old types. They can call this method to avoid getting + * a new type for an AST node where OTI did not add a type. + * Calls to this method are intended to be temporary. As we migrate passes to support + * NTI natively, we will be replacing calls to this method with calls to getTypeI. + */ + public TypeI getTypeIIfOld() { + return typei instanceof JSType ? typei : null; + } + /** * Get the {@link JSDocInfo} attached to this node. * @return the information or {@code null} if no JSDoc is attached to this diff --git a/src/com/google/javascript/rhino/ObjectTypeI.java b/src/com/google/javascript/rhino/ObjectTypeI.java index a13b3c8a24f..3efb807e38d 100644 --- a/src/com/google/javascript/rhino/ObjectTypeI.java +++ b/src/com/google/javascript/rhino/ObjectTypeI.java @@ -50,4 +50,25 @@ public interface ObjectTypeI extends TypeI { * object (constructed natively vs. by instantiation of a function). */ FunctionTypeI getConstructor(); + + ObjectTypeI getPrototypeObject(); + + ObjectTypeI getLowestSupertypeWithProperty(String propertyName, boolean isOverride); + + // TODO(aravindpg): might be better to define a PropertyI interface and + // then have a more general-purpose getProperty method here. + + JSDocInfo getOwnPropertyJSDocInfo(String propertyName); + + Node getOwnPropertyDefsite(String propertyName); + + Node getPropertyDefsite(String propertyName); + + /** Whether this type is an instance object of some constructor. */ + // NOTE(dimvar): for OTI, this is true only for InstanceObjectType and a single case + // in FunctionType.java. Why do we need the FunctionType case? Could this method be + // true for "classy" objects only? + boolean isInstanceType(); + + boolean hasProperty(String propertyName); } diff --git a/src/com/google/javascript/rhino/TypeI.java b/src/com/google/javascript/rhino/TypeI.java index 2fd2316e4df..94899ddbc5f 100644 --- a/src/com/google/javascript/rhino/TypeI.java +++ b/src/com/google/javascript/rhino/TypeI.java @@ -52,6 +52,8 @@ public interface TypeI { boolean isConstructor(); + boolean isOriginalConstructor(); + boolean isEquivalentTo(TypeI type); boolean isFunctionType(); @@ -66,6 +68,14 @@ public interface TypeI { boolean isNullable(); + boolean isPrototypeObject(); + + boolean isInstanceofObject(); + + ObjectTypeI autoboxAndGetObject(); + + JSDocInfo getJSDocInfo(); + /** * If this is a union type, returns a union type that does not include * the null or undefined type. @@ -83,4 +93,6 @@ public interface TypeI { * If it is a non-object or a union of objects, return null. */ ObjectTypeI toMaybeObjectType(); + + String getDisplayName(); } diff --git a/src/com/google/javascript/rhino/jstype/JSType.java b/src/com/google/javascript/rhino/jstype/JSType.java index 5cd1486e17e..15721b250b4 100644 --- a/src/com/google/javascript/rhino/jstype/JSType.java +++ b/src/com/google/javascript/rhino/jstype/JSType.java @@ -119,6 +119,7 @@ JSType getNativeType(JSTypeNative typeId) { * attached to arbitrary types. This must be overridden for * programmer-defined types. */ + @Override public JSDocInfo getJSDocInfo() { return null; } @@ -132,6 +133,7 @@ public JSDocInfo getJSDocInfo() { * * @return the display name of the type, or null if one is not available */ + @Override public String getDisplayName() { return null; } @@ -183,6 +185,11 @@ public boolean isFunctionPrototypeType() { return false; } + @Override + public boolean isPrototypeObject() { + return isFunctionPrototypeType(); + } + public boolean isStringObjectType() { return false; } @@ -331,6 +338,11 @@ public boolean isDict() { return false; } + @Override + public boolean isInstanceofObject() { + return false; + } + /** * Downcasts this to a UnionType, or returns null if this is not a UnionType. * @@ -529,6 +541,11 @@ public final boolean isNominalConstructor() { return false; } + @Override + public boolean isOriginalConstructor() { + return isNominalConstructor(); + } + /** * Whether this type is an Instance object of some constructor. * Does not necessarily mean this is an {@link InstanceObjectType}. @@ -836,6 +853,11 @@ public final ObjectType dereference() { return autobox().toObjectType(); } + @Override + public final ObjectType autoboxAndGetObject() { + return dereference(); + } + /** * Tests whether {@code this} and {@code that} are meaningfully * comparable. By meaningfully, we mean compatible types that do not lead diff --git a/src/com/google/javascript/rhino/jstype/ObjectType.java b/src/com/google/javascript/rhino/jstype/ObjectType.java index 0abe9f1fc5b..e9de9114fe6 100644 --- a/src/com/google/javascript/rhino/jstype/ObjectType.java +++ b/src/com/google/javascript/rhino/jstype/ObjectType.java @@ -48,6 +48,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.javascript.rhino.JSDocInfo; +import com.google.javascript.rhino.JSDocInfo.Visibility; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.ObjectTypeI; @@ -276,6 +277,11 @@ public TernaryValue testForEquality(JSType that) { */ public abstract ObjectType getImplicitPrototype(); + @Override + public ObjectType getPrototypeObject() { + return getImplicitPrototype(); + } + /** * Defines a property whose type is explicitly declared by the programmer. * @param propertyName the property's name @@ -382,16 +388,28 @@ public Node getPropertyNode(String propertyName) { return p == null ? null : p.getNode(); } + @Override + public Node getPropertyDefsite(String propertyName) { + return getPropertyNode(propertyName); + } + /** * Gets the docInfo on the specified property on this type. This should not * be implemented recursively, as you generally need to know exactly on * which type in the prototype chain the JSDocInfo exists. */ + @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { Property p = getOwnSlot(propertyName); return p == null ? null : p.getJSDocInfo(); } + @Override + public Node getOwnPropertyDefsite(String propertyName) { + Property p = getOwnSlot(propertyName); + return p == null ? null : p.getNode(); + } + /** * Sets the docInfo for the specified property from the * {@link JSDocInfo} on its definition. @@ -736,4 +754,17 @@ public Map getPropertyTypeMap() { } return propTypeMap.build(); } + + @Override + public ObjectType getLowestSupertypeWithProperty(String propertyName, boolean isOverride) { + // Find the lowest property defined on a class with visibility information. + ObjectType objectType = isOverride ? this.getImplicitPrototype() : this; + for (; objectType != null; objectType = objectType.getImplicitPrototype()) { + JSDocInfo docInfo = objectType.getOwnPropertyJSDocInfo(propertyName); + if (docInfo != null && docInfo.getVisibility() != Visibility.INHERITED) { + return objectType; + } + } + return null; + } } diff --git a/src/com/google/javascript/rhino/jstype/PrototypeObjectType.java b/src/com/google/javascript/rhino/jstype/PrototypeObjectType.java index 8a065331d1d..f07c43b1c95 100644 --- a/src/com/google/javascript/rhino/jstype/PrototypeObjectType.java +++ b/src/com/google/javascript/rhino/jstype/PrototypeObjectType.java @@ -381,6 +381,11 @@ public boolean isAnonymous() { return anonymousType; } + @Override + public boolean isInstanceofObject() { + return isAnonymous(); + } + @Override public boolean isSubtype(JSType that) { return isSubtype(that, ImplCache.create(), SubtypingMode.NORMAL);