private void addListener(Context ctx) { long[] lastPrint = {0}; ctx.addListener((stepName, className, count, total) -> { if (count == total || System.currentTimeMillis() - lastPrint[0] > 2000) { System.err.println("HuntBugs: " + stepName + " [" + count + "/" + total + "]"); lastPrint[0] = System.currentTimeMillis(); } return true; }); }
private boolean preparingClasses(Set<String> classes) { MetadataSystem ms = createMetadataSystem(); Set<String> auxClasses = new TreeSet<>(); int count = 0; for (String className : classes) { if (!fireEvent("Reading classes", className, count, classes.size())) return false; if(++count % options.classesPerFlush == 0) { ms = createMetadataSystem(); type = lookUp(ms, className); } catch (Throwable t) { addError(new ErrorMessage(null, className, null, null, -1, t)); continue; for(ConstantPool.Entry entry : type.getConstantPool()) { if(entry instanceof TypeInfoEntry) { String depName = getMainType(((TypeInfoEntry)entry).getName()); if(depName != null && !classes.contains(depName)) auxClasses.add(depName); if (!fireEvent("Reading classes", null, classes.size(), classes.size())) return false; ms = createMetadataSystem(); count = 0; for (String className : auxClasses) { if (!fireEvent("Reading dep classes", className, count, auxClasses.size())) return false; if(++count % options.classesPerFlush == 0) { ms = createMetadataSystem();
private void analyzingClasses(Set<String> classes) { MetadataSystem ms = createMetadataSystem(); classesCount.set(0); for (String className : classes) { if(classesCount.get() % options.classesPerFlush == 0) ms = createMetadataSystem(); if (!fireEvent("Analyzing classes", className, classesCount.get(), classes.size())) return; analyzeClass(ms, className); } if (!fireEvent("Analyzing classes", null, classes.size(), classes.size())) return; }
@Override public void visitClass(String className) { String name = className.replace('/', '.'); try { ctx.incStat("Detectors.Total"); if (addDetector(MetadataSystem.class.getClassLoader().loadClass(name))) { ctx.incStat("Detectors"); if (external) { ctx.incStat("Detectors from HuntBugs plugins"); } } } catch (ClassNotFoundException e) { ctx.addError(new ErrorMessage(name, null, null, null, -1, e)); } } }
Context ctx = new Context(repo, options); if (listDetectors) { System.out.println("List of warning types:"); ctx.reportWarningTypes(System.out); list = true; ctx.reportDatabases(System.out); list = true; ctx.reportTitles(System.out); list = true; ctx.reportStats(System.out); return 0; ctx.addListener((stage, className, count, total) -> { if (count == 0) System.out.printf("\r%70s\r%s...%n", "", stage); new Thread(() -> { try { ctx.reportErrors(new PrintStream("huntbugs.errors.txt", "UTF-8")); ctx.reportStats(new PrintStream("huntbugs.stats.txt", "UTF-8")); HuntBugsResult result = ctx; if(compareTo != null) { Duration dur = Duration.ofNanos(end - start); System.out.printf("\r%70s\r", ""); System.out.println("Analyzed " + ctx.getClassesCount() + " of " + ctx.getTotalClasses() + " classes");
public static void test(String packageToAnalyze) throws Exception { // creating built-in and plugins repositories List<Repository> repositories = new ArrayList<>(); repositories.add(Repository.createSelfRepository()); for (HuntBugsPlugin huntBugsPlugin : ServiceLoader.load(HuntBugsPlugin.class)) { repositories.add(Repository.createPluginRepository(huntBugsPlugin)); } CompositeRepository repository = new CompositeRepository(repositories); Context ctx = new Context(repository, new AnalysisOptions()); ctx.analyzePackage(packageToAnalyze); ctx.reportStats(System.out); ctx.reportErrors(System.err); ctx.reportWarnings(new PrintStream("target/testWarnings.out")); Path xmlReport = Paths.get("target/testWarnings.xml"); Reports.write(xmlReport, Paths.get("target/testWarnings.html"), ctx); System.out.println("Analyzed " + ctx.getClassesCount() + " classes"); if (ctx.getErrorCount() > 0) { List<ErrorMessage> errorMessages = ctx.errors().collect(Collectors.toList()); throw new AssertionError(format("Analysis finished with %s errors: %s", ctx.getErrorCount(), errorMessages)); } HuntBugsResult result = XmlReportReader.read(ctx, xmlReport); Path rereadReport = Paths.get("target/testWarnings_reread.xml"); Reports.write(rereadReport, null, result); byte[] expectedReport = Files.readAllBytes(xmlReport); byte[] actualReport = Files.readAllBytes(rereadReport); if (!Arrays.equals(expectedReport, actualReport)) { String errorMessage = format("Expected: \n%s\n\nActual: \n%s\n\n", new String(expectedReport), new String(actualReport)); throw new AssertionError(errorMessage); } }
@Override public void execute() throws MojoExecutionException { if (!skip) { try { Context ctx = new Context(constructRepository(), constructOptions()); if (!quiet) { addAnalysisProgressListener(ctx); } ctx.analyzePackage(""); writeReports(ctx); } catch (Exception e) { throw new MojoExecutionException("Failed to run HuntBugs", e); } } }
public void analyzePackage(String name) { if (!fireEvent("Preparing", null, 0, 0)) return; Set<String> classes = new TreeSet<>(); repository.visit(name, new RepositoryVisitor() { @Override public boolean visitPackage(String packageName) { return true; } @Override public void visitClass(String className) { classes.add(className); } }); totalClasses = classes.size(); if(registry.hasDatabases()) { if(!preparingClasses(classes)) return; } analyzingClasses(classes); }
public void analyzeClass(TypeDefinition type) { ctx.incStat("TotalClasses"); if (body.getCodeSize() > ctx.getOptions().maxMethodSize) { if (systemDetector != null) { MethodContext mc = new ClassContext(ctx, cdata, systemDetector).forMethod(mdata); mc.report(METHOD_TOO_LARGE.getName(), 0, BYTECODE_SIZE.create(body.getCodeSize()), LIMIT.create( ctx.getOptions().maxMethodSize)); mc.finalizeMethod(); mdata.fullyAnalyzed = true; } catch (Throwable t) { ctx.addError(new ErrorMessage(null, type.getFullName(), md.getFullName(), md.getSignature(), -1, t));
@Override public void error(String message) { ctx.addError(new ErrorMessage(detector, fdata.fd, -1, message)); }
public void report(String warning, int priority, WarningAnnotation<?>... annotations) { WarningType wt = resolveWarningType(warning, priority); if(wt == null) return; List<WarningAnnotation<?>> anno = new ArrayList<>(); anno.addAll(getTypeSpecificAnnotations()); anno.addAll(Arrays.asList(annotations)); Warning w = new Warning(wt, priority, anno); if(!cdata.filter.test(w)) return; if(cdata.hasAsserters()) { MemberAsserter ma = cdata.ca; MemberInfo mi = w.getAnnotation(Roles.METHOD); if(mi != null) ma = cdata.getAsserter(mi); ma.checkWarning(this::error, w); } ctx.addWarning(w); }
@Override public void execute() throws BuildException { // Disable unwanted Procyon logging Logger.getLogger(Reifier.class.getSimpleName()).setLevel(Level.OFF); List<Repository> repos = createRepository(); if(xml == null && html == null) { throw new BuildException("Either xml or html must be specified"); } Repository repo = new CompositeRepository(repos); AnalysisOptions opt = new AnalysisOptions(); Context ctx = new Context(repo, opt); if(log == LogLevel.VERBOSE) addListener(ctx); ctx.analyzePackage(""); HuntBugsResult result = ctx; if(diff != null) { try { result = Reports.diff(XmlReportReader.read(ctx, diff.toPath()), ctx); } catch (IOException | SAXException | ParserConfigurationException e) { System.err.println("Unable to read old report "+diff+": "+e); System.err.println("Skipping diff generation"); } } Reports.write(xml == null ? null : xml.toPath(), html == null ? null : html.toPath(), result); }
@Override protected TypeDefinition resolveType(String descriptor, boolean mightBePrimitive) { if(missingClasses.contains(descriptor)) { return null; } try { if(loadedTypes.add(descriptor)) incStat("ClassLoadingEfficiency.Total"); if(classes.add(descriptor)) incStat("ClassLoadingEfficiency"); return super.resolveType(descriptor, mightBePrimitive); } catch (Throwable t) { addError(new ErrorMessage(null, descriptor, null, null, -1, t)); missingClasses.add(descriptor); return null; } } };
@Override public void error(String message) { ctx.addError(new ErrorMessage(detector, mdata.mainMethod, -1, message)); }
public void report(String warning, int priority, WarningAnnotation<?>... annotations) { WarningType wt = resolveWarningType(warning, priority); if(wt == null) return; List<WarningAnnotation<?>> anno = new ArrayList<>(); anno.addAll(cc.getTypeSpecificAnnotations()); anno.add(Roles.FIELD.create(fdata.fd)); anno.addAll(Arrays.asList(annotations)); Warning w = new Warning(wt, priority, anno); if(!cc.cdata.filter.test(w)) return; cc.getMemberAsserter(fdata.fd).checkWarning(this::error, w); MemberInfo mi = w.getAnnotation(Roles.METHOD); if(mi != null) cc.cdata.getAsserter(mi).checkWarning(this::error, w); ctx.addWarning(w); }
private void addAnalysisProgressListener(Context ctx) { long[] lastPrint = {0}; ctx.addListener((stepName, className, count, total) -> { if (count == total || System.currentTimeMillis() - lastPrint[0] > 2000) { getLog().info("HuntBugs: " + stepName + " [" + count + "/" + total + "]"); lastPrint[0] = System.currentTimeMillis(); } return true; }); }
boolean addDetector(Class<?> clazz) { List<WarningDefinition> wds = getDefinitions(clazz); if (wds.isEmpty()) return false; try { wds.forEach(wd -> ctx.incStat("WarningTypes.Total")); Map<String, WarningType> wts = createWarningMap(wds.stream().map(WarningType::new)); Detector detector = createDetector(clazz, wts); if (detector == null) return false; detectors.add(detector); } catch (Exception e) { ctx.addError(new ErrorMessage(clazz.getName(), null, null, null, -1, e)); } return true; }
@Override public void error(String message) { ctx.addError(new ErrorMessage(detector, type, message)); }
private void reportWarning(Warning warn) { if(!cc.cdata.filter.test(warn)) return; if(cc.cdata.hasAsserters()) { MemberInfo field = warn.getAnnotation(Roles.FIELD); if(field != null) cc.cdata.getAsserter(field).checkWarning(this::error, warn); cc.getMemberAsserter(mdata.mainMethod).checkWarning(this::error, warn); } ctx.addWarning(warn); }