1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 """Counts the number of #if or #ifdef lines containing at least one 7 preprocessor token that is a full match for the given pattern, in the 8 given directory. 9 """ 10 11 12 import optparse 13 import os 14 import re 15 import sys 16 17 18 # Filename extensions we know will be handled by the C preprocessor. 19 # We ignore files not matching these. 20 CPP_EXTENSIONS = [ 21 '.h', 22 '.cc', 23 '.m', 24 '.mm', 25 ] 26 27 28 def _IsTestFile(filename): 29 """Does a rudimentary check to try to skip test files; this could be 30 improved but is good enough for basic metrics generation. 31 """ 32 return re.match('(test|mock|dummy)_.*|.*_[a-z]*test\.(h|cc|mm)', filename) 33 34 35 def CountIfdefs(token_pattern, directory, skip_tests=False): 36 """Returns the number of lines in files in |directory| and its 37 subdirectories that have an extension from |CPP_EXTENSIONS| and are 38 an #if or #ifdef line with a preprocessor token fully matching 39 the string |token_pattern|. 40 41 If |skip_tests| is true, a best effort is made to ignore test files. 42 """ 43 token_line_re = re.compile(r'^#if(def)?.*\b(%s)\b.*$' % token_pattern) 44 count = 0 45 for root, dirs, files in os.walk(directory): 46 for filename in files: 47 if os.path.splitext(filename)[1] in CPP_EXTENSIONS: 48 if not skip_tests or not _IsTestFile(filename): 49 with open(os.path.join(root, filename)) as f: 50 for line in f: 51 line = line.strip() 52 if token_line_re.match(line): 53 count += 1 54 return count 55 56 57 def PrintUsage(): 58 print "Usage: %s [--skip-tests] TOKEN_PATTERN DIRECTORY" % sys.argv[0] 59 60 61 def main(): 62 option_parser = optparse.OptionParser() 63 option_parser.add_option('', '--skip-tests', action='store_true', 64 dest='skip_tests', default=False, 65 help='Skip test files.') 66 options, args = option_parser.parse_args() 67 68 if len(args) < 2: 69 PrintUsage() 70 return 1 71 else: 72 print CountIfdefs(args[0], args[1], options.skip_tests) 73 return 0 74 75 76 if __name__ == '__main__': 77 sys.exit(main()) 78