/**
   * 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(PHPFieldDeclaration declaration) throws Exception {
    // This is variable declaration:
    ISourceElementRequestor.FieldInfo info = new ISourceElementRequestor.FieldInfo();
    info.modifiers = declaration.getModifiers();
    info.name = declaration.getName();
    SimpleReference var = declaration.getRef();
    info.nameSourceEnd = var.sourceEnd() - 1;
    info.nameSourceStart = var.sourceStart();
    info.declarationStart = declaration.getDeclarationStart();
    info.modifiers = markAsDeprecated(info.modifiers, declaration);
    PHPDocBlock doc = declaration.getPHPDoc();
    if (doc != null) {
      for (PHPDocTag tag : doc.getTags(PHPDocTag.VAR)) {
        // do it like for
        // PHPDocumentationContentAccess#handleBlockTags(List tags):
        // variable name can be optional, but if present keep only
        // the good ones
        if (tag.getVariableReference() != null
            && !tag.getVariableReference().getName().equals(declaration.getName())) {
          continue;
        }

        if (tag.getTypeReferences().size() > 0) {
          info.type = PHPModelUtils.appendTypeReferenceNames(tag.getTypeReferences());
          break;
        }
      }
    }
    fInfoStack.push(info);
    fRequestor.enterField(info);
    return true;
  }
 private String processReturnType(MethodDeclaration methodDeclaration) {
   PHPMethodDeclaration phpMethodDeclaration = (PHPMethodDeclaration) methodDeclaration;
   PHPDocBlock docBlock = phpMethodDeclaration.getPHPDoc();
   String type = VOID_RETURN_TYPE;
   if (phpMethodDeclaration.getReturnType() != null) {
     return phpMethodDeclaration.getReturnType().getName();
   } else if (docBlock != null) {
     for (PHPDocTag tag : docBlock.getTags(PHPDocTag.RETURN)) {
       if (tag.getTypeReferences().size() > 0) {
         return PHPModelUtils.appendTypeReferenceNames(tag.getTypeReferences());
       }
     }
   }
   return type;
 }
  /**
   * Update modifiers for "deprecated"
   *
   * @param modifiers
   * @param phpDoc
   * @return
   */
  private int markAsDeprecated(int modifiers, PHPDocBlock phpDoc) {
    if (phpDoc != null && phpDoc.getTags(PHPDocTag.DEPRECATED).length > 0) {
      return modifiers | IPHPModifiers.AccDeprecated;
    }

    return modifiers;
  }
 private String getParamType(PHPDocBlock docBlock, String paramName, String defaultType) {
   String result = defaultType;
   if (docBlock != null) {
     for (PHPDocTag tag : docBlock.getTags(PHPDocTag.PARAM)) {
       if (tag.isValidParamTag() && tag.getVariableReference().getName().equals(paramName)) {
         String typeNames = tag.getSingleTypeReference().getName();
         result = typeNames.replace(Constants.TYPE_SEPERATOR_CHAR, Constants.DOT);
         break;
       }
     }
   }
   return result;
 }
 private String[] processParameterTypes(MethodDeclaration methodDeclaration) {
   List<?> args = methodDeclaration.getArguments();
   PHPDocBlock docBlock = ((PHPMethodDeclaration) methodDeclaration).getPHPDoc();
   String[] parameterType = new String[args.size()];
   for (int a = 0; a < args.size(); a++) {
     Argument arg = (Argument) args.get(a);
     if (arg instanceof FormalParameter) {
       SimpleReference type = ((FormalParameter) arg).getParameterType();
       if (type != null) {
         parameterType[a] = type.getName();
       } else if (docBlock != null) {
         for (PHPDocTag tag : docBlock.getTags(PHPDocTag.PARAM)) {
           if (tag.isValidParamTag()
               && tag.getVariableReference().getName().equals(arg.getName())) {
             parameterType[a] = tag.getSingleTypeReference().getName();
             break;
           }
         }
       }
     }
   }
   return parameterType;
 }
  /**
   * 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));
          }
        }
      }
    }
  }
  /**
   * 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) {
        Pattern WHITESPACE_SEPERATOR = MagicMemberUtil.WHITESPACE_SEPERATOR;
        final PHPDocTag[] tags = doc.getTags();
        for (PHPDocTag docTag : tags) {
          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) {
              continue;
            }
            ISourceElementRequestor.FieldInfo info = new ISourceElementRequestor.FieldInfo();
            info.modifiers = Modifiers.AccPublic | IPHPModifiers.AccMagicProperty;
            info.name = split[1];
            info.type = split[0];

            SimpleReference var =
                new SimpleReference(
                    docTag.sourceStart(), docTag.sourceStart() + 9, removeParenthesis(split));
            info.nameSourceStart = var.sourceStart();
            info.nameSourceEnd = var.sourceEnd();
            info.declarationStart = info.nameSourceStart;

            fRequestor.enterField(info);
            fRequestor.exitField(info.nameSourceEnd);

          } else if (tagKind == PHPDocTag.METHOD) {
            // http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.method.pkg.html

            // workaround for lack of method return type
            int methodModifiers = Modifiers.AccPublic;
            String docTagValue = docTag.getValue().trim();
            int index = docTagValue.indexOf('(');
            if (index != -1) {
              String[] split = WHITESPACE_SEPERATOR.split(docTagValue.substring(0, index).trim());
              if (split.length == 1) {
                docTagValue =
                    new StringBuilder(VOID_RETURN_TYPE)
                        .append(Constants.SPACE)
                        .append(docTagValue)
                        .toString();
              } else if (split.length == 2 && Constants.STATIC.equals(split[0])) {
                StringBuilder sb = new StringBuilder(Constants.STATIC);
                sb.append(Constants.SPACE).append(VOID_RETURN_TYPE);
                sb.append(docTagValue.substring(6));
                docTagValue = sb.toString();
              }
            }
            String[] split = WHITESPACE_SEPERATOR.split(docTagValue);
            if (split.length < 2) {
              continue;
            }
            if (Constants.STATIC.equals(split[0])) {
              methodModifiers |= Modifiers.AccStatic;
              split = Arrays.copyOfRange(split, 1, split.length);
              docTagValue = docTagValue.substring(7).trim();
              if (split.length < 2) {
                continue;
              }
            }

            ISourceElementRequestor.MethodInfo mi = new ISourceElementRequestor.MethodInfo();
            mi.parameterNames = null;
            mi.name = removeParenthesis(split);
            SimpleReference var =
                new SimpleReference(
                    docTag.sourceStart(), docTag.sourceStart() + 6, removeParenthesis(split));
            mi.modifiers = methodModifiers;
            mi.nameSourceStart = var.sourceStart();
            mi.nameSourceEnd = var.sourceEnd();
            mi.declarationStart = mi.nameSourceStart;
            mi.isConstructor = false;
            mi.returnType = split[0];

            MagicMethod magicMethod;
            if (mi.name != null && mi.name.indexOf('(') > 0) {
              magicMethod = MagicMemberUtil.getMagicMethod2(docTagValue);
              mi.name = magicMethod.name;
            } else {
              magicMethod = MagicMemberUtil.getMagicMethod(docTagValue);
            }
            if (magicMethod != null) {
              mi.parameterNames = magicMethod.parameterNames;
              mi.parameterTypes = magicMethod.parameterTypes;
              mi.parameterInitializers = magicMethod.parameterInitializers;
            }

            this.fRequestor.enterMethod(mi);
            this.fRequestor.exitMethod(mi.nameSourceEnd);
          }
        }
      }
    }
  }