#!/usr/bin/env python # Copyright (c) 2012 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. """Counts the number of #if or #ifdef lines containing at least one preprocessor token that is a full match for the given pattern, in the given directory. """ import optparse import os import re import sys # Filename extensions we know will be handled by the C preprocessor. # We ignore files not matching these. CPP_EXTENSIONS = [ '.h', '.cc', '.m', '.mm', ] def _IsTestFile(filename): """Does a rudimentary check to try to skip test files; this could be improved but is good enough for basic metrics generation. """ return re.match('(test|mock|dummy)_.*|.*_[a-z]*test\.(h|cc|mm)', filename) def CountIfdefs(token_pattern, directory, skip_tests=False): """Returns the number of lines in files in |directory| and its subdirectories that have an extension from |CPP_EXTENSIONS| and are an #if or #ifdef line with a preprocessor token fully matching the string |token_pattern|. If |skip_tests| is true, a best effort is made to ignore test files. """ token_line_re = re.compile(r'^#if(def)?.*\b(%s)\b.*$' % token_pattern) count = 0 for root, dirs, files in os.walk(directory): for filename in files: if os.path.splitext(filename)[1] in CPP_EXTENSIONS: if not skip_tests or not _IsTestFile(filename): with open(os.path.join(root, filename)) as f: for line in f: line = line.strip() if token_line_re.match(line): count += 1 return count def PrintUsage(): print "Usage: %s [--skip-tests] TOKEN_PATTERN DIRECTORY" % sys.argv[0] def main(): option_parser = optparse.OptionParser() option_parser.add_option('', '--skip-tests', action='store_true', dest='skip_tests', default=False, help='Skip test files.') options, args = option_parser.parse_args() if len(args) < 2: PrintUsage() return 1 else: print CountIfdefs(args[0], args[1], options.skip_tests) return 0 if __name__ == '__main__': sys.exit(main())