#!/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())