class LongStringsAndTextBlockScanner extends TreePathScanner<Void, Void> {

      private final List<TreePath> longStringLiterals;
      private final List<Tree> textBlocks;

      LongStringsAndTextBlockScanner(List<TreePath> longStringLiterals, List<Tree> textBlocks) {
        this.longStringLiterals = longStringLiterals;
        this.textBlocks = textBlocks;
      }

      @Override
      public Void visitLiteral(LiteralTree literalTree, Void aVoid) {
        if (literalTree.getKind() != Kind.STRING_LITERAL) {
          return null;
        }
        int pos = getStartPosition(literalTree);
        if (input.substring(pos, min(input.length(), pos + 3)).equals("\"\"\"")) {
          textBlocks.add(literalTree);
          return null;
        }
        Tree parent = getCurrentPath().getParentPath().getLeaf();
        if (parent instanceof MemberSelectTree
            && ((MemberSelectTree) parent).getExpression().equals(literalTree)) {
          return null;
        }
        int endPosition = getEndPosition(unit, literalTree);
        int lineEnd = endPosition;
        while (Newlines.hasNewlineAt(input, lineEnd) == -1) {
          lineEnd++;
        }
        if (lineMap.getColumnNumber(lineEnd) - 1 <= columnLimit) {
          return null;
        }
        longStringLiterals.add(getCurrentPath());
        return null;
      }
    }

    private void indentTextBlocks(
        TreeRangeMap<Integer, String> replacements, List<Tree> textBlocks) {
      for (Tree tree : textBlocks) {
        int startPosition = getStartPosition(tree);
        int endPosition = getEndPosition(unit, tree);
        String text = input.substring(startPosition, endPosition);

        // Find the source code of the text block with incidental whitespace removed.
        // The first line of the text block is always """, and it does not affect incidental
        // whitespace.
        ImmutableList<String> initialLines = text.lines().collect(toImmutableList());
        String stripped = stripIndent(initialLines.stream().skip(1).collect(joining(separator)));
        ImmutableList<String> lines = stripped.lines().collect(toImmutableList());
        int deindent =
            initialLines.get(1).stripTrailing().length() - lines.get(0).stripTrailing().length();

        int startColumn = lineMap.getColumnNumber(startPosition);
        String prefix =
            (deindent == 0 || lines.stream().anyMatch(x -> x.length() + startColumn > columnLimit))
                ? ""
                : " ".repeat(startColumn - 1);

        StringBuilder output = new StringBuilder("\"\"\"");
        for (int i = 0; i < lines.size(); i++) {
          String line = lines.get(i);
          String trimmed = line.stripLeading().stripTrailing();
          output.append(separator);
          if (!trimmed.isEmpty()) {
            // Don't add incidental leading whitespace to empty lines
            output.append(prefix);
          }
          if (i == lines.size() - 1 && trimmed.equals("\"\"\"")) {
            // If the trailing line is just """, indenting is more than the prefix of incidental
            // whitespace has no effect, and results in a javac text-blocks warning that 'trailing
            // white space will be removed'.
            output.append("\"\"\"");
          } else {
            output.append(line);
          }
        }
        replacements.put(Range.closedOpen(startPosition, endPosition), output.toString());
      }
    }

    private void wrapLongStrings(
        TreeRangeMap<Integer, String> replacements, List<TreePath> longStringLiterals) {<FILL_FUNCTION_BODY>

      for (TreePath path : longStringLiterals) {
        // Find the outermost contiguous enclosing concatenation expression
        TreePath enclosing = path;
        while (enclosing.getParentPath().getLeaf().getKind() == Kind.PLUS) {
          enclosing = enclosing.getParentPath();
        }
        // Is the literal being wrapped the first in a chain of concatenation expressions?
        // i.e. `ONE + TWO + THREE`
        // We need this information to handle continuation indents.
        AtomicBoolean first = new AtomicBoolean(false);
        // Finds the set of string literals in the concat expression that includes the one that
        // needs
        // to be wrapped.
        List<Tree> flat = flatten(input, unit, path, enclosing, first);
        // Zero-indexed start column
        int startColumn = lineMap.getColumnNumber(getStartPosition(flat.get(0))) - 1;

        // Handling leaving trailing non-string tokens at the end of the literal,
        // e.g. the trailing `);` in `foo("...");`.
        int end = getEndPosition(unit, getLast(flat));
        int lineEnd = end;
        while (Newlines.hasNewlineAt(input, lineEnd) == -1) {
          lineEnd++;
        }
        int trailing = lineEnd - end;

        // Get the original source text of the string literals, excluding `"` and `+`.
        ImmutableList<String> components = stringComponents(input, unit, flat);
        replacements.put(
            Range.closedOpen(getStartPosition(flat.get(0)), getEndPosition(unit, getLast(flat))),
            reflow(separator, columnLimit, startColumn, trailing, components, first.get()));
      }
    
<no_super_class>