@Override
  public void visitVariablesDeclaration(VariablesDeclaration v) {
    super.visitVariablesDeclaration(v);
    if (v.findParentOfTypes(Struct.class, Function.class, Enum.class) != null) return;

    for (Declarator d : v.getDeclarators()) globalVariablesByName.put(ident(d.resolveName()), v);
    getList(globalsByLibrary, getLibrary(v)).add(v);
  }
 @Override
 public void visitFunctionSignature(FunctionSignature functionSignature) {
   super.visitFunctionSignature(functionSignature);
   Function function = functionSignature.getFunction();
   if (function != null) {
     getList(callbacksByLibrary, getLibrary(functionSignature)).add(functionSignature);
     Identifier name = typeConverter.inferCallBackName(functionSignature, false, false, null);
     if (name != null) {
       callbacksByName.put(name, functionSignature);
       Identifier identifier =
           typeConverter.inferCallBackName(functionSignature, true, true, null);
       if (identifier != null) callbacksFullNames.add(identifier);
     }
   }
 }
  @Override
  public void visitEnumItem(EnumItem enumItem) {
    super.visitEnumItem(enumItem);
    enumItems.put(enumItem.getName(), enumItem);

    String library = getLibrary(enumItem);
    if (library == null) return;

    Element parent = enumItem.getParentElement();
    if (parent == null || !(parent instanceof Enum)) return;

    Enum e = (Enum) parent;
    Identifier ident =
        ident(
            getLibraryClassFullName(library),
            declarationsConverter.getActualTaggedTypeName(e),
            ident(enumItem.getName()));
    enumItemsFullName.add(ident);
  }
  @Override
  public void visitFunction(Function function) {
    super.visitFunction(function);
    Element parent = function.getParentElement();
    if (parent != null) {
      if (parent instanceof FunctionSignature) return;
      if (parent instanceof Struct) {
        Struct parentStruct = (Struct) parent;
        switch (parentStruct.getType()) {
          case CPPClass:
            //						if (config.genCPlusPlus)
            //							break;
          case JavaClass:
          case JavaInterface:
          case ObjCClass:
          case ObjCProtocol:
          case CStruct:
            return;
        }
      }
    }

    getList(functionsByLibrary, getLibrary(function)).add(function);
  }
  @Override
  public void visitStruct(Struct struct) {
    super.visitStruct(struct);

    Identifier name = struct.getTag();
    if (name != null) {
      switch (struct.getType()) {
        case CPPClass:
          if (!config.runtime.equals(JNAeratorConfig.Runtime.BridJ) && !config.genCPlusPlus) break;
        case CStruct:
        case CUnion:
          boolean isFwd = struct.isForwardDeclaration();
          if (!isFwd
              && struct.getDeclarations().isEmpty()
              && config.treatEmptyStructsAsForwardDecls) {
            List<SimpleTypeRef> parents = struct.getParents();
            Struct p;
            if (parents.isEmpty()
                || parents.size() == 1
                    && ((p = structsByName.get(parents.get(0))) == null
                        || p.isForwardDeclaration())) isFwd = true;
          }

          if (isFwd) break;

          if (config.skipIncludedFrameworks) {
            String lib = getLibrary(struct);
            if (lib != null) {
              if (!config.frameworks.contains(lib)) break;
            }
          }
          Struct oldStruct = structsByName.get(name);

          if (oldStruct == null
              || oldStruct.isForwardDeclaration()
              || (!(oldStruct.getParentElement() instanceof TypeDef)
                  && struct.getParentElement() instanceof TypeDef)) {
            structsByName.put(name, struct);

            getList(structsByLibrary, getLibrary(struct)).add(struct);
            Identifier identifier = getTaggedTypeIdentifierInJava(struct);
            if (identifier != null) {
              if (struct.getType() == Type.CUnion) unionsFullNames.add(identifier);
              structsFullNames.add(identifier);
            }
          }

          break;
        case ObjCClass:
        case ObjCProtocol:
          //				if (name.equals("NSObject"))
          //					name = name.clone();

          if (struct.isForwardDeclaration()) break;

          if (struct.getCategoryName() != null) {
            getMap(objCCategoriesByTargetType, struct.getTag())
                .put(struct.getCategoryName(), struct);
            objCCategoriesByName.put(struct.getCategoryName(), struct);
          } else getMap(classes, struct.getType()).put(struct.getTag(), struct);

          break;
        default:
          struct = null;
      }
    }
  }
 @Override
 public void visitTypeDef(TypeDef typeDef) {
   super.visitTypeDef(typeDef);
   for (Declarator vs : typeDef.getDeclarators())
     typeDefs.put(vs.resolveName(), new Pair<TypeDef, Declarator>(typeDef, vs));
 }
  @Override
  public void visitEnum(Enum e) {
    super.visitEnum(e);
    if (e.getTag() == null) {
      // Hack to infer the enum name from the next typedef NSUInteger
      // NSSomethingThatLooksLikeTheEnumsIdentifiers
      Element nextDeclaration = e.getNextSibling();
      if (nextDeclaration != null && (nextDeclaration instanceof TypeDef)) {
        TypeDef typeDef = (TypeDef) nextDeclaration;
        TypeRef type = typeDef.getValueType();
        if (type instanceof TypeRef.SimpleTypeRef) {
          String simpleTypeStr = ((TypeRef.SimpleTypeRef) type).getName().toString();
          if (simpleTypeStr.equals("NSUInteger")
              || simpleTypeStr.equals("NSInteger")
              || simpleTypeStr.equals("CFIndex")) {
            Declarator bestPlainStorage = null;
            for (Declarator st : typeDef.getDeclarators()) {
              if (st instanceof DirectDeclarator) {
                String name = st.resolveName();
                boolean niceName = StringUtils.trimUnderscores(name).equals(name);
                ;
                if (bestPlainStorage == null || niceName) {
                  bestPlainStorage = st;
                  if (niceName) break;
                }
              }
            }
            if (bestPlainStorage != null) {
              String name = bestPlainStorage.resolveName();
              System.err.println("Automatic struct name matching : " + name);
              e.setTag(ident(name));
            }
          }
        }
      }
    }

    Identifier name = e.getTag();
    String lib = getLibrary(e);
    if (name == null) getList(enumsByLibrary, lib).add(e);
    else {
      Enum oldEnum = enumsByName.get(name);

      if (oldEnum == null
          || oldEnum.isForwardDeclaration()
          || (!(oldEnum.getParentElement() instanceof TypeDef)
              && oldEnum.getParentElement() instanceof TypeDef)) {
        enumsByName.put(name, e);

        // if (e.getTag() != null) {
        //	enumsByName.put(e.getTag(), e);
        // }
        getList(enumsByLibrary, lib).add(e);

        Identifier identifier = getTaggedTypeIdentifierInJava(e);
        if (identifier != null) {
          enumsFullNames.add(identifier);
        }
      }
    }
  }
 @Override
 public void visitDefine(Define define) {
   super.visitDefine(define);
   defines.put(define.getName(), define);
   getList(definesByLibrary, getLibrary(define)).add(define);
 }