private void checkCanAssignToNameGetpropOrGetelem ( NodeTraversal t , Node nodeToWarn , Node lvalue , JSType rightType , JSDocInfo info , String msg ) { checkArgument ( lvalue . isName ( ) || lvalue . isGetProp ( ) || lvalue . isGetElem ( ) || lvalue . isCast ( ) , lvalue ) ; if ( lvalue . isGetProp ( ) ) { Node object = lvalue . getFirstChild ( ) ; JSType objectJsType = getJSType ( object ) ; Node property = lvalue . getLastChild ( ) ; String pname = property . getString ( ) ; // the first name in this getprop refers to an interface // we perform checks in addition to the ones below if ( object . isGetProp ( ) ) { JSType jsType = getJSType ( object . getFirstChild ( ) ) ; if ( jsType . isInterface ( ) && object . getLastChild ( ) . getString ( ) . equals ( "prototype" ) ) { visitInterfacePropertyAssignment ( object , lvalue ) ; } } checkEnumAlias ( t , info , rightType , nodeToWarn ) ; checkPropCreation ( lvalue ) ; // Prototype assignments are special, because they actually affect // the definition of a class. These are mostly validated // during TypedScopeCreator, and we only look for the "dumb" cases here. // object.prototype = ...; if ( pname . equals ( "prototype" ) ) { validator . expectCanAssignToPrototype ( objectJsType , nodeToWarn , rightType ) ; return ; } // The generic checks for 'object.property' when 'object' is known, // and 'property' is declared on it. // object.property = ...; ObjectType objectCastType = ObjectType . cast ( objectJsType . restrictByNotNullOrUndefined ( ) ) ; JSType expectedPropertyType = getPropertyTypeIfDeclared ( objectCastType , pname ) ; checkPropertyInheritanceOnGetpropAssign ( nodeToWarn , object , pname , info , expectedPropertyType ) ; // If we successfully found a non-unknown declared type, validate the assignment and don't do // any further checks. if ( ! expectedPropertyType . isUnknownType ( ) ) { // Note: if the property has @implicitCast at its declaration, we don't check any // assignments to it. if ( ! propertyIsImplicitCast ( objectCastType , pname ) ) { validator . expectCanAssignToPropertyOf ( nodeToWarn , rightType , expectedPropertyType , object , pname ) ; } return ; } } // Check qualified name sets to 'object' and 'object.property'. // This can sometimes handle cases when the type of 'object' is not known. // e.g., // var obj = createUnknownType(); // /** @type {number} */ obj.foo = true; JSType leftType = getJSType ( lvalue ) ; if ( lvalue . isQualifiedName ( ) ) { // variable with inferred type case TypedVar var = t . getTypedScope ( ) . getVar ( lvalue . getQualifiedName ( ) ) ; if ( var != null ) { if ( var . isTypeInferred ( ) ) { return ; } if ( NodeUtil . getRootOfQualifiedName ( lvalue ) . isThis ( ) && t . getTypedScope ( ) != var . getScope ( ) ) { // Don't look at "this.foo" variables from other scopes. return ; } if ( var . getType ( ) != null ) { leftType = var . getType ( ) ; } } } // Fall through case for arbitrary LHS and arbitrary RHS. validator . expectCanAssignTo ( nodeToWarn , rightType , leftType , msg ) ; }
Checks that we can assign the given right type to the given lvalue .