1 cananian 1.1.2.1 // Lint.java, created Sun Sep 12 09:49:13 1999 by cananian 2 cananian 1.1.2.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Main; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 7 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 8 cananian 1.1.2.3 import harpoon.ClassFile.HCodeElement; 9 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 10 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 11 cananian 1.1.2.5 import harpoon.ClassFile.Linker; 12 cananian 1.1.2.1 import harpoon.ClassFile.Loader; 13 cananian 1.1.2.1 import harpoon.Temp.Temp; 14 cananian 1.1.2.1 15 cananian 1.1.2.3 import java.io.BufferedReader; 16 cananian 1.1.2.3 import java.io.File; 17 cananian 1.1.2.3 import java.io.FileReader; 18 cananian 1.1.2.3 import java.util.ArrayList; 19 cananian 1.1.2.1 import java.util.Iterator; 20 cananian 1.1.2.3 import java.util.List; 21 cananian 1.1.2.1 /** 22 cananian 1.1.2.1 * <code>Lint</code> is a quick Java code-checker.<p> 23 cananian 1.1.2.1 * Currently it checks only two things:<ul> 24 cananian 1.1.2.1 * <li>Uses of <code>Label</code><code>.toString()</code> (which should 25 cananian 1.1.2.1 * almost always be <code>Label.name</code> instead), and 26 cananian 1.1.2.1 * <li>Testing objects for equality using <code>==</code> (instead of 27 cananian 1.1.2.1 * <code>equals()</code>). 28 cananian 1.1.2.1 * </ul><p> 29 cananian 1.1.2.1 * Invoke with:<pre> 30 cananian 1.1.2.1 * java harpoon.Main.Lint [package1] [package2] ... 31 cananian 1.1.2.1 * </pre><p> 32 cananian 1.1.2.1 * Output is a list of source files and line numbers which are being 33 cananian 1.1.2.1 * flagged as possibly incorrect. 34 cananian 1.1.2.1 * 35 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 36 cananian 1.3 * @version $Id: Lint.java,v 1.3 2004/02/08 01:58:13 cananian Exp $ 37 cananian 1.1.2.1 */ 38 cananian 1.1.2.1 public abstract class Lint extends harpoon.IR.Registration { 39 cananian 1.1.2.5 public final static Linker linker = Loader.systemLinker; 40 cananian 1.1.2.5 41 cananian 1.1.2.4 public static void usage(String errmsg) { 42 cananian 1.1.2.4 System.err.println(errmsg); 43 cananian 1.1.2.4 System.err.println("Usage: java "+Lint.class.getName()+" "+ 44 cananian 1.1.2.4 "{-use sourcepath} {-e} {-v} {-l} "+ 45 cananian 1.1.2.4 "[packages] ..."); 46 cananian 1.1.2.4 System.err.println(" -e\tShow possibly-incorrect object comparisons using =="); 47 cananian 1.1.2.4 System.err.println(" -v\tShow possibly-incorrect QuadVisitor.visit(CALL) methods"); 48 cananian 1.1.2.4 System.err.println(" -l\tShow uses of (deprecated) Label.toString()"); 49 cananian 1.1.2.4 System.exit(1); 50 cananian 1.1.2.4 } 51 cananian 1.1.2.1 public static void main(String[] args) { 52 cananian 1.1.2.4 boolean check_visit=false,check_labels=false,check_equals=false; 53 cananian 1.1.2.3 // Command-line should have list of packages, & opt. sourcepath 54 cananian 1.1.2.4 int s; 55 cananian 1.1.2.4 for (s=0; args.length>s && args[s].charAt(0)=='-'; s++) { 56 cananian 1.1.2.4 if (args[s].startsWith("-use") && args.length>s+1) 57 cananian 1.1.2.4 SourceLineReader.sourcepath=args[++s]; 58 cananian 1.1.2.4 else if (args[s].startsWith("-v")) 59 cananian 1.1.2.4 check_visit=true; 60 cananian 1.1.2.4 else if (args[s].startsWith("-l")) 61 cananian 1.1.2.4 check_labels=true; 62 cananian 1.1.2.4 else if (args[s].startsWith("-e")) 63 cananian 1.1.2.4 check_equals=true; 64 cananian 1.1.2.4 else 65 cananian 1.1.2.4 usage("Unrecognized option: "+args[s]); 66 cananian 1.1.2.4 } 67 cananian 1.1.2.4 if (!(args.length>s)) 68 cananian 1.1.2.4 usage("No packages specified."); 69 cananian 1.1.2.4 70 cananian 1.1.2.4 HCodeFactory hcf = harpoon.IR.Bytecode.Code.codeFactory(); 71 cananian 1.1.2.4 // rule-checkers using any IR at all. 72 cananian 1.1.2.4 if (check_visit) // check implementations of visit(CALL) 73 cananian 1.1.2.4 hcf = new CheckVisitCALL(hcf); 74 cananian 1.1.2.4 // rule-checkers using quad-no-ssa 75 cananian 1.1.2.4 if (check_labels) // check uses of Label.toString() 76 cananian 1.1.2.4 hcf = new CheckLabels(hcf); 77 cananian 1.1.2.4 // rule-checkers using quad-ssi 78 cananian 1.1.2.4 if (check_equals) // check usage of == for objects. 79 cananian 1.1.2.4 hcf = new CheckEquals(hcf); 80 cananian 1.1.2.4 81 cananian 1.1.2.3 for (int i=s; i<args.length; i++) { 82 cananian 1.1.2.1 System.err.println("CHECKING PACKAGE "+args[i]); 83 cananian 1.1.2.1 for (Iterator it=Loader.listClasses(args[i]); it.hasNext(); ) { 84 cananian 1.1.2.5 HClass hc = linker.forName((String)it.next()); 85 cananian 1.1.2.1 System.err.println(" - " + hc); 86 cananian 1.1.2.1 HMethod[] hms = hc.getDeclaredMethods(); 87 cananian 1.1.2.2 for (int j=0; j<hms.length; j++) { 88 cananian 1.1.2.1 hcf.convert(hms[j]); 89 cananian 1.1.2.2 hcf.clear(hms[j]); // free memory. 90 cananian 1.1.2.2 } 91 cananian 1.1.2.1 } 92 cananian 1.1.2.1 } 93 cananian 1.1.2.1 } 94 cananian 1.1.2.3 /** Allow reference to particular lines of a class file */ 95 cananian 1.1.2.3 static class SourceLineReader { 96 cananian 1.1.2.3 public static String sourcepath="."; 97 cananian 1.1.2.3 private List linelist = new ArrayList(); 98 cananian 1.1.2.3 SourceLineReader(HClass cls, String sourcefile) { 99 cananian 1.1.2.3 String filesep = System.getProperty("file.separator"); 100 cananian 1.1.2.3 String packagepath = 101 cananian 1.1.2.3 cls.getPackage().replace('.',filesep.charAt(0)); 102 cananian 1.1.2.3 File f = new File(new File(sourcepath,packagepath),sourcefile); 103 cananian 1.1.2.3 try { 104 cananian 1.1.2.3 BufferedReader br = new BufferedReader(new FileReader(f)); 105 cananian 1.1.2.3 for (String line = br.readLine(); line!=null; line=br.readLine()) 106 cananian 1.1.2.3 linelist.add(line); 107 cananian 1.1.2.3 br.close(); 108 cananian 1.1.2.3 } catch (java.io.IOException e) { linelist=null; } 109 cananian 1.1.2.3 } 110 cananian 1.1.2.3 public String getLine(int lineno) { 111 cananian 1.1.2.3 if (linelist==null || linelist.size()<lineno) 112 cananian 1.1.2.3 return "[--- unable to read file ---]"; 113 cananian 1.1.2.3 return (String) linelist.get(lineno-1); 114 cananian 1.1.2.3 } 115 cananian 1.1.2.3 } 116 cananian 1.1.2.3 /** method for caching sourcelinereaders */ 117 cananian 1.1.2.3 public static SourceLineReader getSLR(HClass cls, String sourcefile) { 118 cananian 1.1.2.3 if (last_slr==null || last_cls!=cls || last_sourcefile!=sourcefile) { 119 cananian 1.1.2.3 last_slr = new SourceLineReader(cls, sourcefile); 120 cananian 1.1.2.3 last_cls = cls; last_sourcefile=sourcefile; 121 cananian 1.1.2.3 } 122 cananian 1.1.2.3 return last_slr; 123 cananian 1.1.2.3 } 124 cananian 1.1.2.3 static SourceLineReader last_slr = null; 125 cananian 1.1.2.3 static HClass last_cls = null; 126 cananian 1.1.2.3 static String last_sourcefile = null; 127 cananian 1.1.2.3 /** print out a standardized error message */ 128 cananian 1.1.2.3 public static void printError(String msg, HMethod hm, HCodeElement hce) { 129 cananian 1.1.2.3 System.out.println("WARNING: "+msg+" in " + 130 cananian 1.1.2.3 hm.getDeclaringClass().getName()+"."+hm.getName() + 131 cananian 1.1.2.3 ":"); 132 cananian 1.1.2.3 System.out.println(hce.getSourceFile()+"("+hce.getLineNumber()+"): " + 133 cananian 1.1.2.3 getSLR(hm.getDeclaringClass(), hce.getSourceFile()) 134 cananian 1.1.2.3 .getLine(hce.getLineNumber()).trim()); 135 cananian 1.1.2.3 System.out.println(); 136 cananian 1.1.2.3 } 137 cananian 1.1.2.3 138 cananian 1.1.2.3 /////////// RULE-CHECKING CODE FACTORIES: 139 cananian 1.1.2.3 140 cananian 1.1.2.4 /** Find all methods overriding QuadVisitor.visit(CALL q). */ 141 cananian 1.1.2.4 static class CheckVisitCALL implements HCodeFactory { 142 cananian 1.1.2.4 final HCodeFactory hcf; 143 cananian 1.1.2.4 CheckVisitCALL(HCodeFactory hcf) { this.hcf = hcf; } 144 cananian 1.1.2.4 public void clear(HMethod hm) { hcf.clear(hm); } 145 cananian 1.1.2.4 public String getCodeName() { return hcf.getCodeName(); } 146 cananian 1.1.2.4 public HCode convert(HMethod hm) { 147 cananian 1.1.2.4 HCode c = hcf.convert(hm); 148 cananian 1.1.2.4 if (c==null) return c; 149 cananian 1.1.2.4 if (hm.getDeclaringClass().isInstanceOf(HCqv) && 150 cananian 1.1.2.4 hm.getName().equals(HMvC.getName()) && 151 cananian 1.1.2.4 hm.getDescriptor().equals(HMvC.getDescriptor())) 152 cananian 1.1.2.4 Lint.printError("Possibly incorrect implementation of "+ 153 cananian 1.1.2.4 "QuadVisitor.visit(CALL q)", 154 cananian 1.1.2.4 hm, c.getRootElement()); 155 cananian 1.1.2.4 return c; 156 cananian 1.1.2.4 } 157 cananian 1.1.2.4 private static final HClass HCqv = 158 cananian 1.1.2.5 linker.forName("harpoon.IR.Quads.QuadVisitor"); 159 cananian 1.1.2.4 private static final HMethod HMvC = 160 cananian 1.1.2.4 HCqv.getMethod("visit", new HClass[] 161 cananian 1.1.2.5 { linker.forName("harpoon.IR.Quads.CALL") } ); 162 cananian 1.1.2.4 } 163 cananian 1.1.2.4 164 cananian 1.1.2.1 /** Find all places where Label.toString() is called. */ 165 cananian 1.1.2.1 static class CheckLabels implements HCodeFactory { 166 cananian 1.1.2.1 final HCodeFactory hcf; 167 cananian 1.1.2.4 CheckLabels(HCodeFactory hcf) { 168 cananian 1.1.2.4 if (!hcf.getCodeName().equals(harpoon.IR.Quads.QuadNoSSA.codename)) 169 cananian 1.1.2.4 hcf = harpoon.IR.Quads.QuadNoSSA.codeFactory(hcf); 170 cananian 1.1.2.4 this.hcf = hcf; 171 cananian 1.1.2.4 } 172 cananian 1.1.2.1 public void clear(HMethod hm) { hcf.clear(hm); } 173 cananian 1.1.2.1 public String getCodeName() { return hcf.getCodeName(); } 174 cananian 1.1.2.1 public HCode convert(HMethod hm) { 175 cananian 1.1.2.1 HCode c = hcf.convert(hm); 176 cananian 1.1.2.1 if (c==null) return c; 177 cananian 1.1.2.1 for (Iterator it=c.getElementsI(); it.hasNext(); ) { 178 cananian 1.1.2.1 harpoon.IR.Quads.Quad q = (harpoon.IR.Quads.Quad) it.next(); 179 cananian 1.1.2.1 if (q instanceof harpoon.IR.Quads.CALL && 180 cananian 1.1.2.1 ((harpoon.IR.Quads.CALL)q).method().equals(label_toString)) 181 cananian 1.1.2.3 Lint.printError("Use of deprecated Label.toString() method", 182 cananian 1.1.2.3 hm, q); 183 cananian 1.1.2.1 } 184 cananian 1.1.2.1 return c; 185 cananian 1.1.2.1 } 186 cananian 1.1.2.1 private static final HMethod label_toString = 187 cananian 1.1.2.5 linker.forName("harpoon.Temp.Label") 188 cananian 1.1.2.1 .getMethod("toString",new HClass[0]); 189 cananian 1.1.2.1 } 190 cananian 1.1.2.1 /** Find all places where object equality is checked with == and 191 cananian 1.1.2.1 * where we're not comparing something against null. */ 192 cananian 1.1.2.1 static class CheckEquals implements HCodeFactory { 193 cananian 1.1.2.1 final HCodeFactory hcf; 194 cananian 1.1.2.4 CheckEquals(HCodeFactory hcf) { 195 cananian 1.1.2.4 if (!hcf.getCodeName().equals(harpoon.IR.Quads.QuadSSI.codename)) 196 cananian 1.1.2.4 hcf = harpoon.IR.Quads.QuadSSI.codeFactory(hcf); 197 cananian 1.1.2.4 this.hcf = hcf; 198 cananian 1.1.2.4 } 199 cananian 1.1.2.1 public void clear(HMethod hm) { hcf.clear(hm); } 200 cananian 1.1.2.1 public String getCodeName() { return hcf.getCodeName(); } 201 cananian 1.1.2.1 public HCode convert(HMethod hm) { 202 cananian 1.1.2.1 HCode c = hcf.convert(hm); 203 cananian 1.1.2.1 if (c==null) return c; 204 cananian 1.1.2.2 harpoon.Analysis.Quads.SCC.SCCAnalysis tm = 205 cananian 1.1.2.1 new harpoon.Analysis.Quads.SCC.SCCAnalysis(c); 206 cananian 1.1.2.2 new harpoon.Analysis.Quads.SCC.SCCOptimize(tm).optimize(c); 207 cananian 1.1.2.1 for (Iterator it=c.getElementsI(); it.hasNext(); ) { 208 cananian 1.1.2.1 harpoon.IR.Quads.Quad q = (harpoon.IR.Quads.Quad) it.next(); 209 cananian 1.1.2.1 if (!(q instanceof harpoon.IR.Quads.OPER)) continue; 210 cananian 1.1.2.1 harpoon.IR.Quads.OPER oper = (harpoon.IR.Quads.OPER)q; 211 cananian 1.1.2.1 if (oper.opcode()!=harpoon.IR.Quads.Qop.ACMPEQ) continue; 212 cananian 1.1.2.1 Temp l=oper.operands(0), r=oper.operands(1); 213 cananian 1.1.2.1 if (tm.typeMap(q,l)==HClass.Void || 214 cananian 1.1.2.1 tm.typeMap(q,r)==HClass.Void) continue; 215 cananian 1.1.2.3 if (refunique.isSuperinterfaceOf(tm.typeMap(q,l)) || 216 cananian 1.1.2.3 refunique.isSuperinterfaceOf(tm.typeMap(q,r))) continue; 217 cananian 1.1.2.6 Lint.printError("Possibly incorrect use of == ("+tm.typeMap(q,l)+" / "+tm.typeMap(q,r)+")", hm, q); 218 cananian 1.1.2.1 } 219 cananian 1.1.2.1 return c; 220 cananian 1.1.2.1 } 221 cananian 1.1.2.3 private static final HClass refunique = 222 cananian 1.3 linker.forName("net.cscott.jutil.ReferenceUnique"); 223 cananian 1.1.2.1 } 224 cananian 1.2 }