Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 314   Methods: 11
NCLOC: 141   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
LanguageLevelStackTraceMapper.java 7.9% 7.3% 36.4% 9.5%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.model.compiler;
 38   
 39    import java.awt.EventQueue;
 40    import java.io.File;
 41    import java.io.IOException;
 42    import java.io.BufferedReader;
 43    import java.io.FileReader;
 44   
 45    import java.util.List;
 46    import java.util.HashMap;
 47    import java.util.HashSet;
 48    import java.util.Set;
 49    import java.util.TreeMap;
 50   
 51    import edu.rice.cs.drjava.model.GlobalModel;
 52    import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
 53    import edu.rice.cs.drjava.model.DrJavaFileUtils;
 54    import edu.rice.cs.util.swing.Utilities;
 55   
 56    /** Class used to get TreeMaps with dj* to java line number (and vise versa) conversions */
 57    public class LanguageLevelStackTraceMapper {
 58   
 59    /** logging information */
 60    public static final edu.rice.cs.util.Log LOG = new edu.rice.cs.util.Log("llstm.txt",false);
 61   
 62    /** cache to store the tree maps */
 63    private HashMap<String,TreeMap<Integer,Integer>> cache;
 64   
 65    /** model used to get the OpenDefinitionsDocuments from files */
 66    private GlobalModel aGModel;
 67   
 68    /* constructor */
 69  157 public LanguageLevelStackTraceMapper(GlobalModel aGM){
 70  157 aGModel = aGM;
 71  157 cache = new HashMap<String,TreeMap<Integer,Integer>>();
 72    }
 73   
 74  0 public StackTraceElement replaceStackTraceElement(StackTraceElement s, File d, TreeMap<Integer,Integer> m) {
 75   
 76  0 int jl = s.getLineNumber();
 77  0 int lll = m.containsKey(jl) ? m.get(jl) : -1;
 78   
 79  0 return new StackTraceElement(s.getClassName(), s.getMethodName(), d.getName(), lll);
 80    }
 81   
 82    /** Converts java file and line number to corresponding dj* file name and line number in a given stacktrace element.
 83    * @param s the StackTraceElement to do be converted
 84    * @param d the dj* file whose name and line numbers are required in the StackTraceElement
 85    */
 86  0 public StackTraceElement replaceStackTraceElement(StackTraceElement s, File d) {
 87   
 88    // If the file name in s matches d, check if n already exists in the cache.
 89    // If it does, call the above replaceStackTraceElement with the cached TreeMap
 90    // Otherwise load the TreeMap from the *.java file, store it in the cache, and then
 91    // call the above replaceStackTraceElement.
 92    // If the file name does not match, just return s
 93   
 94  0 if (! matches(d, s)) return s;
 95  0 String fileName = d.getAbsolutePath();
 96  0 if (cache.containsKey(fileName)) return replaceStackTraceElement(s, d, cache.get(fileName));
 97   
 98  0 String dn = d.getName();
 99  0 dn = dn.substring(0, dn.lastIndexOf('.')) + edu.rice.cs.drjava.config.OptionConstants.JAVA_FILE_EXTENSION;
 100  0 File javaFile = new File(d.getParentFile(), dn);
 101   
 102  0 TreeMap<Integer, Integer> djToJavaMap = readLLLineBlock(javaFile);
 103   
 104  0 cache.put(fileName, djToJavaMap);
 105   
 106  0 return replaceStackTraceElement(s, d, djToJavaMap);
 107    }
 108   
 109    /** Replaces the dj* file name and line numbers in a given stacktrace element.
 110    * @param s the StackTraceElement to do the replacing in
 111    * @param ds a list of the dj* file whose names and line numbers need replacing in the StackTraceElement
 112    */
 113  453 public StackTraceElement replaceStackTraceElement(StackTraceElement s, List<File> ds) {
 114  453 for (int i = 0; i < ds.size(); i++) {
 115  0 s = replaceStackTraceElement(s, ds.get(i));
 116    }
 117  453 return s;
 118    }
 119    // Call replaceStackTraceElement(s, f.get(i), cache) for all i to replace the
 120    // file name and map the numbers for all files
 121   
 122    /** Replaces the dj* file names and line numbers in the given stacktrace elements.
 123    * @param ss an array of StackTraceElement to do the replacing in
 124    * @param ds a list of the dj* file whose names and line numbers need replacing in the StackTraceElement
 125    */
 126  13 public StackTraceElement[] replaceStackTrace(StackTraceElement[] ss, List<File> ds) {
 127  13 for(int i = 0; i < ss.length; i++) {
 128  453 ss[i] = replaceStackTraceElement(ss[i], ds);
 129    }
 130  13 return ss;
 131    }
 132    // Call replaceStackTraceElement(ss.get(i), f, cache) for all i to process all stack trace
 133    // elements in the array.
 134   
 135   
 136    /** Clears the TreeMap cache */
 137  57 public void clearCache() {
 138  57 cache = new HashMap<String,TreeMap<Integer,Integer>>();
 139    }
 140   
 141    /** Ensures the given file and StackTraceElement match. The extension on the file f may be a LL extension while the
 142    * extension in the StackTraceElement is the corresponding .java file.
 143    * @param f the file
 144    * @param s the StackTraceElement
 145    */
 146  0 private boolean matches(File f, StackTraceElement s) {
 147  0 LOG.log("matches(" + f + ", " + s + ")");
 148  0 if (s.getFileName() == null) return false;
 149    // OpenDefinitionsDocument d;
 150    // try { d = aGModel.getDocumentForFile(f); }
 151    // catch(java.io.IOException e) { return false; }
 152    //
 153    // String dn = d.getRawFile().getName();
 154   
 155  0 String fn = f.getPath(); // a relative path because traces use relative paths for files.
 156   
 157    // make sure that the document is a LL document
 158  0 if (! DrJavaFileUtils.isLLFile(fn)) return false;
 159   
 160    // replace suffix with ".java"
 161  0 String javaFn = DrJavaFileUtils.getJavaForLLFile(fn);
 162   
 163    // Utilities.show("Document file name is: " + fn + "\nJava file name is: " + javaFn + "\nStack file name is: " +
 164    // s.getFileName() + "\nResult is: " + javaFn.endsWith(s.getFileName()));
 165   
 166    //// make sure packages match
 167    // String dp = d.getPackageName();
 168    // int dotPos = s.getClassName().lastIndexOf('.');
 169    // if ((dp.length() == 0) && (dotPos >= 0)) return false; // d in default package, s not
 170    // if ((dp.length() > 0) && (dotPos < 0)) return false; // s in default package, d not
 171    // String sp = "";
 172    // if (dotPos >= 0) sp = s.getClassName().substring(0, dotPos);
 173    // if (! dp.equals(sp)) return false; // packages do not match
 174   
 175    // make sure the file names match
 176  0 return javaFn.endsWith(s.getFileName()); // names in trace elements are relative
 177    }
 178   
 179  0 private TreeMap<Integer, Integer> createOneToOneMap(BufferedReader bufReader) {
 180    // legacy support for old .dj2 language level files:
 181    // see DrJava feature request 2990660
 182    // As of revisions 5225-5227, .dj2 files aren't converted by the LanguageLevelConverter anymore,
 183    // they are just copied. That means the debugger and JUnit test errors cannot translate their line
 184    // numbers in .java files back to the .dj2 line numbers. Since the .dj2 file and the .java file
 185    // are identical, we just create a 1-to-1 map that maps a line number to itself.
 186  0 TreeMap<Integer, Integer> oneToOne = new TreeMap<Integer, Integer>();
 187  0 int lineNo = 1;
 188  0 oneToOne.put(lineNo,lineNo);
 189  0 try {
 190  0 String rdLine;
 191  0 while((rdLine = bufReader.readLine()) != null) {
 192  0 ++lineNo;
 193  0 oneToOne.put(lineNo,lineNo);
 194    }
 195    }
 196    catch(java.io.IOException e) { /* ignore, just return incomplete map */ }
 197  0 return oneToOne;
 198    }
 199   
 200    /** Reads the LanguageLevel header from a LL file and pulls the line number conversion map out.
 201    * @return <java line, dj* line>
 202    */
 203  0 public TreeMap<Integer, Integer> readLLLineBlock(File LLFile){
 204   
 205  0 BufferedReader bufReader = null;
 206  0 String rdLine = "";
 207   
 208  0 try { bufReader = new BufferedReader(new FileReader(LLFile)); } catch(java.io.FileNotFoundException e){ }
 209   
 210  0 try { rdLine = bufReader.readLine(); } catch(java.io.IOException e){ }
 211   
 212  0 if (! rdLine.startsWith("// Language Level Converter line number map: dj*->java. Entries:")) {
 213    // no language level header, create a 1-to-1 mapping
 214  0 return createOneToOneMap(bufReader);
 215    }
 216   
 217    // Process header line of block
 218  0 LOG.log("rdLine = '" + rdLine + "'");
 219  0 LOG.log("\tlastIndex = " + rdLine.lastIndexOf(" "));
 220  0 Integer mapSize = new Integer (rdLine.substring(rdLine.lastIndexOf(" ") + 1));
 221   
 222  0 try { rdLine = bufReader.readLine(); } catch(java.io.IOException e){ }
 223   
 224  0 if (rdLine.indexOf("//") != 0) mapSize = 0; // Kills the for loop if read line is not of correct format
 225   
 226    // Create the LL map
 227  0 TreeMap<Integer,Integer> javaDJMap = new TreeMap<Integer,Integer>();
 228   
 229    // Process block lines containing map entries; rdLine is first such line
 230    // Invariant for text: text has no leading whitespace and trailing whitespace consisting of a single blank
 231  0 String text = rdLine.substring(2).trim() + " ";
 232   
 233  0 Integer djNum;
 234  0 Integer javaNum;
 235   
 236    // Utilities.show("read " + mapSize + " entries from bufReader");
 237  0 for (int i = 0; i < mapSize; i++) {
 238  0 if (text.length() < 2) text = readNextLLBlockLine(bufReader);
 239  0 if (text == null) break; // no more entries in block; mapSize is wrong // ERROR should be raised !!!
 240   
 241  0 int firstBlankPos = text.indexOf(" ");
 242  0 String numRnum = text.substring(0, firstBlankPos);
 243  0 text = text.substring(firstBlankPos).trim() + " "; // Only need to trim leading blanks here; String API is clumsy
 244   
 245  0 djNum = new Integer(numRnum.substring(0, numRnum.indexOf("->")));
 246  0 javaNum = new Integer(numRnum.substring(numRnum.indexOf("->") + 2));
 247   
 248  0 javaDJMap.put(javaNum,djNum);
 249    }
 250  0 return javaDJMap;
 251    }
 252   
 253   
 254   
 255    /** Reads the LanguageLevel header from a LL file and pulls the line number conversion map out.
 256    * @return <dj* line, java line>
 257    */
 258  0 public TreeMap<Integer, Integer> readLLBlock(File LLFile) {
 259   
 260  0 BufferedReader bufReader = null;
 261  0 String rdLine = "";
 262   
 263  0 try { bufReader = new BufferedReader(new FileReader(LLFile)); } catch(java.io.FileNotFoundException e){ }
 264   
 265  0 try { rdLine = bufReader.readLine(); } catch(java.io.IOException e){ }
 266   
 267  0 if (! rdLine.startsWith("// Language Level Converter line number map: dj*->java. Entries:")) {
 268    // no language level header, create a 1-to-1 mapping
 269  0 return createOneToOneMap(bufReader);
 270    }
 271   
 272  0 LOG.log("rdLine = '" + rdLine + "'");
 273  0 LOG.log("\tlastIndex = " + rdLine.lastIndexOf(" "));
 274  0 Integer mapSize = new Integer (rdLine.substring(rdLine.lastIndexOf(" ") + 1));
 275   
 276  0 try { rdLine = bufReader.readLine(); } catch(java.io.IOException e){ }
 277   
 278  0 if(rdLine.indexOf("//") != 0) mapSize = 0; // Kills the for loop if read line is not of correct format
 279   
 280  0 TreeMap<Integer,Integer> map = new TreeMap<Integer,Integer>();
 281   
 282  0 String text = rdLine.substring(2).trim() + " "; // invariant: temp has no leading spaces and a single trailing space
 283  0 String numRnum = "";
 284   
 285  0 int djNum;
 286  0 int javaNum;
 287   
 288  0 for(int i = 0; i < mapSize; i++) {
 289  0 if (text.length() < 2) text = readNextLLBlockLine(bufReader);
 290  0 if (text == null) break;
 291   
 292  0 numRnum = text.substring(0, text.indexOf(" "));
 293   
 294  0 djNum = Integer.parseInt(numRnum.substring(0, numRnum.indexOf("->")), 10);
 295  0 javaNum = Integer.parseInt(numRnum.substring(numRnum.indexOf("->") + 2), 10);
 296   
 297  0 map.put(djNum, javaNum);
 298  0 text = text.substring(text.indexOf(" ")).trim() + " "; // slices off first non-blank section
 299    // NOTE: it would more efficient to simply remove all leading whitespace instead of trimming and adding a space.
 300    }
 301  0 return map;
 302    }
 303   
 304    /** Helper method to read the next comment line in a file. Returns null if no new comment line exists.
 305    * Line is trimmed and padded by a single blank on the end. */
 306  0 private String readNextLLBlockLine(BufferedReader br) {
 307  0 String line = "";
 308  0 try { line = br.readLine(); } catch(java.io.IOException e){ }
 309   
 310  0 if (line.indexOf("//") != 0) return null;
 311  0 line = line.substring(2).trim() + " ";
 312  0 return line;
 313    }
 314    }