Skip to content

Commit ac63189

Browse files
Add module dependency check to CPP-LINT
To use it just put a module_dependencies.txt into a directory, which lists all modules that it is allowed to include header files from.
1 parent 9fe432b commit ac63189

File tree

1 file changed

+38
-6
lines changed

1 file changed

+38
-6
lines changed

scripts/cpplint.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4976,7 +4976,7 @@ def _ClassifyInclude(fileinfo, include, is_system):
49764976

49774977

49784978

4979-
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
4979+
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error, module_deps):
49804980
"""Check rules that are applicable to #include lines.
49814981
49824982
Strings on #include lines are NOT removed from elided line, to make
@@ -5024,6 +5024,21 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
50245024
elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
50255025
include_state.include_list[-1].append((include, linenum))
50265026

5027+
# Check module dependencies
5028+
module_name = os.path.dirname(filename)
5029+
has_src = module_name.find('src/')
5030+
if has_src >= 0:
5031+
module_name = module_name[has_src+4:]
5032+
deps_name = os.path.dirname(include)
5033+
if deps_name and module_deps:
5034+
found = False
5035+
for module in module_deps:
5036+
if deps_name.startswith(module):
5037+
found = True
5038+
if not found:
5039+
error(filename, linenum, 'build/include', 4,
5040+
'Module `'+module_name+'` must not use `'+include+'`')
5041+
50275042
# We want to ensure that headers appear in the right order:
50285043
# 1) for foo.cc, foo.h (preferred location)
50295044
# 2) c system files
@@ -5136,7 +5151,7 @@ def _GetTextInside(text, start_pattern):
51365151

51375152

51385153
def CheckLanguage(filename, clean_lines, linenum, file_extension,
5139-
include_state, nesting_state, error):
5154+
include_state, nesting_state, error, module_deps):
51405155
"""Checks rules from the 'C++ language rules' section of cppguide.html.
51415156
51425157
Some of these rules are hard to test (function overloading, using
@@ -5160,7 +5175,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
51605175

51615176
match = _RE_PATTERN_INCLUDE.search(line)
51625177
if match:
5163-
CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
5178+
CheckIncludeLine(filename, clean_lines, linenum, include_state, error, module_deps)
51645179
return
51655180

51665181
# Reset include state across preprocessor directives. This is meant
@@ -6241,7 +6256,7 @@ def CheckForEndl(filename, clean_lines, linenum, error):
62416256
error(filename, linenum, 'runtime/endl', 4, 'Do not use std::endl')
62426257

62436258
def ProcessLine(filename, file_extension, clean_lines, line,
6244-
include_state, function_state, nesting_state, error,
6259+
include_state, function_state, nesting_state, error, module_deps,
62456260
extra_check_functions=[]):
62466261
"""Processes a single line in the file.
62476262
@@ -6271,7 +6286,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
62716286
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
62726287
CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
62736288
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
6274-
nesting_state, error)
6289+
nesting_state, error, module_deps)
62756290
CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
62766291
CheckForNonStandardConstructs(filename, clean_lines, line,
62776292
nesting_state, error)
@@ -6365,6 +6380,23 @@ def ProcessFileData(filename, file_extension, lines, error,
63656380

63666381
ResetNolintSuppressions()
63676382

6383+
# Load module dependencies
6384+
module_deps_file = os.path.join(os.path.dirname(filename), 'module_dependencies.txt')
6385+
module_deps = []
6386+
if os.path.isfile(module_deps_file):
6387+
with open(module_deps_file, 'r') as f:
6388+
module_deps = f.read().splitlines()
6389+
# strip off comments and whitespace
6390+
def strip_off_comments(s):
6391+
has_comment = s.find('#')
6392+
if has_comment >= 0:
6393+
s = s[:has_comment]
6394+
s = s.lstrip().rstrip()
6395+
return s
6396+
module_deps = [ strip_off_comments(module) for module in module_deps]
6397+
# remove empty lines
6398+
module_deps = [ module for module in module_deps if module]
6399+
63686400
CheckForCopyright(filename, lines, error)
63696401
CheckForFunctionCommentHeaders(filename, lines, error)
63706402
ProcessGlobalSuppresions(lines)
@@ -6376,7 +6408,7 @@ def ProcessFileData(filename, file_extension, lines, error,
63766408

63776409
for line in xrange(clean_lines.NumLines()):
63786410
ProcessLine(filename, file_extension, clean_lines, line,
6379-
include_state, function_state, nesting_state, error,
6411+
include_state, function_state, nesting_state, error, module_deps,
63806412
extra_check_functions)
63816413
FlagCxx11Features(filename, clean_lines, line, error)
63826414
nesting_state.CheckCompletedBlocks(filename, error)

0 commit comments

Comments
 (0)