Path: blob/master/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java
58461 views
/*1* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.javap;2627import java.io.BufferedReader;28import java.io.IOException;29import java.io.StringReader;30import java.util.ArrayList;31import java.util.List;32import java.util.Set;33import java.util.SortedMap;34import java.util.SortedSet;35import java.util.TreeMap;36import java.util.TreeSet;37import javax.tools.JavaFileManager;38import javax.tools.JavaFileManager.Location;39import javax.tools.JavaFileObject;40import javax.tools.StandardLocation;4142import com.sun.tools.classfile.Attribute;43import com.sun.tools.classfile.ClassFile;44import com.sun.tools.classfile.Code_attribute;45import com.sun.tools.classfile.ConstantPoolException;46import com.sun.tools.classfile.Instruction;47import com.sun.tools.classfile.LineNumberTable_attribute;48import com.sun.tools.classfile.SourceFile_attribute;495051/**52* Annotate instructions with source code.53*54* <p><b>This is NOT part of any supported API.55* If you write code that depends on this, you do so at your own risk.56* This code and its internal interfaces are subject to change or57* deletion without notice.</b>58*/59public class SourceWriter extends InstructionDetailWriter {60static SourceWriter instance(Context context) {61SourceWriter instance = context.get(SourceWriter.class);62if (instance == null)63instance = new SourceWriter(context);64return instance;65}6667protected SourceWriter(Context context) {68super(context);69context.put(SourceWriter.class, this);70}7172void setFileManager(JavaFileManager fileManager) {73this.fileManager = fileManager;74}7576public void reset(ClassFile cf, Code_attribute attr) {77setSource(cf);78setLineMap(attr);79}8081public void writeDetails(Instruction instr) {82String indent = space(40); // could get from Options?83Set<Integer> lines = lineMap.get(instr.getPC());84if (lines != null) {85for (int line: lines) {86print(indent);87print(String.format(" %4d ", line));88if (line < sourceLines.length)89print(sourceLines[line]);90println();91int nextLine = nextLine(line);92for (int i = line + 1; i < nextLine; i++) {93print(indent);94print(String.format("(%4d)", i));95if (i < sourceLines.length)96print(sourceLines[i]);97println();98}99}100}101}102103public boolean hasSource() {104return (sourceLines.length > 0);105}106107private void setLineMap(Code_attribute attr) {108SortedMap<Integer, SortedSet<Integer>> map = new TreeMap<>();109SortedSet<Integer> allLines = new TreeSet<>();110for (Attribute a: attr.attributes) {111if (a instanceof LineNumberTable_attribute) {112LineNumberTable_attribute t = (LineNumberTable_attribute) a;113for (LineNumberTable_attribute.Entry e: t.line_number_table) {114int start_pc = e.start_pc;115int line = e.line_number;116SortedSet<Integer> pcLines = map.get(start_pc);117if (pcLines == null) {118pcLines = new TreeSet<>();119map.put(start_pc, pcLines);120}121pcLines.add(line);122allLines.add(line);123}124}125}126lineMap = map;127lineList = new ArrayList<>(allLines);128}129130private void setSource(ClassFile cf) {131if (cf != classFile) {132classFile = cf;133sourceLines = splitLines(readSource(cf));134}135}136137private String readSource(ClassFile cf) {138if (fileManager == null)139return null;140141Location location;142if (fileManager.hasLocation((StandardLocation.SOURCE_PATH)))143location = StandardLocation.SOURCE_PATH;144else145location = StandardLocation.CLASS_PATH;146147// Guess the source file for a class from the package name for this148// class and the base of the source file. This avoids having to read149// additional classes to determine the outmost class from any150// InnerClasses and EnclosingMethod attributes.151try {152String className = cf.getName();153SourceFile_attribute sf =154(SourceFile_attribute) cf.attributes.get(Attribute.SourceFile);155if (sf == null) {156report(messages.getMessage("err.no.SourceFile.attribute"));157return null;158}159String sourceFile = sf.getSourceFile(cf.constant_pool);160String fileBase = sourceFile.endsWith(".java")161? sourceFile.substring(0, sourceFile.length() - 5) : sourceFile;162int sep = className.lastIndexOf("/");163String pkgName = (sep == -1 ? "" : className.substring(0, sep+1));164String topClassName = (pkgName + fileBase).replace('/', '.');165JavaFileObject fo =166fileManager.getJavaFileForInput(location,167topClassName,168JavaFileObject.Kind.SOURCE);169if (fo == null) {170report(messages.getMessage("err.source.file.not.found"));171return null;172}173return fo.getCharContent(true).toString();174} catch (ConstantPoolException e) {175report(e);176return null;177} catch (IOException e) {178report(e.getLocalizedMessage());179return null;180}181}182183private static String[] splitLines(String text) {184if (text == null)185return new String[0];186187List<String> lines = new ArrayList<>();188lines.add(""); // dummy line 0189try {190BufferedReader r = new BufferedReader(new StringReader(text));191String line;192while ((line = r.readLine()) != null)193lines.add(line);194} catch (IOException ignore) {195}196return lines.toArray(new String[lines.size()]);197}198199private int nextLine(int line) {200int i = lineList.indexOf(line);201if (i == -1 || i == lineList.size() - 1)202return - 1;203return lineList.get(i + 1);204}205206private JavaFileManager fileManager;207private ClassFile classFile;208private SortedMap<Integer, SortedSet<Integer>> lineMap;209private List<Integer> lineList;210private String[] sourceLines;211}212213214