void rewritePolymerCall(
      Node exprRoot, final PolymerClassDefinition cls, boolean isInGlobalScope) {
    Node objLit = checkNotNull(cls.descriptor);

    // Add {@code @lends} to the object literal.
    JSDocInfoBuilder objLitDoc = new JSDocInfoBuilder(true);
    JSTypeExpression jsTypeExpression =
        new JSTypeExpression(
            IR.string(cls.target.getQualifiedName() + ".prototype"), exprRoot.getSourceFileName());
    objLitDoc.recordLends(jsTypeExpression);
    objLit.setJSDocInfo(objLitDoc.build());

    addTypesToFunctions(objLit, cls.target.getQualifiedName(), cls.defType);
    PolymerPassStaticUtils.switchDollarSignPropsToBrackets(objLit, compiler);
    PolymerPassStaticUtils.quoteListenerAndHostAttributeKeys(objLit, compiler);

    for (MemberDefinition prop : cls.props) {
      if (prop.value.isObjectLit()) {
        PolymerPassStaticUtils.switchDollarSignPropsToBrackets(prop.value, compiler);
      }
    }

    // For simplicity add everything into a block, before adding it to the AST.
    Node block = IR.block();

    JSDocInfoBuilder constructorDoc = this.getConstructorDoc(cls);

    // Remove the original constructor JS docs from the objlit.
    Node ctorKey = cls.constructor.value.getParent();
    if (ctorKey != null) {
      ctorKey.removeProp(Node.JSDOC_INFO_PROP);
    }

    if (cls.target.isGetProp()) {
      // foo.bar = Polymer({...});
      Node assign = IR.assign(cls.target.cloneTree(), cls.constructor.value.cloneTree());
      NodeUtil.markNewScopesChanged(assign, compiler);
      assign.setJSDocInfo(constructorDoc.build());
      Node exprResult = IR.exprResult(assign);
      exprResult.useSourceInfoIfMissingFromForTree(cls.target);
      block.addChildToBack(exprResult);
    } else {
      // var foo = Polymer({...}); OR Polymer({...});
      Node var = IR.var(cls.target.cloneTree(), cls.constructor.value.cloneTree());
      NodeUtil.markNewScopesChanged(var, compiler);
      var.useSourceInfoIfMissingFromForTree(exprRoot);
      var.setJSDocInfo(constructorDoc.build());
      block.addChildToBack(var);
    }

    appendPropertiesToBlock(cls.props, block, cls.target.getQualifiedName() + ".prototype.");
    appendBehaviorMembersToBlock(cls, block);
    ImmutableList<MemberDefinition> readOnlyProps = parseReadOnlyProperties(cls, block);
    ImmutableList<MemberDefinition> attributeReflectedProps =
        parseAttributeReflectedProperties(cls);
    createExportsAndExterns(cls, readOnlyProps, attributeReflectedProps);
    removePropertyDocs(objLit, PolymerClassDefinition.DefinitionType.ObjectLiteral);

    Node statements = block.removeChildren();
    Node parent = exprRoot.getParent();

    // If the call to Polymer() is not in the global scope and the assignment target
    // is not namespaced (which likely means it's exported to the global scope), put the type
    // declaration into the global scope at the start of the current script.
    //
    // This avoids unknown type warnings which are a result of the compiler's poor understanding of
    // types declared inside IIFEs or any non-global scope. We should revisit this decision as
    // the typechecker's support for non-global types improves.
    if (!isInGlobalScope && !cls.target.isGetProp()) {
      Node scriptNode = NodeUtil.getEnclosingScript(parent);
      scriptNode.addChildrenToFront(statements);
      compiler.reportChangeToChangeScope(scriptNode);
    } else {
      Node beforeRoot = exprRoot.getPrevious();
      if (beforeRoot == null) {
        parent.addChildrenToFront(statements);
      } else {
        parent.addChildrenAfter(statements, beforeRoot);
      }
      compiler.reportChangeToEnclosingScope(parent);
    }
    compiler.reportChangeToEnclosingScope(statements);

    // Since behavior files might contain language features that aren't present in the class file,
    // we might need to update the FeatureSet.
    if (cls.features != null) {
      Node scriptNode = NodeUtil.getEnclosingScript(parent);
      FeatureSet oldFeatures = (FeatureSet) scriptNode.getProp(Node.FEATURE_SET);
      FeatureSet newFeatures = oldFeatures.union(cls.features);
      if (!newFeatures.equals(oldFeatures)) {
        scriptNode.putProp(Node.FEATURE_SET, newFeatures);
        compiler.reportChangeToChangeScope(scriptNode);
      }
    }

    if (NodeUtil.isNameDeclaration(exprRoot)) {
      Node assignExpr = varToAssign(exprRoot);
      parent.replaceChild(exprRoot, assignExpr);
      compiler.reportChangeToEnclosingScope(assignExpr);
    }

    // If property renaming is enabled, wrap the properties object literal
    // in a reflection call so that the properties are renamed consistently
    // with the class members.
    if (polymerVersion > 1 && propertyRenamingEnabled && cls.descriptor != null) {
      Node props = NodeUtil.getFirstPropMatchingKey(cls.descriptor, "properties");
      if (props != null && props.isObjectLit()) {
        addPropertiesConfigObjectReflection(cls, props);
      }
    }
  }
