15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Counts the number of #if or #ifdef lines containing at least one 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)preprocessor token that is a full match for the given pattern, in the 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)given directory. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Filename extensions we know will be handled by the C preprocessor. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We ignore files not matching these. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CPP_EXTENSIONS = [ 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '.h', 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '.cc', 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '.m', 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '.mm', 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)] 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _IsTestFile(filename): 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Does a rudimentary check to try to skip test files; this could be 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) improved but is good enough for basic metrics generation. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return re.match('(test|mock|dummy)_.*|.*_[a-z]*test\.(h|cc|mm)', filename) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CountIfdefs(token_pattern, directory, skip_tests=False): 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns the number of lines in files in |directory| and its 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subdirectories that have an extension from |CPP_EXTENSIONS| and are 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) an #if or #ifdef line with a preprocessor token fully matching 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the string |token_pattern|. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If |skip_tests| is true, a best effort is made to ignore test files. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) token_line_re = re.compile(r'^#if(def)?.*\b(%s)\b.*$' % token_pattern) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count = 0 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for root, dirs, files in os.walk(directory): 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for filename in files: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.splitext(filename)[1] in CPP_EXTENSIONS: 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not skip_tests or not _IsTestFile(filename): 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) with open(os.path.join(root, filename)) as f: 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in f: 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.strip() 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if token_line_re.match(line): 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count += 1 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def PrintUsage(): 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Usage: %s [--skip-tests] TOKEN_PATTERN DIRECTORY" % sys.argv[0] 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(): 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) option_parser = optparse.OptionParser() 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) option_parser.add_option('', '--skip-tests', action='store_true', 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest='skip_tests', default=False, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) help='Skip test files.') 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options, args = option_parser.parse_args() 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(args) < 2: 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrintUsage() 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print CountIfdefs(args[0], args[1], options.skip_tests) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main()) 78