/**
   * See {@link PhpElementResolver#decodeDocInfo(String)} for the decoding routine.
   *
   * @param declaration Declaration ASTNode
   * @return decoded PHPDoc info, or <code>null</code> if there's no PHPDoc info to store.
   */
  protected static String encodeDocInfo(Declaration declaration) {
    if (declaration instanceof IPHPDocAwareDeclaration) {
      PHPDocBlock docBlock = ((IPHPDocAwareDeclaration) declaration).getPHPDoc();
      if (docBlock != null) {
        Map<String, String> info = new HashMap<String, String>();
        for (PHPDocTag tag : docBlock.getTags()) {
          if (tag.getTagKind() == PHPDocTag.DEPRECATED) {
            info.put("d", null); // $NON-NLS-1$
          } else if (tag.getTagKind() == PHPDocTag.RETURN) {
            StringBuilder buf = new StringBuilder();
            for (TypeReference ref : tag.getTypeReferences()) {
              String type = ref.getName().replaceAll(",", "~"); // $NON-NLS-1$ //$NON-NLS-2$
              if (buf.length() > 0) {
                buf.append(',');
              }
              buf.append(type);
            }
            info.put("r", buf.toString()); // $NON-NLS-1$
          } else if (tag.getTagKind() == PHPDocTag.VAR) {
            if (tag.getTypeReferences().size() > 0) {
              String typeNames = PHPModelUtils.appendTypeReferenceNames(tag.getTypeReferences());
              typeNames = typeNames.replace(Constants.TYPE_SEPERATOR_CHAR, Constants.DOT);

              info.put("v", typeNames); // $NON-NLS-1$
            }
          }
        }
        return encodeDocInfo(info);
      }
    }
    return null;
  }
 public boolean visit(UseStatement declaration) throws Exception {
   Collection<UsePart> parts = declaration.getParts();
   for (UsePart part : parts) {
     String name = null;
     if (part.getAlias() != null) {
       name = part.getAlias().getName();
     } else {
       name = part.getNamespace().getName();
       int index = name.lastIndexOf(NamespaceReference.NAMESPACE_SEPARATOR);
       if (index >= 0) {
         name = name.substring(index + 1);
       }
     }
     fLastUseParts.put(name, part);
   }
   return visitGeneral(declaration);
 }
 public boolean visit(UseStatement declaration) throws Exception {
   Collection<UsePart> parts = declaration.getParts();
   for (UsePart part : parts) {
     String name = null;
     if (part.getAlias() != null) {
       name = part.getAlias().getName();
     } else {
       name = part.getNamespace().getName();
       int index = name.lastIndexOf(NamespaceReference.NAMESPACE_SEPARATOR);
       if (index >= 0) {
         name = name.substring(index + 1);
       }
     }
     ImportInfo info = new ImportInfo();
     String containerName;
     if (fLastNamespace == null) {
       containerName = GLOBAL_NAMESPACE_CONTAINER_NAME;
     } else {
       containerName = fLastNamespace.getName();
     }
     info.containerName = containerName;
     if (declaration.getNamespace() == null) {
       info.name = part.getNamespace().getFullyQualifiedName();
     } else {
       info.name =
           PHPModelUtils.concatFullyQualifiedNames(
               declaration.getNamespace().getFullyQualifiedName(),
               part.getNamespace().getFullyQualifiedName());
     }
     info.sourceStart = part.getNamespace().sourceStart();
     info.sourceEnd = part.getNamespace().sourceEnd();
     fRequestor.acceptImport(info);
     fLastUseParts.put(name, part);
   }
   return true;
 }
  /**
   * Resolve class members that were defined using the @property tag
   *
   * @param type declaration for wich we add the magic variables
   */
  private void resolveMagicMembers(TypeDeclaration type) {
    if (type instanceof IPHPDocAwareDeclaration) {
      IPHPDocAwareDeclaration declaration = (IPHPDocAwareDeclaration) type;
      final PHPDocBlock doc = declaration.getPHPDoc();
      if (doc != null) {
        for (PHPDocTag docTag : doc.getTags()) {
          final int tagKind = docTag.getTagKind();
          if (tagKind == PHPDocTag.PROPERTY
              || tagKind == PHPDocTag.PROPERTY_READ
              || tagKind == PHPDocTag.PROPERTY_WRITE) {
            // http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.property.pkg.html
            final String[] split = WHITESPACE_SEPERATOR.split(docTag.getValue().trim());
            if (split.length < 2) {
              break;
            }

            String name = removeParenthesis(split);
            int offset = docTag.sourceStart();
            int length = docTag.sourceStart() + 9;

            Map<String, String> info = new HashMap<String, String>();
            info.put("v", split[0]); // $NON-NLS-1$

            StringBuilder metadata = new StringBuilder();
            if (fCurrentQualifier != null) {
              metadata.append(fCurrentQualifierCounts.get(fCurrentQualifier));
              metadata.append(";"); // $NON-NLS-1$
            }

            modifyDeclaration(
                null,
                new DeclarationInfo(
                    IModelElement.FIELD,
                    Modifiers.AccPublic,
                    offset,
                    length,
                    offset,
                    length,
                    name,
                    metadata.length() == 0 ? null : metadata.toString(),
                    encodeDocInfo(info),
                    fCurrentQualifier,
                    fCurrentParent));

          } else if (tagKind == PHPDocTag.METHOD) {
            // http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.method.pkg.html
            String[] split = WHITESPACE_SEPERATOR.split(docTag.getValue().trim());
            if (split.length < 2) {
              break;
            }
            int methodModifiers = Modifiers.AccPublic;
            if (Constants.STATIC.equals(split[0].trim())) {
              if (split.length < 3) {
                break;
              }
              methodModifiers |= Modifiers.AccStatic;
              split = Arrays.copyOfRange(split, 1, split.length);
            }

            String name = removeParenthesis(split);
            int index = name.indexOf('(');
            if (index > 0) {
              name = name.substring(0, index);
            }
            int offset = docTag.sourceStart();
            int length = docTag.sourceStart() + 6;
            Map<String, String> info = new HashMap<String, String>();
            info.put("r", split[0]); // $NON-NLS-1$

            StringBuilder metadata = new StringBuilder();
            if (fCurrentQualifier != null) {
              metadata.append(fCurrentQualifierCounts.get(fCurrentQualifier));
              metadata.append(";"); // $NON-NLS-1$
            }

            modifyDeclaration(
                null,
                new DeclarationInfo(
                    IModelElement.METHOD,
                    methodModifiers,
                    offset,
                    length,
                    offset,
                    length,
                    name,
                    metadata.length() == 0 ? null : metadata.toString(),
                    encodeDocInfo(info),
                    fCurrentQualifier,
                    fCurrentParent));
          }
        }
      }
    }
  }
  public boolean visit(TypeDeclaration type) throws Exception {
    if (type instanceof NamespaceDeclaration) {
      NamespaceDeclaration namespaceDecl = (NamespaceDeclaration) type;
      fCurrentNamespace = namespaceDecl;
      fLastUseParts.clear();
      if (namespaceDecl.isGlobal()) {
        return visitGeneral(type);
      }
      declarations.push(type);

      int modifiers = type.getModifiers() | Modifiers.AccNameSpace;
      fCurrentQualifier = type.getName();
      Integer count = fCurrentQualifierCounts.get(fCurrentQualifier);
      count = count != null ? count + 1 : 1;
      fCurrentQualifierCounts.put(fCurrentQualifier, count);

      modifiers = markAsDeprecated(modifiers, type);
      StringBuilder metadata = new StringBuilder();
      if (fCurrentQualifier != null) {
        metadata.append(fCurrentQualifierCounts.get(fCurrentQualifier));
        metadata.append(";"); // $NON-NLS-1$
      }
      modifyDeclaration(
          type,
          new DeclarationInfo(
              IModelElement.PACKAGE_DECLARATION,
              modifiers,
              type.sourceStart(),
              type.sourceEnd() - type.sourceStart(),
              type.getNameStart(),
              type.getNameEnd() - type.getNameStart(),
              type.getName(),
              metadata.length() == 0 ? null : metadata.toString(),
              encodeDocInfo(type),
              null,
              null));
    } else {
      Declaration parentDeclaration = null;
      if (!declarations.empty()) {
        parentDeclaration = declarations.peek();
      }
      declarations.push(type);

      if (!(parentDeclaration instanceof NamespaceDeclaration)) {
        type.setModifier(Modifiers.AccGlobal);
      }

      // In case we are entering a nested element
      if (parentDeclaration instanceof MethodDeclaration) {
        if (fCurrentNamespace == null) {
          deferredDeclarations.add(type);
        } else {
          deferredNamespacedDeclarations.add(type);
        }
        return visitGeneral(type);
      }

      int modifiers = type.getModifiers();
      fCurrentParent = type.getName();

      String[] superClasses = processSuperClasses(type);
      StringBuilder metadata = new StringBuilder();
      if (fCurrentQualifier != null) {
        metadata.append(fCurrentQualifierCounts.get(fCurrentQualifier));
        metadata.append(";"); // $NON-NLS-1$
      }
      for (int i = 0; i < superClasses.length; ++i) {
        metadata.append(superClasses[i]);
        if (i < superClasses.length - 1) {
          metadata.append(","); // $NON-NLS-1$
        }
      }
      modifiers = markAsDeprecated(modifiers, type);
      modifyDeclaration(
          type,
          new DeclarationInfo(
              IModelElement.TYPE,
              modifiers,
              type.sourceStart(),
              type.sourceEnd() - type.sourceStart(),
              type.getNameStart(),
              type.getNameEnd() - type.getNameStart(),
              type.getName(),
              metadata.length() == 0 ? null : metadata.toString(),
              encodeDocInfo(type),
              fCurrentQualifier,
              null));
    }

    for (PhpIndexingVisitorExtension visitor : extensions) {
      visitor.visit(type);
    }

    return visitGeneral(type);
  }