docs: private static String attributeName(SourceCode cfml, RefBoolean dynamic, ArrayList<String> args, TagLibTag tag, StringBuffer sbType, boolean[] parseExpression,
  	    boolean allowDefaultValue) throws TemplateException {
  
  	String _id = identifier(cfml, !allowDefaultValue, true);
  	if (StringUtil.isEmpty(_id)) {
  	    return null;
  	}
  
  	int typeDef = tag.getAttributeType();
  	String id = StringUtil.toLowerCase(_id);
  	if (args.contains(id)) throw createTemplateException(cfml, "you can't use the same tag attribute [" + id + "] twice", tag);
  	args.add(id);
  
  	if ("attributecollection".equals(id)) {
  	    dynamic.setValue(tag.getAttribute(id, true) == null);
  	    sbType.append("struct");
  	    parseExpression[0] = true;
  	    parseExpression[1] = true;
  	}
  	else if (typeDef == TagLibTag.ATTRIBUTE_TYPE_FIXED || typeDef == TagLibTag.ATTRIBUTE_TYPE_MIXED) {
  	    TagLibTagAttr attr = tag.getAttribute(id, true);
  	    if (attr == null) {
  		if (typeDef == TagLibTag.ATTRIBUTE_TYPE_FIXED) {
  		    String names = tag.getAttributeNames();
  		    if (StringUtil.isEmpty(names)) throw createTemplateException(cfml, "Attribute " + id + " is not allowed for tag " + tag.getFullName(), tag);
  
  		    try {
  			names = ListUtil.sort(names, "textnocase", null, null);
  		    }
  		    catch (Throwable t) {
  			ExceptionUtil.rethrowIfNecessary(t);
  		    }
  		    throw createTemplateException(cfml, "Attribute " + id + " is not allowed for tag " + tag.getFullName(), "valid attribute names are [" + names + "]", tag);
  		}
  		dynamic.setValue(true);
  	    }
  	    else {
  		id = attr.getName();
  		sbType.append(attr.getType());
  		parseExpression[0] = attr.getRtexpr();
  	    }
  	}
  	else if (typeDef == TagLibTag.ATTRIBUTE_TYPE_DYNAMIC) {
  	    dynamic.setValue(true);
  	}
  	return id;
      }