private ClassDefinition extractClassDefinition(
      Node targetName, Node callNode) {

    JSDocInfo classInfo = NodeUtil.getBestJSDocInfo(targetName);

    // name = goog.defineClass(superClass, {...}, [modifier, ...])
    Node superClass = NodeUtil.getArgumentForCallOrNew(callNode, 0);
    if (superClass == null
        || (!superClass.isNull()
            && !superClass.isQualifiedName()
            && !NodeUtil.isCallTo(superClass, "goog.module.get"))) {
      compiler.report(JSError.make(callNode, GOOG_CLASS_SUPER_CLASS_NOT_VALID));
      return null;
    }

    if (NodeUtil.isNullOrUndefined(superClass)
        || superClass.matchesQualifiedName("Object")) {
      superClass = null;
    }

    Node description = NodeUtil.getArgumentForCallOrNew(callNode, 1);
    if (!validateObjLit(description, callNode)) {
      // Errors will be reported in the validate method. Keeping here clean
      return null;
    }

    int paramCount = callNode.getChildCount() - 1;
    if (paramCount > 2) {
      compiler.report(JSError.make(callNode, GOOG_CLASS_UNEXPECTED_PARAMS));
      return null;
    }

    Node constructor = extractProperty(description, "constructor");
    if (classInfo != null && classInfo.isInterface()) {
      if (constructor != null) {
        compiler.report(JSError.make(description, GOOG_CLASS_CONSTRUCTOR_ON_INTERFACE));
        return null;
      }
    } else if (constructor == null) {
      // report missing constructor
      compiler.report(JSError.make(description, GOOG_CLASS_CONSTRUCTOR_MISSING));
      return null;
    } else {
      if (!constructor.isFunction()) {
        compiler.report(JSError.make(constructor, GOOG_CLASS_CONSTRUCTOR_NOT_VALID));
      }
    }

    if (constructor == null) {
      constructor = IR.function(
          IR.name("").srcref(callNode),
          IR.paramList().srcref(callNode),
          IR.block().srcref(callNode));
      constructor.srcref(callNode);
      compiler.reportChangeToChangeScope(constructor);
    }

    JSDocInfo info = NodeUtil.getBestJSDocInfo(constructor);

    Node classModifier = null;
    Node statics = null;
    Node staticsProp = extractProperty(description, "statics");
    if (staticsProp != null) {
      if (staticsProp.isObjectLit()){
        if (!validateObjLit(staticsProp, staticsProp.getParent())) {
          // Errors will be reported in the validate method. Keeping here clean
          return null;
        }
        statics = staticsProp;
      } else if (staticsProp.isFunction()) {
        classModifier = staticsProp;
      } else {
        compiler.report(
            JSError.make(staticsProp, GOOG_CLASS_STATICS_NOT_VALID));
        return null;
      }
    }

    if (statics == null) {
      statics = IR.objectlit();
    }

    // Ok, now rip apart the definition into its component pieces.
    // Remove the "special" property key nodes.
    maybeDetach(constructor.getParent());
    maybeDetach(statics.getParent());
    if (classModifier != null) {
      maybeDetach(classModifier.getParent());
    }
    ClassDefinition def = new ClassDefinition(
        targetName,
        classInfo,
        maybeDetach(superClass),
        new MemberDefinition(info, null, maybeDetach(constructor)),
        objectLitToList(maybeDetach(statics)),
        objectLitToList(description),
        maybeDetach(classModifier));
    return def;
  }
private ClassDefinition extractClassDefinition ( Node targetName , Node callNode ) { JSDocInfo classInfo = NodeUtil . getBestJSDocInfo ( targetName ) ; Node superClass = NodeUtil . getArgumentForCallOrNew ( callNode , 0 ) ; if ( superClass == null || ( ! superClass . isNull ( ) && ! superClass . isQualifiedName ( ) && ! NodeUtil . isCallTo ( superClass , "goog.module.get" ) ) ) { compiler . report ( JSError . make ( callNode , GOOG_CLASS_SUPER_CLASS_NOT_VALID ) ) ; return null ; } if ( NodeUtil . isNullOrUndefined ( superClass ) || superClass . matchesQualifiedName ( "Object" ) ) { superClass = null ; } Node description = NodeUtil . getArgumentForCallOrNew ( callNode , 1 ) ; if ( ! validateObjLit ( description , callNode ) ) { return null ; } int paramCount = callNode . getChildCount ( ) - 1 ; if ( paramCount > 2 ) { compiler . report ( JSError . make ( callNode , GOOG_CLASS_UNEXPECTED_PARAMS ) ) ; return null ; } Node constructor = extractProperty ( description , "constructor" ) ; if ( classInfo != null && classInfo . isInterface ( ) ) { if ( constructor != null ) { compiler . report ( JSError . make ( description , GOOG_CLASS_CONSTRUCTOR_ON_INTERFACE ) ) ; return null ; } } else if ( constructor == null ) { compiler . report ( JSError . make ( description , GOOG_CLASS_CONSTRUCTOR_MISSING ) ) ; return null ; } else { if ( ! constructor . isFunction ( ) ) { compiler . report ( JSError . make ( constructor , GOOG_CLASS_CONSTRUCTOR_NOT_VALID ) ) ; } } if ( constructor == null ) { constructor = IR . function ( IR . name ( "" ) . srcref ( callNode ) , IR . paramList ( ) . srcref ( callNode ) , IR . block ( ) . srcref ( callNode ) ) ; constructor . srcref ( callNode ) ; compiler . reportChangeToChangeScope ( constructor ) ; } JSDocInfo info = NodeUtil . getBestJSDocInfo ( constructor ) ; Node classModifier = null ; Node statics = null ; Node staticsProp = extractProperty ( description , "statics" ) ; if ( staticsProp != null ) { if ( staticsProp . isObjectLit ( ) ) { if ( ! validateObjLit ( staticsProp , staticsProp . getParent ( ) ) ) { return null ; } statics = staticsProp ; } else if ( staticsProp . isFunction ( ) ) { classModifier = staticsProp ; } else { compiler . report ( JSError . make ( staticsProp , GOOG_CLASS_STATICS_NOT_VALID ) ) ; return null ; } } if ( statics == null ) { statics = IR . objectlit ( ) ; } maybeDetach ( constructor . getParent ( ) ) ; maybeDetach ( statics . getParent ( ) ) ; if ( classModifier != null ) { maybeDetach ( classModifier . getParent ( ) ) ; } ClassDefinition def = new ClassDefinition ( targetName , classInfo , maybeDetach ( superClass ) , new MemberDefinition ( info , null , maybeDetach ( constructor ) ) , objectLitToList ( maybeDetach ( statics ) ) , objectLitToList ( description ) , maybeDetach ( classModifier ) ) ; return def ; }
Validates the class definition and if valid, destructively extracts
the class definition from the AST.