public void clearClassesCache() {
   synchronized (PsiLock.LOCK) {
     if (myMacroDefinition != null) {
       final AntFile file = getAntFile();
       for (AntTypeId id : myMacroDefinition.getNestedElements()) {
         final AntTypeDefinition nestedDef =
             file.getBaseTypeDefinition(myMacroDefinition.getNestedClassName(id));
         if (nestedDef != null) {
           file.unregisterCustomType(nestedDef);
         }
       }
       final AntStructuredElement parent = getAntProject();
       if (parent != null) {
         parent.unregisterCustomType(myMacroDefinition);
       }
       myMacroDefinition = null;
     }
   }
 }
  @SuppressWarnings({"HardCodedStringLiteral"})
  private void invalidateMacroDefinition() {
    if (!hasNameElement()) {
      myMacroDefinition = null;
      return;
    }

    final AntFile file = getAntFile();
    if (file == null) return;

    final String thisClassName = createMacroClassName(getName());
    myMacroDefinition = (AntTypeDefinitionImpl) file.getBaseTypeDefinition(thisClassName);
    final Map<String, AntAttributeType> attributes =
        (myMacroDefinition == null)
            ? new HashMap<String, AntAttributeType>()
            : myMacroDefinition.getAttributesMap();
    attributes.clear();
    final Map<AntTypeId, String> nestedElements =
        (myMacroDefinition == null)
            ? new HashMap<AntTypeId, String>()
            : myMacroDefinition.getNestedElementsMap();
    for (AntElement child : getChildren()) {
      if (child instanceof AntStructuredElement) {
        final AntStructuredElement se = (AntStructuredElement) child;
        final String name = se.getName();
        if (name != null) {
          final String tagName = se.getSourceElement().getName();
          if (tagName.equals("attribute")) {
            attributes.put(name.toLowerCase(Locale.US), AntAttributeType.STRING);
          } else if (tagName.equals("element")) {
            final String elementClassName = thisClassName + '$' + name;
            AntTypeDefinitionImpl nestedDef =
                (AntTypeDefinitionImpl) file.getBaseTypeDefinition(elementClassName);
            if (nestedDef == null) {
              final AntTypeDefinitionImpl targetDef =
                  (AntTypeDefinitionImpl) file.getTargetDefinition();
              if (targetDef != null) {
                nestedDef = new AntTypeDefinitionImpl(targetDef);
              }
            }
            if (nestedDef != null) {
              final AntTypeId typeId = new AntTypeId(name);
              nestedDef.setTypeId(typeId);
              nestedDef.setClassName(elementClassName);
              nestedDef.setIsTask(false);
              nestedDef.setDefiningElement(child);
              file.registerCustomType(nestedDef);
              nestedElements.put(typeId, nestedDef.getClassName());
            }
          }
        }
      }
    }
    final AntTypeId definedTypeId = new AntTypeId(getName());
    if (myMacroDefinition == null) {
      myMacroDefinition =
          new AntTypeDefinitionImpl(
              definedTypeId, thisClassName, true, false, attributes, nestedElements, this);
    } else {
      myMacroDefinition.setTypeId(definedTypeId);
      myMacroDefinition.setClassName(thisClassName);
      myMacroDefinition.setIsTask(true);
      myMacroDefinition.setDefiningElement(this);
    }
    final AntStructuredElement parent = getAntProject();
    if (parent != null) {
      parent.registerCustomType(myMacroDefinition);
    }
    // define itself as nested task for sequential
    final AntAllTasksContainerImpl sequential =
        PsiTreeUtil.getChildOfType(this, AntAllTasksContainerImpl.class);
    if (sequential != null) {
      sequential.registerCustomType(myMacroDefinition);
      for (final AntTypeId id : myMacroDefinition.getNestedElements()) {
        sequential.registerCustomType(
            file.getBaseTypeDefinition(myMacroDefinition.getNestedClassName(id)));
      }
    }
  }