Skip to content

Commit a26f953

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 88f8cfc commit a26f953

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

scripts/cpplint.py

+42-6
Original file line numberDiff line numberDiff line change
@@ -4981,7 +4981,7 @@ def _ClassifyInclude(fileinfo, include, is_system):
49814981

49824982

49834983

4984-
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
4984+
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error, module_deps):
49854985
"""Check rules that are applicable to #include lines.
49864986
49874987
Strings on #include lines are NOT removed from elided line, to make
@@ -5029,6 +5029,21 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
50295029
elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
50305030
include_state.include_list[-1].append((include, linenum))
50315031

5032+
# Check module dependencies
5033+
module_name = os.path.dirname(filename)
5034+
has_src = module_name.find('src/')
5035+
if has_src >= 0:
5036+
module_name = module_name[has_src+4:]
5037+
deps_name = os.path.dirname(include)
5038+
if deps_name and module_deps:
5039+
found = False
5040+
for module in module_deps:
5041+
if deps_name.startswith(module):
5042+
found = True
5043+
if not found:
5044+
error(filename, linenum, 'build/include', 4,
5045+
'Module `'+module_name+'` must not use `'+include+'`')
5046+
50325047
# We want to ensure that headers appear in the right order:
50335048
# 1) for foo.cc, foo.h (preferred location)
50345049
# 2) c system files
@@ -5141,7 +5156,7 @@ def _GetTextInside(text, start_pattern):
51415156

51425157

51435158
def CheckLanguage(filename, clean_lines, linenum, file_extension,
5144-
include_state, nesting_state, error):
5159+
include_state, nesting_state, error, module_deps):
51455160
"""Checks rules from the 'C++ language rules' section of cppguide.html.
51465161
51475162
Some of these rules are hard to test (function overloading, using
@@ -5165,7 +5180,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
51655180

51665181
match = _RE_PATTERN_INCLUDE.search(line)
51675182
if match:
5168-
CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
5183+
CheckIncludeLine(filename, clean_lines, linenum, include_state, error, module_deps)
51695184
return
51705185

51715186
# Reset include state across preprocessor directives. This is meant
@@ -6246,7 +6261,7 @@ def CheckForEndl(filename, clean_lines, linenum, error):
62466261
error(filename, linenum, 'runtime/endl', 4, 'Do not use std::endl')
62476262

62486263
def ProcessLine(filename, file_extension, clean_lines, line,
6249-
include_state, function_state, nesting_state, error,
6264+
include_state, function_state, nesting_state, error, module_deps,
62506265
extra_check_functions=[]):
62516266
"""Processes a single line in the file.
62526267
@@ -6276,7 +6291,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
62766291
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
62776292
CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
62786293
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
6279-
nesting_state, error)
6294+
nesting_state, error, module_deps)
62806295
CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
62816296
CheckForNonStandardConstructs(filename, clean_lines, line,
62826297
nesting_state, error)
@@ -6370,6 +6385,27 @@ def ProcessFileData(filename, file_extension, lines, error,
63706385

63716386
ResetNolintSuppressions()
63726387

6388+
# Load module dependencies
6389+
module_deps_file = os.path.join(os.path.dirname(filename), 'module_dependencies.txt')
6390+
module_deps = []
6391+
if os.path.isfile(module_deps_file):
6392+
with open(module_deps_file, 'r') as f:
6393+
module_deps = f.read().splitlines()
6394+
# strip off comments and whitespace
6395+
def strip_off_comments(s):
6396+
has_comment = s.find('#')
6397+
if has_comment >= 0:
6398+
s = s[:has_comment]
6399+
s = s.lstrip().rstrip()
6400+
return s
6401+
module_deps = [ strip_off_comments(module) for module in module_deps]
6402+
# remove empty lines
6403+
module_deps = [ module for module in module_deps if module]
6404+
else:
6405+
error(filename, 0, 'build/include', 4,
6406+
'module_dependencies.txt not found in `' +
6407+
os.path.dirname(filename) + '`')
6408+
63736409
CheckForCopyright(filename, lines, error)
63746410
CheckForFunctionCommentHeaders(filename, lines, error)
63756411
ProcessGlobalSuppresions(lines)
@@ -6381,7 +6417,7 @@ def ProcessFileData(filename, file_extension, lines, error,
63816417

63826418
for line in xrange(clean_lines.NumLines()):
63836419
ProcessLine(filename, file_extension, clean_lines, line,
6384-
include_state, function_state, nesting_state, error,
6420+
include_state, function_state, nesting_state, error, module_deps,
63856421
extra_check_functions)
63866422
FlagCxx11Features(filename, clean_lines, line, error)
63876423
nesting_state.CheckCompletedBlocks(filename, error)

0 commit comments

Comments
 (0)