public StringBuffer printBody(int indent, StringBuffer output) {

    if (isAbstract() || (this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0)
      return output.append(';');

    output.append(" {"); // $NON-NLS-1$
    if (this.statements != null) {
      for (int i = 0; i < this.statements.length; i++) {
        output.append('\n');
        this.statements[i].printStatement(indent, output);
      }
    }
    output.append('\n');
    printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
    return output;
  }
  public StringBuffer print(int tab, StringBuffer output) {

    if (this.javadoc != null) {
      this.javadoc.print(tab, output);
    }
    printIndent(tab, output);
    printModifiers(this.modifiers, output);
    if (this.annotations != null) {
      printAnnotations(this.annotations, output);
      output.append(' ');
    }

    TypeParameter[] typeParams = typeParameters();
    if (typeParams != null) {
      output.append('<');
      int max = typeParams.length - 1;
      for (int j = 0; j < max; j++) {
        typeParams[j].print(0, output);
        output.append(", "); // $NON-NLS-1$
      }
      typeParams[max].print(0, output);
      output.append('>');
    }

    printReturnType(0, output).append(this.selector).append('(');
    if (this.receiver != null) {
      this.receiver.print(0, output);
    }
    if (this.arguments != null) {
      for (int i = 0; i < this.arguments.length; i++) {
        if (i > 0 || this.receiver != null) output.append(", "); // $NON-NLS-1$
        this.arguments[i].print(0, output);
      }
    }
    output.append(')');
    if (this.thrownExceptions != null) {
      output.append(" throws "); // $NON-NLS-1$
      for (int i = 0; i < this.thrownExceptions.length; i++) {
        if (i > 0) output.append(", "); // $NON-NLS-1$
        this.thrownExceptions[i].print(0, output);
      }
    }
    printBody(tab + 1, output);
    return output;
  }
 /*
  * @see org.eclipse.jdt.internal.ui.text.SubstitutionTextReader#computeSubstitution(int)
  */
 protected String computeSubstitution(int c) throws IOException {
   StringBuffer buf = new StringBuffer();
   // Accumulate *s into the buffer until we see something other than *.
   while (c == '*') {
     this.bits &= ~BEGIN_LINE;
     c = nextChar();
     buf.append('*');
   }
   if (c == -1)
     // Snippet must have ended with *s.  Just return them.
     return buf.toString();
   if (c == '/' && buf.length() > 0) {
     /*
      * Translate a * that precedes a / to &#42; so it isn't
      * misinterpreted as the end of the Javadoc comment that contains
      * the code we are formatting.
      * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=109636
      */
     buf.setLength(buf.length() - 1);
     buf.append("&#42;/"); // $NON-NLS-1$
   } else if (c == '@' && (this.bits & BEGIN_LINE) != 0) {
     /*
      * When @ is first on a line, translate it to &#064; so it isn't
      * misinterpreted as a Javadoc tag.
      * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=197169
      */
     buf.append("&#064;"); // $NON-NLS-1$
   } else {
     /*
      * Ordinary processing.  If the character needs an entity in HTML,
      * add the entity, otherwise add the character.
      */
     String entity = (String) fgEntityLookup.get(String.valueOf((char) c));
     if (entity != null) buf.append(entity);
     else buf.append((char) c);
   }
   // Update bits for the benefit of the next character.
   if (c == '\n' || c == '\r') {
     this.bits |= BEGIN_LINE;
   } else if (!ScannerHelper.isWhitespace((char) c)) {
     this.bits &= ~BEGIN_LINE;
   }
   return buf.toString();
 }