1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.googlejavaformat; 16 17 import com.google.common.collect.DiscreteDomain; 18 import com.google.common.collect.ImmutableList; 19 import com.google.common.collect.Range; 20 import java.util.ArrayList; 21 import java.util.HashMap; 22 import java.util.List; 23 import java.util.Map; 24 25 /** This interface defines methods common to an {@link Input} or an {@link Output}. */ 26 public abstract class InputOutput { 27 private ImmutableList<String> lines = ImmutableList.of(); 28 29 protected static final Range<Integer> EMPTY_RANGE = Range.closedOpen(-1, -1); 30 private static final DiscreteDomain<Integer> INTEGERS = DiscreteDomain.integers(); 31 32 /** Set the lines. */ setLines(ImmutableList<String> lines)33 protected final void setLines(ImmutableList<String> lines) { 34 this.lines = lines; 35 } 36 37 /** 38 * Get the line count. 39 * 40 * @return the line count 41 */ getLineCount()42 public final int getLineCount() { 43 return lines.size(); 44 } 45 46 /** 47 * Get a line. 48 * 49 * @param lineI the line number 50 * @return the line 51 */ getLine(int lineI)52 public final String getLine(int lineI) { 53 return lines.get(lineI); 54 } 55 56 /** The {@link Range}s of the tokens or comments lying on each line, in any part. */ 57 protected final List<Range<Integer>> ranges = new ArrayList<>(); 58 addToRanges(List<Range<Integer>> ranges, int i, int k)59 private static void addToRanges(List<Range<Integer>> ranges, int i, int k) { 60 while (ranges.size() <= i) { 61 ranges.add(EMPTY_RANGE); 62 } 63 Range<Integer> oldValue = ranges.get(i); 64 ranges.set(i, Range.closedOpen(oldValue.isEmpty() ? k : oldValue.lowerEndpoint(), k + 1)); 65 } 66 computeRanges(List<? extends Input.Tok> toks)67 protected final void computeRanges(List<? extends Input.Tok> toks) { 68 int lineI = 0; 69 for (Input.Tok tok : toks) { 70 String txt = tok.getOriginalText(); 71 int lineI0 = lineI; 72 lineI += Newlines.count(txt); 73 int k = tok.getIndex(); 74 if (k >= 0) { 75 for (int i = lineI0; i <= lineI; i++) { 76 addToRanges(ranges, i, k); 77 } 78 } 79 } 80 } 81 82 /** 83 * Given an {@code InputOutput}, compute the map from tok indices to line ranges. 84 * 85 * @param put the {@code InputOutput} 86 * @return the map from {@code com.google.googlejavaformat.java.JavaInput.Tok} indices to line 87 * ranges in this {@code put} 88 */ makeKToIJ(InputOutput put)89 public static Map<Integer, Range<Integer>> makeKToIJ(InputOutput put) { 90 Map<Integer, Range<Integer>> map = new HashMap<>(); 91 int ijN = put.getLineCount(); 92 for (int ij = 0; ij <= ijN; ij++) { 93 Range<Integer> range = put.getRanges(ij).canonical(INTEGERS); 94 for (int k = range.lowerEndpoint(); k < range.upperEndpoint(); k++) { 95 if (map.containsKey(k)) { 96 map.put(k, Range.closedOpen(map.get(k).lowerEndpoint(), ij + 1)); 97 } else { 98 map.put(k, Range.closedOpen(ij, ij + 1)); 99 } 100 } 101 } 102 return map; 103 } 104 105 /** 106 * Get the {@link Range} of {@link Input.Tok}s lying in any part on a line. 107 * 108 * @param lineI the line number 109 * @return the {@link Range} of {@link Input.Tok}s on the specified line 110 */ getRanges(int lineI)111 public final Range<Integer> getRanges(int lineI) { 112 return 0 <= lineI && lineI < ranges.size() ? ranges.get(lineI) : EMPTY_RANGE; 113 } 114 115 @Override toString()116 public String toString() { 117 return "InputOutput{" + "lines=" + lines + ", ranges=" + ranges + '}'; 118 } 119 } 120