Skip to content

Commit a90ea44

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 a90ea44

File tree

1 file changed

+39
-6
lines changed

1 file changed

+39
-6
lines changed

scripts/cpplint.py

+39-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,18 @@ 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+
may_use = any(deps_name.startswith(module) for module in module_deps)
5040+
if not may_use:
5041+
error(filename, linenum, 'build/include', 4,
5042+
'Module `'+module_name+'` must not use `'+include+'`')
5043+
50325044
# We want to ensure that headers appear in the right order:
50335045
# 1) for foo.cc, foo.h (preferred location)
50345046
# 2) c system files
@@ -5141,7 +5153,7 @@ def _GetTextInside(text, start_pattern):
51415153

51425154

51435155
def CheckLanguage(filename, clean_lines, linenum, file_extension,
5144-
include_state, nesting_state, error):
5156+
include_state, nesting_state, error, module_deps):
51455157
"""Checks rules from the 'C++ language rules' section of cppguide.html.
51465158
51475159
Some of these rules are hard to test (function overloading, using
@@ -5165,7 +5177,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
51655177

51665178
match = _RE_PATTERN_INCLUDE.search(line)
51675179
if match:
5168-
CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
5180+
CheckIncludeLine(filename, clean_lines, linenum, include_state, error, module_deps)
51695181
return
51705182

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

62486260
def ProcessLine(filename, file_extension, clean_lines, line,
6249-
include_state, function_state, nesting_state, error,
6261+
include_state, function_state, nesting_state, error, module_deps,
62506262
extra_check_functions=[]):
62516263
"""Processes a single line in the file.
62526264
@@ -6276,7 +6288,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
62766288
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
62776289
CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
62786290
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
6279-
nesting_state, error)
6291+
nesting_state, error, module_deps)
62806292
CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
62816293
CheckForNonStandardConstructs(filename, clean_lines, line,
62826294
nesting_state, error)
@@ -6370,6 +6382,27 @@ def ProcessFileData(filename, file_extension, lines, error,
63706382

63716383
ResetNolintSuppressions()
63726384

6385+
# Load module dependencies
6386+
module_deps_file = os.path.join(os.path.dirname(filename), 'module_dependencies.txt')
6387+
module_deps = []
6388+
if os.path.isfile(module_deps_file):
6389+
with open(module_deps_file, 'r') as f:
6390+
module_deps = f.read().splitlines()
6391+
# strip off comments and whitespace
6392+
def strip_off_comments(s):
6393+
comment_index = s.find('#')
6394+
if comment_index >= 0:
6395+
s = s[:comment_index]
6396+
s = s.strip()
6397+
return s
6398+
module_deps = [strip_off_comments(module) for module in module_deps]
6399+
# remove empty lines
6400+
module_deps = [module for module in module_deps if len(module) != 0]
6401+
else:
6402+
error(filename, 0, 'build/include', 4,
6403+
'module_dependencies.txt not found in `' +
6404+
os.path.dirname(filename) + '`')
6405+
63736406
CheckForCopyright(filename, lines, error)
63746407
CheckForFunctionCommentHeaders(filename, lines, error)
63756408
ProcessGlobalSuppresions(lines)
@@ -6381,7 +6414,7 @@ def ProcessFileData(filename, file_extension, lines, error,
63816414

63826415
for line in xrange(clean_lines.NumLines()):
63836416
ProcessLine(filename, file_extension, clean_lines, line,
6384-
include_state, function_state, nesting_state, error,
6417+
include_state, function_state, nesting_state, error, module_deps,
63856418
extra_check_functions)
63866419
FlagCxx11Features(filename, clean_lines, line, error)
63876420
nesting_state.CheckCompletedBlocks(filename, error)

0 commit comments

Comments
 (0)