com.google.errorprone.apply.SourceFile.java Source code

Java tutorial

Introduction

Here is the source code for com.google.errorprone.apply.SourceFile.java

Source

/*
 * Copyright 2011 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.errorprone.apply;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.io.CharSource;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.tools.JavaFileObject;

/**
 * Representation of a mutable Java source file.
 * 
 * This class is not thread-safe.
 * 
 * @author sjnickerson@google.com (Simon Nickerson)
 * @author alexeagle@google.com (Alex Eagle)
 */
public class SourceFile {

    private final String path;
    private final StringBuilder sourceBuilder;

    public static SourceFile create(JavaFileObject fileObject) throws IOException {
        return new SourceFile(fileObject.toUri().getPath(), fileObject.getCharContent(false));
    }

    public SourceFile(String path, CharSequence source) {
        this.path = path;
        sourceBuilder = new StringBuilder(source);
    }

    /**
     * Returns the path for this source file
     */
    public String getPath() {
        return path;
    }

    /**
     * Returns a copy of code as a list of lines.
     */
    public List<String> getLines() {
        try {
            return CharSource.wrap(sourceBuilder).readLines();
        } catch (IOException e) {
            throw new AssertionError("IOException not possible, as the string is in-memory");
        }
    }

    /**
     * Returns a copy of the code as a string.
     */
    public String getSourceText() {
        return sourceBuilder.toString();
    }

    public CharSequence getAsSequence() {
        return CharBuffer.wrap(sourceBuilder).asReadOnlyBuffer();
    }

    /**
     * Clears the current source test for this SourceFile and resets it to
     * the passed-in value.
     */
    public void setSourceText(CharSequence source) {
        sourceBuilder.setLength(0); // clear StringBuilder
        sourceBuilder.append(source);
    }

    /**
     * Returns a fragment of the source code as a string.
     * 
     * <p>This method uses the same conventions as {@link String#substring(int, int)} for its start
     * and end parameters.
     */
    public String getFragmentByChars(int startPosition, int endPosition) {
        return sourceBuilder.substring(startPosition, endPosition);
    }

    /**
     * Returns a fragment of the source code between the two stated line numbers. The parameters
     * represent <b>inclusive</b> line numbers.
     * 
     * <p>The returned fragment will end in a newline.
     */
    public String getFragmentByLines(int startLine, int endLine) {
        Preconditions.checkArgument(startLine <= endLine);
        return Joiner.on("\n").join(getLines(startLine, endLine)) + "\n";
    }

    private List<String> getLines(int startLine, int endLine) {
        LineNumberReader reader = new LineNumberReader(new StringReader(sourceBuilder.toString()));
        List<String> lines = new ArrayList<>(endLine - startLine + 1);
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                if (reader.getLineNumber() >= startLine) {
                    lines.add(line);
                }
                if (reader.getLineNumber() >= endLine) {
                    break;
                }
            }
            return lines;
        } catch (IOException e) {
            throw new AssertionError("Wrapped StringReader should not produce I/O exceptions");
        }
    }

    /**
     * Replace the source code with the new lines of code.
     */
    public void replaceLines(List<String> lines) {
        sourceBuilder.replace(0, sourceBuilder.length(), Joiner.on("\n").join(lines) + "\n");
    }

    /**
     * Replace the source code between the start and end lines with some new lines of code.
     */
    public void replaceLines(int startLine, int endLine, List<String> replacementLines) {
        Preconditions.checkArgument(startLine <= endLine);
        List<String> originalLines = getLines();
        List<String> newLines = new ArrayList<>();
        for (int i = 0; i < originalLines.size(); i++) {
            int lineNum = i + 1;
            if (lineNum == startLine) {
                newLines.addAll(replacementLines);
            } else if (lineNum > startLine && lineNum <= endLine) {
                // Skip
            } else {
                newLines.add(originalLines.get(i));
            }
        }
        replaceLines(newLines);
    }

    /**
     * Replace the source code between the start and end character positions with a new string.
     * 
     * <p>This method uses the same conventions as {@link String#substring(int, int)} for its start
     * and end parameters.
     */
    public void replaceChars(int startPosition, int endPosition, String replacement) {
        try {
            sourceBuilder.replace(startPosition, endPosition, replacement);
        } catch (StringIndexOutOfBoundsException e) {
            throw new IndexOutOfBoundsException(String.format(
                    "Replacement cannot be made. Source file %s has length %d, requested start "
                            + "position %d, requested end position %d, replacement %s",
                    path, sourceBuilder.length(), startPosition, endPosition, replacement));
        }
    }
}