📄 filter.java
字号:
/* * FindBugs - Find bugs in Java programs * Copyright (C) 2003-2005 William Pugh * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package edu.umd.cs.findbugs.workflow;import java.io.IOException;import java.lang.reflect.Field;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;import java.util.SortedMap;import java.util.TreeMap;import java.util.regex.Pattern;import edu.umd.cs.findbugs.AppVersion;import edu.umd.cs.findbugs.BugCategory;import edu.umd.cs.findbugs.BugCollection;import edu.umd.cs.findbugs.BugInstance;import edu.umd.cs.findbugs.BugPattern;import edu.umd.cs.findbugs.DetectorFactoryCollection;import edu.umd.cs.findbugs.I18N;import edu.umd.cs.findbugs.PackageStats;import edu.umd.cs.findbugs.Project;import edu.umd.cs.findbugs.SortedBugCollection;import edu.umd.cs.findbugs.SourceLineAnnotation;import edu.umd.cs.findbugs.TigerSubstitutes;import edu.umd.cs.findbugs.PackageStats.ClassStats;import edu.umd.cs.findbugs.config.CommandLine;import edu.umd.cs.findbugs.filter.FilterException;import edu.umd.cs.findbugs.filter.Matcher;/** * Java main application to filter/transform an XML bug collection * or bug history collection. * * @author William Pugh */public class Filter { static class FilterCommandLine extends CommandLine { /** * */ public static final long MILLISECONDS_PER_DAY = 24*60*60*1000L; Pattern className,bugPattern; public boolean notSpecified = false; public boolean not = false; long first; String firstAsString; long after; String afterAsString; long before; String beforeAsString; long last; String lastAsString; String fixedAsString; // alternate way to specify 'last' long present; String presentAsString; long absent; String absentAsString; String annotation; public boolean activeSpecified = false; public boolean active = false; public boolean hasField = false; public boolean hasFieldSpecified = false; public boolean hasLocal = false; public boolean hasLocalSpecified = false; public boolean withSource = false; public boolean withSourceSpecified = false; public boolean introducedByChange = false; public boolean introducedByChangeSpecified = false; public boolean removedByChange = false; public boolean removedByChangeSpecified = false; public boolean newCode = false; public boolean newCodeSpecified = false; public boolean hashChanged = false; public boolean hashChangedSpecified = false; public boolean removedCode = false; public boolean removedCodeSpecified = false; public boolean classified = false; public boolean classifiedSpecified = false; public boolean withMessagesSpecified = false; public boolean withMessages = false; public boolean serious = false; public boolean seriousSpecified = false; private Matcher includeFilter, excludeFilter; String designationString; String designationKey; String categoryString; String categoryKey; int priority = 3; FilterCommandLine() { addSwitch("-not", "reverse (all) switches for the filter"); addSwitchWithOptionalExtraPart("-withSource", "truth", "only warnings for switch source is available"); addSwitchWithOptionalExtraPart("-hashChanged", "truth", "only warnings for which the stored hash is not the same as the calculated hash"); addOption("-exclude", "filter file", "exclude bugs matching given filter"); addOption("-include", "filter file", "include only bugs matching given filter"); addOption("-annotation", "text", "allow only warnings containing this text in an annotation"); addSwitchWithOptionalExtraPart("-classified", "truth", "allow only classified warnings"); addSwitchWithOptionalExtraPart("-withMessages", "truth", "generated XML should contain textual messages"); addSwitchWithOptionalExtraPart("-serious", "truth", "allow only warnings classified as serious"); addOption("-after", "when", "allow only warnings that first occurred after this version"); addOption("-before", "when", "allow only warnings that first occurred before this version"); addOption("-first", "when", "allow only warnings that first occurred in this version"); addOption("-last", "when", "allow only warnings that last occurred in this version"); addOption("-fixed", "when", "allow only warnings that last occurred in the previous version (clobbers last)"); addOption("-present", "when", "allow only warnings present in this version"); addOption("-absent", "when", "allow only warnings absent in this version"); addSwitchWithOptionalExtraPart("-hasField", "truth", "allow only warnings that are annotated with a field"); addSwitchWithOptionalExtraPart("-hasLocal", "truth", "allow only warnings that are annotated with a local variable"); addSwitchWithOptionalExtraPart("-active", "truth", "allow only warnings alive in the last sequence number"); addSwitchWithOptionalExtraPart("-introducedByChange", "truth", "allow only warnings introduced by a change of an existing class"); addSwitchWithOptionalExtraPart("-removedByChange", "truth", "allow only warnings removed by a change of a persisting class"); addSwitchWithOptionalExtraPart("-newCode", "truth", "allow only warnings introduced by the addition of a new class"); addSwitchWithOptionalExtraPart("-removedCode", "truth", "allow only warnings removed by removal of a class"); addOption("-priority", "level", "allow only warnings with this priority or higher"); addOption("-class", "pattern", "allow only bugs whose primary class name matches this pattern"); addOption("-bugPattern", "pattern", "allow only bugs whose type matches this pattern"); addOption("-category", "category", "allow only warnings with a category that starts with this string"); addOption("-designation", "designation", "allow only warnings with this designation (e.g., -designation SHOULD_FIX)"); addSwitch("-hashChanged", "recomputed instance hash is different than stored instance hash"); } static long getVersionNum(Map<String, AppVersion> versions, SortedMap<Long, AppVersion> timeStamps , String val, boolean roundToLaterVersion, long numVersions) { if (val == null) return -1; if (val.equals("last") || val.equals("lastVersion")) return numVersions -1; AppVersion v = versions.get(val); if (v != null) return v.getSequenceNumber(); try { long time = 0; if (val.endsWith("daysAgo")) time = System.currentTimeMillis() - MILLISECONDS_PER_DAY * Integer.parseInt(val.substring(0, val.length() - 7)); else time = Date.parse(val); return getAppropriateSeq(timeStamps, time, roundToLaterVersion); } catch (Exception e) { try { long version = Long.parseLong(val); if (version < 0) { version = numVersions + version; } return version; } catch (NumberFormatException e1) { throw new IllegalArgumentException("Could not interpret version specification of '" + val + "'"); } } } // timeStamps contains 0 10 20 30 // if roundToLater == true, ..0 = 0, 1..10 = 1, 11..20 = 2, 21..30 = 3, 31.. = Long.MAX // if roundToLater == false, ..-1 = Long.MIN, 0..9 = 0, 10..19 = 1, 20..29 = 2, 30..39 = 3, 40 .. = 4 static private long getAppropriateSeq(SortedMap<Long, AppVersion> timeStamps, long when, boolean roundToLaterVersion) { if (roundToLaterVersion) { SortedMap<Long, AppVersion> geq = timeStamps.tailMap(when); if (geq.isEmpty()) return Long.MAX_VALUE; return geq.get(geq.firstKey()).getSequenceNumber(); } else { SortedMap<Long, AppVersion> leq = timeStamps.headMap(when); if (leq.isEmpty()) return Long.MIN_VALUE; return leq.get(leq.lastKey()).getSequenceNumber(); } } void adjustFilter(BugCollection collection) { Map<String, AppVersion> versions = new HashMap<String, AppVersion>(); SortedMap<Long, AppVersion> timeStamps = new TreeMap<Long, AppVersion>(); for(Iterator<AppVersion> i = collection.appVersionIterator(); i.hasNext(); ) { AppVersion v = i.next(); versions.put(v.getReleaseName(), v); timeStamps.put(v.getTimestamp(), v); } // add current version to the maps AppVersion v = collection.getCurrentAppVersion(); versions.put(v.getReleaseName(), v); timeStamps.put(v.getTimestamp(), v); first = getVersionNum(versions, timeStamps, firstAsString, true, v.getSequenceNumber()); last = getVersionNum(versions, timeStamps, lastAsString, true, v.getSequenceNumber()); before = getVersionNum(versions, timeStamps, beforeAsString, true, v.getSequenceNumber()); after = getVersionNum(versions, timeStamps, afterAsString, false, v.getSequenceNumber()); present = getVersionNum(versions, timeStamps, presentAsString, true, v.getSequenceNumber()); absent = getVersionNum(versions, timeStamps, absentAsString, true, v.getSequenceNumber()); long fixed = getVersionNum(versions, timeStamps, fixedAsString, true, v.getSequenceNumber()); if (fixed >= 0) last = fixed - 1; // fixed means last on previous sequence (ok if -1) } boolean accept(BugInstance bug) { boolean result = evaluate(bug); if (not) return !result; return result; } boolean evaluate(BugInstance bug) { if (includeFilter != null && !includeFilter.match(bug)) return false; if (excludeFilter != null && excludeFilter.match(bug)) return false; if (annotation != null && bug.getAnnotationText().indexOf(annotation) == -1) return false; if (bug.getPriority() > priority) return false; if (firstAsString != null && bug.getFirstVersion() != first) return false; if (afterAsString != null && bug.getFirstVersion() <= after) return false; if (beforeAsString != null && bug.getFirstVersion() >= before) return false; if ((lastAsString != null || fixedAsString != null) && (last < 0 || bug.getLastVersion() != last))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -