help="Regenerate the exceptions file")
parser.add_argument("--list-overbroad", action="store_true",
help="List over-broad exceptions")
+ parser.add_argument("--regen-overbroad", action="store_true",
+ help="Regenerate the exceptions file, "
+ "removing over-broad exceptions.")
parser.add_argument("--exceptions",
help="Override the location for the exceptions file")
parser.add_argument("--strict", action="store_true",
filt.addThreshold(problem.DependencyViolationItem("*.c", int(args.max_dependency_violations)))
filt.addThreshold(problem.DependencyViolationItem("*.h", int(args.max_dependency_violations)))
- if args.list_overbroad and args.regen:
- print("Cannot use --regen with --list-overbroad",
+ if args.list_overbroad + args.regen + args.regen_overbroad > 1:
+ print("Cannot use more than one of --regen, --list-overbroad, and "
+ "--regen-overbroad.",
file=sys.stderr)
sys.exit(1)
ProblemVault = problem.ProblemVault(exceptions_file)
problem_file = sys.stdout
- if args.list_overbroad:
- # If we're listing overbroad exceptions, don't list problems.
+ if args.list_overbroad or args.regen_overbroad:
+ # If we're looking for overbroad exceptions, don't list problems
+ # immediately to the problem file.
problem_file = util.NullFile()
# 2.1) Adjust the exceptions so that we warn only about small problems,
# and produce errors on big ones.
- if not (args.regen or args.list_overbroad or args.strict):
+ if not (args.regen or args.list_overbroad or args.regen_overbroad or
+ args.strict):
ProblemVault.set_tolerances(TOLERANCE_FNS)
# 3) Go through all the files and report problems if they are not exceptions
os.rename(tmpname, exceptions_file)
sys.exit(0)
+ if args.regen_overbroad:
+ tmpname = exceptions_file + ".tmp"
+ tmpfile = open(tmpname, "w")
+ tmpfile.write(HEADER)
+ for item in ProblemVault.list_exceptions_without_overbroad():
+ print(item, file=tmpfile)
+ tmpfile.close()
+ os.rename(tmpname, exceptions_file)
+ sys.exit(0)
+
# If new issues were found, try to give out some advice to the developer on how to resolve it.
if found_new_issues and not args.regen and not args.terse:
new_issues_str = """\
else:
print(ex, "->", p.metric_value)
+
sys.exit(found_new_issues)
if __name__ == '__main__':
def __init__(self, exception_fname=None):
# Exception dictionary: { problem.key() : Problem object }
self.exceptions = {}
+ # Exception list: list of Problem objects, in the order added.
+ self.exception_list = []
# Exception dictionary: maps key to the problem it was used to
# suppress.
self.used_exception_for = {}
sys.exit(1)
self.exceptions[problem.key()] = problem
+ self.exception_list.append(problem)
#print "Registering exception: %s" % problem
def register_problem(self, problem):
if p is None or e.is_worse_than(p):
yield (e, p)
+ def list_exceptions_without_overbroad(self):
+ """Return an iterator of new problems, such that overbroad
+ exceptions are replaced with minimally broad versions, or removed.
+ """
+ for e in self.exception_list:
+ p = self.used_exception_for.get(e.key())
+ if p is None:
+ # This exception wasn't needed at all.
+ continue
+ if e.is_worse_than(p):
+ # The exception is worse than the problem we found.
+ # Yield the problem as the new exception value.
+ yield p
+ else:
+ # The problem is as bad as the exception, or worse.
+ # Yield the exception.
+ yield e
+
def set_tolerances(self, fns):
"""Adjust the tolerances for the exceptions in this vault. Takes
a map of problem type to a function that adjusts the permitted