/** Called on each content unit that is not part of the default value. */
  private void processNonDefaultPropertyContentUnit(MXMLTreeBuilder builder, MXMLNodeInfo info) {
    // If this gets called and we're processing the default property,
    // then childTag is the first child tag after the default property value tags.
    if (processingDefaultProperty) {
      processingDefaultProperty = false;
      processedDefaultProperty = true;

      assert defaultPropertyContentUnits.size() > 0;
      assert !builder.getFileScope().isScriptTag(defaultPropertyContentUnits.get(0))
          : "First default property content unit must not be a script tag!";
      // We've accumulated all the default property child tags
      // in defaultPropertyChildTags. Use them to initialize
      // the defaultPropertyNode.

      // But first find all the trailing script tags
      // and remove those from the list of default
      // property content units.
      // Script tags are put in the defaultPropertyContentUnits collection
      // to fix http://bugs.adobe.com/jira/browse/CMP-955.
      int lastNonScriptTagIndex;
      for (lastNonScriptTagIndex = (defaultPropertyContentUnits.size() - 1);
          lastNonScriptTagIndex > 0;
          --lastNonScriptTagIndex) {
        MXMLUnitData unitData = defaultPropertyContentUnits.get(lastNonScriptTagIndex);
        if (!builder.getFileScope().isScriptTag(unitData)) break;
      }
      assert lastNonScriptTagIndex >= 0;
      assert lastNonScriptTagIndex < defaultPropertyContentUnits.size();

      List<MXMLUnitData> trailingScriptTags =
          defaultPropertyContentUnits.subList(
              lastNonScriptTagIndex + 1, defaultPropertyContentUnits.size());
      List<MXMLUnitData> defaultPropertyContentUnitsWithoutTrailingScriptTags =
          defaultPropertyContentUnits.subList(0, lastNonScriptTagIndex + 1);

      // process the default property content units with the trailing
      // script tags removed.
      IVariableDefinition defaultPropertyDefinition = getDefaultPropertyDefinition(builder);
      defaultPropertyNode.initializeDefaultProperty(
          builder, defaultPropertyDefinition, defaultPropertyContentUnitsWithoutTrailingScriptTags);

      // Now create MXMLScriptNode's for all the trailing script tags.
      for (MXMLUnitData scriptTagData : trailingScriptTags) {
        assert builder.getFileScope().isScriptTag(scriptTagData);
        MXMLScriptNode scriptNode = new MXMLScriptNode(this);
        scriptNode.initializeFromTag(builder, (MXMLTagData) scriptTagData);
        info.addChildNode(scriptNode);
      }
    }
  }
  @Override
  protected void processTagSpecificAttribute(
      MXMLTreeBuilder builder, MXMLTagData tag, MXMLTagAttributeData attribute, MXMLNodeInfo info) {

    MXMLSpecifierNodeBase childNode = createSpecifierNode(builder, attribute.getName());
    if (childNode != null) {
      childNode.setLocation(attribute);
      childNode.setSuffix(builder, attribute.getStateName());
      childNode.initializeFromAttribute(builder, attribute, info);
      info.addChildNode(childNode);
    } else {
      super.processTagSpecificAttribute(builder, tag, attribute, info);
    }
  }
 @Override
 protected void processChildNonWhitespaceUnit(
     MXMLTreeBuilder builder, MXMLTagData tag, MXMLTextData text, MXMLNodeInfo info) {
   // Non-whitespace may be the value of a default property.
   IVariableDefinition defaultPropertyDefinition = getDefaultPropertyDefinition(builder);
   if (defaultPropertyDefinition != null) {
     MXMLSpecifierNodeBase childNode =
         createSpecifierNode(builder, defaultPropertyDefinition.getBaseName());
     if (childNode != null) {
       childNode.initializeFromText(builder, text, info);
       info.addChildNode(childNode);
     }
   } else {
     super.processChildNonWhitespaceUnit(builder, tag, text, info);
   }
 }
  @Override
  protected void initializationComplete(
      MXMLTreeBuilder builder, MXMLTagData tag, MXMLNodeInfo info) {
    super.initializationComplete(builder, tag, info);

    // If the last child unit was part of the default property,
    // we don't know to process the default property units
    // until we get here.
    processNonDefaultPropertyContentUnit(builder, info);

    setChildren(info.getChildNodeList().toArray(new IMXMLNode[0]));

    // If the class references by this node implements mx.core.IContainer,
    // add an expression dependency on mx.core.UIComponentDescriptor
    // because we'll have to codegen descriptors.
    if (isContainer) {
      FlexProject project = builder.getProject();
      builder.addExpressionDependency(project.getUIComponentDescriptorClass());
    }
  }
  /** Called on each content unit that is part of the default value. */
  private void processDefaultPropertyContentUnit(
      MXMLTreeBuilder builder, MXMLTagData childTag, MXMLNodeInfo info) {
    // If this gets called and we're not already processing the default property,
    // then childTag is the first child tag of the default property value.
    if (!processingDefaultProperty) {
      processingDefaultProperty = true;

      String defaultPropertyName = getDefaultPropertyDefinition(builder).getBaseName();

      // Create an implicit MXMLPropertySpecifierNode for the default property,
      // at the correct location in the child list.
      defaultPropertyNode =
          (MXMLPropertySpecifierNode) createSpecifierNode(builder, defaultPropertyName);
      info.addChildNode(defaultPropertyNode);

      // Create a list in which we'll accumulate the tags for the default property.
      defaultPropertyContentUnits = new ArrayList<MXMLUnitData>(1);
    }

    defaultPropertyContentUnits.add(childTag);
  }
  @Override
  protected void processChildTag(
      MXMLTreeBuilder builder, MXMLTagData tag, MXMLTagData childTag, MXMLNodeInfo info) {
    if (info.hasSpecifierWithName(childTag.getShortName(), childTag.getStateName())) {
      ICompilerProblem problem = new MXMLDuplicateChildTagProblem(childTag);
      builder.addProblem(problem);
      return;
    }

    FlexProject project = builder.getProject();

    // Handle child tags that are property/style/event specifiers.
    MXMLSpecifierNodeBase childNode = createSpecifierNode(builder, childTag.getShortName());
    if (childNode != null) {
      // This tag is not part of the default property value.
      processNonDefaultPropertyContentUnit(builder, info);

      childNode.setSuffix(builder, childTag.getStateName());
      childNode.initializeFromTag(builder, childTag);
      info.addChildNode(childNode);
    } else if (builder.getFileScope().isScriptTag(childTag)
        && (builder.getMXMLDialect().isEqualToOrBefore(MXMLDialect.MXML_2009))) {
      // In MXML 2006 and 2009, allow a <Script> tag
      // inside any class reference tag

      if (!processingDefaultProperty) {
        // Not processing the default property, just make a script
        // node and put it in the tree.
        MXMLScriptNode scriptNode = new MXMLScriptNode(this);
        scriptNode.initializeFromTag(builder, childTag);
        info.addChildNode(scriptNode);
      } else {
        // We are processing a default property.  Script nodes need
        // to be a child of that default specifier nodes so that
        // finding a node by offset works properly.
        // See: http://bugs.adobe.com/jira/browse/CMP-955
        processDefaultPropertyContentUnit(builder, childTag, info);
      }

    } else if (builder.getFileScope().isReparentTag(childTag)) {
      MXMLReparentNode reparentNode = new MXMLReparentNode(this);
      reparentNode.initializeFromTag(builder, childTag);
      info.addChildNode(reparentNode);
    } else {
      IDefinition definition = builder.getFileScope().resolveTagToDefinition(childTag);
      if (definition instanceof ClassDefinition) {
        // Handle child tags that are instance tags.

        IVariableDefinition defaultPropertyDefinition = getDefaultPropertyDefinition(builder);
        if (defaultPropertyDefinition != null && !processedDefaultProperty) {
          // Since there is a default property and we haven't already processed it,
          // assume this child instance tag is part of its value.
          processDefaultPropertyContentUnit(builder, childTag, info);
        } else {
          // This tag is not part of the default property value.
          processNonDefaultPropertyContentUnit(builder, info);

          MXMLInstanceNode instanceNode =
              MXMLInstanceNode.createInstanceNode(builder, definition.getQualifiedName(), this);
          instanceNode.setClassReference(
              project,
              (IClassDefinition) definition); // TODO Move this logic to initializeFromTag().
          instanceNode.initializeFromTag(builder, childTag);
          info.addChildNode(instanceNode);
        }
      } else {
        // Handle child tags that are something other than property/style/event tags
        // or instance tags.

        // This tag is not part of the default property value.
        processNonDefaultPropertyContentUnit(builder, info);

        super.processChildTag(builder, tag, childTag, info);
      }
    }
  }