#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import argparse import os import re import subprocess import sys SKY_TOOLS_DIR = os.path.dirname(os.path.abspath(__file__)) SKY_ROOT = os.path.dirname(SKY_TOOLS_DIR) SRC_ROOT = os.path.dirname(SKY_ROOT) WORKBENCH = os.path.join(SRC_ROOT, 'sky', 'packages', 'workbench') DART_SDK = os.path.join(SRC_ROOT, 'third_party', 'dart-sdk', 'dart-sdk', 'bin') DARTANALYZER = os.path.join(DART_SDK, 'dartanalyzer') SKY_UNIT_TESTS = os.path.join(SKY_ROOT, 'unit', 'test') _IGNORED_PATTERNS = [ # Ignored because they're not indicative of specific errors. re.compile(r'^$'), re.compile(r'^Analyzing \['), re.compile(r'^No issues found'), re.compile(r'^[0-9]+ (error|warning|hint).*found[.]'), # Disable the Strong checks that we don't care about. re.compile(r'^\[error\] Invalid override\. The type of [^ ]+ \(.+\) is not a subtype of [^ ]+ \(.+\)\.'), # we allow type narrowing re.compile(r'^\[(warning|hint)\] .+ will need runtime check to cast to type .+'), # https://github.com/dart-lang/sdk/issues/24542 re.compile(r'^\[hint\] .+ requires dynamic invoke'), # too many false positives, e.g. https://github.com/dart-lang/sdk/issues/24564 re.compile(r'^\[hint\] Runtime check on non-ground type .+ may throw StrongModeError'), # https://github.com/dart-lang/sdk/issues/24565 re.compile(r'^\[hint] \([_, ]+\) .+ has inferred type '), # ignore underscore-only arguments # Disable the lint checks that will be caught by code review re.compile(r'^\[lint\] Avoid defining a one-member abstract class when a simple function will do'), re.compile(r'^\[lint\] Prefer using lowerCamelCase for constant names.'), # TODO: Fix all the warnings in the mojo packages re.compile(r'.*pub-cache.*\.mojom\.dart'), # It'd be nice if the other packages we used didn't have warnings, too... re.compile(r'.*pub-cache/hosted/pub.dartlang.org/'), ] def main(): parser = argparse.ArgumentParser(description='Sky Analyzer') parser.add_argument('--congratulate', action="store_true") parser.add_argument('app_path', type=str, nargs="?") args = parser.parse_args() if args.app_path is not None: app_paths = [args.app_path] else: # If no app_path is provided, then run the analyzer on any Dart file # within the unit tests. app_paths = [] for root, _, files in os.walk(SKY_UNIT_TESTS): app_paths.extend(os.path.join(root, f) for f in files if f.endswith(".dart")) try: subprocess.check_output([ DARTANALYZER, "--package-warnings", "--package-root", os.path.join(WORKBENCH, "packages"), "--ignore-unrecognized-flags", "--fatal-hints", "--fatal-warnings", "--lints", "--strong", "--strong-hints", "--enable-strict-call-checks", "--enable_type_checks", "--supermixin", ] + app_paths, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: errors = [l for l in e.output.split('\n') if not any(p.match(l) for p in _IGNORED_PATTERNS)] if len(errors) > 0: for error in errors: print >> sys.stderr, error # Propagate analyzer error code. return e.returncode # If we do not have any errors left after filtering, return 0. if args.congratulate: print >> sys.stdout, "No analyzer warnings!" return 0 if __name__ == '__main__': sys.exit(main())