1 /* 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.util; 27 28 import java.io.IOException; 29 import java.lang.ref.SoftReference; 30 import java.nio.CharBuffer; 31 import javax.tools.JavaFileObject; 32 33 import com.sun.tools.javac.file.JavacFileManager; 34 import com.sun.tools.javac.tree.EndPosTable; 35 36 import static com.sun.tools.javac.util.LayoutCharacters.*; 37 38 /** 39 * A simple abstraction of a source file, as needed for use in a diagnostic message. 40 * Provides access to the line and position in a line for any given character offset. 41 * 42 * <p><b>This is NOT part of any supported API. 43 * If you write code that depends on this, you do so at your own risk. 44 * This code and its internal interfaces are subject to change or 45 * deletion without notice.</b> 46 */ 47 public class DiagnosticSource { 48 49 /* constant DiagnosticSource to be used when sourcefile is missing */ 50 public static final DiagnosticSource NO_SOURCE = new DiagnosticSource() { 51 @Override 52 protected boolean findLine(int pos) { 53 return false; 54 } 55 }; 56 57 public DiagnosticSource(JavaFileObject fo, AbstractLog log) { 58 this.fileObject = fo; 59 this.log = log; 60 } 61 62 private DiagnosticSource() {} 63 64 /** Return the underlying file object handled by this 65 * DiagnosticSource object. 66 */ 67 public JavaFileObject getFile() { 68 return fileObject; 69 } 70 71 /** Return the one-based line number associated with a given pos 72 * for the current source file. Zero is returned if no line exists 73 * for the given position. 74 */ 75 public int getLineNumber(int pos) { 76 try { 77 if (findLine(pos)) { 78 return line; 79 } 80 return 0; 81 } finally { 82 buf = null; 83 } 84 } 85 86 /** Return the one-based column number associated with a given pos 87 * for the current source file. Zero is returned if no column exists 88 * for the given position. 89 */ 90 public int getColumnNumber(int pos, boolean expandTabs) { 91 try { 92 if (findLine(pos)) { 93 int column = 0; 94 for (int bp = lineStart; bp < pos; bp++) { 95 if (bp >= bufLen) { 96 return 0; 97 } 98 if (buf[bp] == '\t' && expandTabs) { 99 column = (column / TabInc * TabInc) + TabInc; 100 } else { 101 column++; 102 } 103 } 104 return column + 1; // positions are one-based 105 } 106 return 0; 107 } finally { 108 buf = null; 109 } 110 } 111 112 /** Return the content of the line containing a given pos. 113 */ 114 public String getLine(int pos) { 115 try { 116 if (!findLine(pos)) 117 return null; 118 119 int lineEnd = lineStart; 120 while (lineEnd < bufLen && buf[lineEnd] != CR && buf[lineEnd] != LF) 121 lineEnd++; 122 if (lineEnd - lineStart == 0) 123 return null; 124 return new String(buf, lineStart, lineEnd - lineStart); 125 } finally { 126 buf = null; 127 } 128 } 129 130 public EndPosTable getEndPosTable() { 131 return endPosTable; 132 } 133 134 public void setEndPosTable(EndPosTable t) { 135 if (endPosTable != null && endPosTable != t) 136 throw new IllegalStateException("endPosTable already set"); 137 endPosTable = t; 138 } 139 140 /** Find the line in the buffer that contains the current position 141 * @param pos Character offset into the buffer 142 */ 143 protected boolean findLine(int pos) { 144 if (pos == Position.NOPOS) 145 return false; 146 147 try { 148 // try and recover buffer from soft reference cache 149 if (buf == null && refBuf != null) 150 buf = refBuf.get(); 151 152 if (buf == null) { 153 buf = initBuf(fileObject); 154 lineStart = 0; 155 line = 1; 156 } else if (lineStart > pos) { // messages don't come in order 157 lineStart = 0; 158 line = 1; 159 } 160 161 int bp = lineStart; 162 while (bp < bufLen && bp < pos) { 163 switch (buf[bp++]) { 164 case CR: 165 if (bp < bufLen && buf[bp] == LF) bp++; 166 line++; 167 lineStart = bp; 168 break; 169 case LF: 170 line++; 171 lineStart = bp; 172 break; 173 } 174 } 175 return bp <= bufLen; 176 } catch (IOException e) { 177 log.directError("source.unavailable"); 178 buf = new char[0]; 179 return false; 180 } 181 } 182 183 protected char[] initBuf(JavaFileObject fileObject) throws IOException { 184 char[] buf; 185 CharSequence cs = fileObject.getCharContent(true); 186 if (cs instanceof CharBuffer) { 187 CharBuffer cb = (CharBuffer) cs; 188 buf = JavacFileManager.toArray(cb); 189 bufLen = cb.limit(); 190 } else { 191 buf = cs.toString().toCharArray(); 192 bufLen = buf.length; 193 } 194 refBuf = new SoftReference<>(buf); 195 return buf; 196 } 197 198 /** The underlying file object. */ 199 protected JavaFileObject fileObject; 200 201 protected EndPosTable endPosTable; 202 203 /** A soft reference to the content of the file object. */ 204 protected SoftReference<char[]> refBuf; 205 206 /** A temporary hard reference to the content of the file object. */ 207 protected char[] buf; 208 209 /** The length of the content. */ 210 protected int bufLen; 211 212 /** The start of a line found by findLine. */ 213 protected int lineStart; 214 215 /** The line number of a line found by findLine. */ 216 protected int line; 217 218 /** A log for reporting errors, such as errors accessing the content. */ 219 protected AbstractLog log; 220 }