void rewritePolymerCall ( Node exprRoot , final PolymerClassDefinition cls , boolean isInGlobalScope ) { Node objLit = checkNotNull ( cls . descriptor ) ; JSDocInfoBuilder objLitDoc = new JSDocInfoBuilder ( true ) ; JSTypeExpression jsTypeExpression = new JSTypeExpression ( IR . string ( cls . target . getQualifiedName ( ) + ".prototype" ) , exprRoot . getSourceFileName ( ) ) ; objLitDoc . recordLends ( jsTypeExpression ) ; objLit . setJSDocInfo ( objLitDoc . build ( ) ) ; addTypesToFunctions ( objLit , cls . target . getQualifiedName ( ) , cls . defType ) ; PolymerPassStaticUtils . switchDollarSignPropsToBrackets ( objLit , compiler ) ; PolymerPassStaticUtils . quoteListenerAndHostAttributeKeys ( objLit , compiler ) ; for ( MemberDefinition prop : cls . props ) { if ( prop . value . isObjectLit ( ) ) { PolymerPassStaticUtils . switchDollarSignPropsToBrackets ( prop . value , compiler ) ; } } Node block = IR . block ( ) ; JSDocInfoBuilder constructorDoc = this . getConstructorDoc ( cls ) ; Node ctorKey = cls . constructor . value . getParent ( ) ; if ( ctorKey != null ) { ctorKey . removeProp ( Node . JSDOC_INFO_PROP ) ; } if ( cls . target . isGetProp ( ) ) { Node assign = IR . assign ( cls . target . cloneTree ( ) , cls . constructor . value . cloneTree ( ) ) ; NodeUtil . markNewScopesChanged ( assign , compiler ) ; assign . setJSDocInfo ( constructorDoc . build ( ) ) ; Node exprResult = IR . exprResult ( assign ) ; exprResult . useSourceInfoIfMissingFromForTree ( cls . target ) ; block . addChildToBack ( exprResult ) ; } else { Node var = IR . var ( cls . target . cloneTree ( ) , cls . constructor . value . cloneTree ( ) ) ; NodeUtil . markNewScopesChanged ( var , compiler ) ; var . useSourceInfoIfMissingFromForTree ( exprRoot ) ; var . setJSDocInfo ( constructorDoc . build ( ) ) ; block . addChildToBack ( var ) ; } appendPropertiesToBlock ( cls . props , block , cls . target . getQualifiedName ( ) + ".prototype." ) ; appendBehaviorMembersToBlock ( cls , block ) ; ImmutableList < MemberDefinition > readOnlyProps = parseReadOnlyProperties ( cls , block ) ; ImmutableList < MemberDefinition > attributeReflectedProps = parseAttributeReflectedProperties ( cls ) ; createExportsAndExterns ( cls , readOnlyProps , attributeReflectedProps ) ; removePropertyDocs ( objLit , PolymerClassDefinition . DefinitionType . ObjectLiteral ) ; Node statements = block . removeChildren ( ) ; Node parent = exprRoot . getParent ( ) ; if ( ! isInGlobalScope && ! cls . target . isGetProp ( ) ) { Node scriptNode = NodeUtil . getEnclosingScript ( parent ) ; scriptNode . addChildrenToFront ( statements ) ; compiler . reportChangeToChangeScope ( scriptNode ) ; } else { Node beforeRoot = exprRoot . getPrevious ( ) ; if ( beforeRoot == null ) { parent . addChildrenToFront ( statements ) ; } else { parent . addChildrenAfter ( statements , beforeRoot ) ; } compiler . reportChangeToEnclosingScope ( parent ) ; } compiler . reportChangeToEnclosingScope ( statements ) ; if ( cls . features != null ) { Node scriptNode = NodeUtil . getEnclosingScript ( parent ) ; FeatureSet oldFeatures = ( FeatureSet ) scriptNode . getProp ( Node . FEATURE_SET ) ; FeatureSet newFeatures = oldFeatures . union ( cls . features ) ; if ( ! newFeatures . equals ( oldFeatures ) ) { scriptNode . putProp ( Node . FEATURE_SET , newFeatures ) ; compiler . reportChangeToChangeScope ( scriptNode ) ; } } if ( NodeUtil . isNameDeclaration ( exprRoot ) ) { Node assignExpr = varToAssign ( exprRoot ) ; parent . replaceChild ( exprRoot , assignExpr ) ; compiler . reportChangeToEnclosingScope ( assignExpr ) ; } if ( polymerVersion > 1 && propertyRenamingEnabled && cls . descriptor != null ) { Node props = NodeUtil . getFirstPropMatchingKey ( cls . descriptor , "properties" ) ; if ( props != null && props . isObjectLit ( ) ) { addPropertiesConfigObjectReflection ( cls , props ) ; } } }
Rewrites a given call to Polymer({}) to a set of declarations and assignments which can be
understood by the compiler.

@param exprRoot The root expression of the call to Polymer({}).
@param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this
call.