Location.java revision 731b74f7f44e67312a1fc4161c4e0aae221b2417
13516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/* 23516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Copyright (C) 2015 The Android Open Source Project 33516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 43516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 53516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * you may not use this file except in compliance with the License. 63516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * You may obtain a copy of the License at 73516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 83516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 93516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Unless required by applicable law or agreed to in writing, software 113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * See the License for the specific language governing permissions and 143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * limitations under the License. 153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 173516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipackage android.databinding.tool.store; 187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport org.antlr.v4.runtime.ParserRuleContext; 193516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.antlr.v4.runtime.Token; 203516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.apache.commons.lang3.StringUtils; 213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 223516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport javax.xml.bind.annotation.XmlAccessType; 233516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport javax.xml.bind.annotation.XmlAccessorType; 243516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport javax.xml.bind.annotation.XmlAttribute; 253516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport javax.xml.bind.annotation.XmlElement; 263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/** 283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Identifies the range of a code block inside a file or a string. 293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Note that, unlike antlr4 tokens, the line positions start from 0 (to be compatible with Studio). 303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * <p> 313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Both start and end line/column indices are inclusive. 323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski@XmlAccessorType(XmlAccessType.NONE) 343516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipublic class Location { 353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public static final int NaN = -1; 363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @XmlAttribute(name = "startLine") 373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public int startLine; 383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @XmlAttribute(name = "startOffset") 393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public int startOffset; 403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @XmlAttribute(name = "endLine") 413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public int endLine; 423516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @XmlAttribute(name = "endOffset") 433516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public int endOffset; 443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @XmlElement(name = "parentLocation") 453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location parentLocation; 463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski // for XML unmarshalling 483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location() { 493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startOffset = endOffset = startLine = endLine = NaN; 503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 513516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location(Location other) { 533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startOffset = other.startOffset; 543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski endOffset = other.endOffset; 553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startLine = other.startLine; 563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski endLine = other.endLine; 573516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location(Token start, Token end) { 603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (start == null) { 613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startLine = startOffset = NaN; 623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } else { 633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startLine = start.getLine() - 1; //token lines start from 1 643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski startOffset = start.getCharPositionInLine(); 653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (end == null) { 687f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski endLine = endOffset = NaN; 697f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } else { 707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski endLine = end.getLine() - 1; // token lines start from 1 71c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski String endText = end.getText(); 72c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski int lastLineStart = endText.lastIndexOf(System.lineSeparator()); 73978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski String lastLine = lastLineStart < 0 ? endText : endText.substring(lastLineStart + 1); 74c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski endOffset = end.getCharPositionInLine() + lastLine.length() - 1;//end is inclusive 75c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski } 76c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski } 77c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski 78c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski public Location(ParserRuleContext context) { 79c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski this(context == null ? null : context.getStart(), 80978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski context == null ? null : context.getStop()); 81978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski } 823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location(int startLine, int startOffset, int endLine, int endOffset) { 849d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski this.startOffset = startOffset; 859d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski this.startLine = startLine; 869d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski this.endLine = endLine; 879d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski this.endOffset = endOffset; 889d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 899d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski 903516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @Override 913516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public String toString() { 923516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return "Location{" + 933516800b611a79339a3c188332d13a26e9086b09Adam Lesinski "startLine=" + startLine + 943516800b611a79339a3c188332d13a26e9086b09Adam Lesinski ", startOffset=" + startOffset + 953516800b611a79339a3c188332d13a26e9086b09Adam Lesinski ", endLine=" + endLine + 963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski ", endOffset=" + endOffset + 973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski ", parentLocation=" + parentLocation + 983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski '}'; 993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public void setParentLocation(Location parentLocation) { 1027f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski this.parentLocation = parentLocation; 1037f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1047f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1057f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski @Override 1067f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public boolean equals(Object o) { 1077f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (this == o) { 1089d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski return true; 1099d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1109d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (o == null || getClass() != o.getClass()) { 1119d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski return false; 1129d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1139d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski 1149d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski Location location = (Location) o; 1159d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski 1169d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (endLine != location.endLine) { 1179d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski return false; 1189d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1199d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (endOffset != location.endOffset) { 1203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (startLine != location.startLine) { 123cc562a811da508b275254f275d6e0c1758a47d07Adam Lesinski return false; 124cc562a811da508b275254f275d6e0c1758a47d07Adam Lesinski } 125cc562a811da508b275254f275d6e0c1758a47d07Adam Lesinski if (startOffset != location.startOffset) { 1263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (parentLocation != null ? !parentLocation.equals(location.parentLocation) 1293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski : location.parentLocation != null) { 1303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return true; 1343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski @Override 1373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public int hashCode() { 1383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski int result = startLine; 1393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski result = 31 * result + startOffset; 1407f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski result = 31 * result + endLine; 1417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski result = 31 * result + endOffset; 1427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return result; 1437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public boolean isValid() { 1467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return startLine != NaN && endLine != NaN && startOffset != NaN && endOffset != NaN; 1477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public boolean contains(Location other) { 1503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (startLine > other.startLine) { 1513516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (startLine == other.startLine && startOffset > other.startOffset) { 1543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (endLine < other.endLine) { 1573516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (endLine == other.endLine && endOffset < other.endOffset) { 1603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 1613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return true; 1639d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private Location getValidParentAbsoluteLocation() { 1663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (parentLocation == null) { 1673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return null; 1683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (parentLocation.isValid()) { 1703516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return parentLocation.toAbsoluteLocation(); 1713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return parentLocation.getValidParentAbsoluteLocation(); 1739d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public Location toAbsoluteLocation() { 1763516800b611a79339a3c188332d13a26e9086b09Adam Lesinski Location absoluteParent = getValidParentAbsoluteLocation(); 1773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (absoluteParent == null) { 1783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return this; 1793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski Location copy = new Location(this); 1813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski boolean sameLine = copy.startLine == copy.endLine; 1823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (copy.startLine == 0) { 1833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski copy.startOffset += absoluteParent.startOffset; 1843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (sameLine) { 1863516800b611a79339a3c188332d13a26e9086b09Adam Lesinski copy.endOffset += absoluteParent.startOffset; 1873516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1883516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1893516800b611a79339a3c188332d13a26e9086b09Adam Lesinski copy.startLine += absoluteParent.startLine; 1903516800b611a79339a3c188332d13a26e9086b09Adam Lesinski copy.endLine += absoluteParent.startLine; 1913516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return copy; 1923516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1933516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1943516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public String toUserReadableString() { 1953516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return startLine + ":" + startOffset + " - " + endLine + ":" + endOffset; 1963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1979d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski 1989d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski public static Location fromUserReadableString(String str) { 1993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski int glue = str.indexOf('-'); 2003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (glue == -1) { 2013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return new Location(); 2023516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2033516800b611a79339a3c188332d13a26e9086b09Adam Lesinski String start = str.substring(0, glue); 2043516800b611a79339a3c188332d13a26e9086b09Adam Lesinski String end = str.substring(glue + 1); 2053516800b611a79339a3c188332d13a26e9086b09Adam Lesinski int[] point = new int[]{-1, -1}; 2063516800b611a79339a3c188332d13a26e9086b09Adam Lesinski Location location = new Location(); 2073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski parsePoint(start, point); 2083516800b611a79339a3c188332d13a26e9086b09Adam Lesinski location.startLine = point[0]; 2093516800b611a79339a3c188332d13a26e9086b09Adam Lesinski location.startOffset = point[1]; 2103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski point[0] = point[1] = -1; 2113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski parsePoint(end, point); 2123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski location.endLine = point[0]; 2133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski location.endOffset = point[1]; 2143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return location; 2153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 2173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private static boolean parsePoint(String content, int[] into) { 2183516800b611a79339a3c188332d13a26e9086b09Adam Lesinski int index = content.indexOf(':'); 2193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (index == -1) { 2203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return false; 2213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski into[0] = Integer.parseInt(content.substring(0, index).trim()); 2233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski into[1] = Integer.parseInt(content.substring(index + 1).trim()); 2243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return true; 2253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2267f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski} 2279d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski