protected int parseTag(int lineno, String tagPrefix) {
    final Substring lineWithPrefix = getLine(lineno).trimLeft();
    if (lineWithPrefix.startsWith(tagPrefix)) {
      final Substring line = lineWithPrefix.substring(tagPrefix.length());
      final Matcher strictTagMatcher = RE_STRICT_TAG_LINE.matcher(line);
      final Matcher looseTagMatcher = RE_LOOSE_TAG_LINE.matcher(line);
      Matcher tagMatcher = null;
      if (strictTagMatcher.matches()) {
        tagMatcher = strictTagMatcher;
      }
      else if (looseTagMatcher.matches()) {
        tagMatcher = looseTagMatcher;
      }
      if (tagMatcher != null) {
        final Substring tagName = line.getMatcherGroup(tagMatcher, 1);
        Substring argName = line.getMatcherGroup(tagMatcher, 2).trim();
        final TextRange firstArgLineRange = line.getMatcherGroup(tagMatcher, 3).trim().getTextRange();
        final int linesCount = getLineCount();
        final int argStart = firstArgLineRange.getStartOffset();
        int argEnd = firstArgLineRange.getEndOffset();
        while (lineno + 1 < linesCount) {
          final Substring nextLine = getLine(lineno + 1).trim();
          if (nextLine.isEmpty() || nextLine.startsWith(tagPrefix)) {
            break;
          }
          argEnd = nextLine.getTextRange().getEndOffset();
          lineno++;
        }
        final Substring argValue = new Substring(argName.getSuperString(), argStart, argEnd);
        final String tagNameString = tagName.toString();
        if (argName.isEmpty()) {
          mySimpleTagValues.put(tagNameString, argValue);
        }
        else {
          if ("param".equals(tagNameString) || "parameter".equals(tagNameString) ||
              "arg".equals(tagNameString) || "argument".equals(tagNameString)) {
            // Process declarations that combine type and description, e.g. ":param int foo: bar"
            // as if there were both ":param foo: bar" and ":type foo: int"
            final Matcher argTypeMatcher = RE_ARG_TYPE.matcher(argName);
            if (argTypeMatcher.matches()) {
              final Substring argType = argName.getMatcherGroup(argTypeMatcher, 1).trim();
              argName = argName.getMatcherGroup(argTypeMatcher, 2);
              getTagValuesMap(TYPE).put(argName, argType);
            }
          }
          getTagValuesMap(tagNameString).put(argName, argValue);
        }
      }
    }
    return lineno;
  }
protected int parseTag(int lineno, String tagPrefix)