mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Alexander Thomas](/assets/img/avatar_default.png)
Some files in runtime/ are UTF-8 encoded, e.g.: runtime/vm/unicode_test.cc Change-Id: Ie71fd46fb66fe793742dbf8a6645b8402956ab77 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214381 Reviewed-by: Johnni Winther <johnniwinther@google.com>
132 lines
4.5 KiB
Python
Executable file
132 lines
4.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
|
# for details. All rights reserved. Use of this source code is governed by a
|
|
# BSD-style license that can be found in the LICENSE file.
|
|
|
|
# Simple tool for verifying that sources from one layer do not reference
|
|
# sources from another layer.
|
|
#
|
|
# Currently it only checks that core runtime headers RUNTIME_LAYER_HEADERS
|
|
# are not included into any sources listed in SHOULD_NOT_DEPEND_ON_RUNTIME.
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
INCLUDE_DIRECTIVE_RE = re.compile(r'^#include "(.*)"')
|
|
|
|
RUNTIME_LAYER_HEADERS = [
|
|
'runtime/vm/isolate.h',
|
|
'runtime/vm/object.h',
|
|
'runtime/vm/raw_object.h',
|
|
'runtime/vm/thread.h',
|
|
]
|
|
|
|
SHOULD_NOT_DEPEND_ON_RUNTIME = [
|
|
'runtime/vm/allocation.h',
|
|
'runtime/vm/growable_array.h',
|
|
]
|
|
|
|
|
|
class LayeringChecker(object):
|
|
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.worklist = set()
|
|
# Mapping from header to a set of files it is included into.
|
|
self.included_into = dict()
|
|
# Set of files that were parsed to avoid double parsing.
|
|
self.loaded = set()
|
|
# Mapping from headers to their layer.
|
|
self.file_layers = {file: 'runtime' for file in RUNTIME_LAYER_HEADERS}
|
|
|
|
def Check(self):
|
|
self.AddAllSourcesToWorklist(os.path.join(self.root, 'runtime/vm'))
|
|
self.BuildIncludesGraph()
|
|
errors = self.PropagateLayers()
|
|
errors += self.CheckNotInRuntime(SHOULD_NOT_DEPEND_ON_RUNTIME)
|
|
return errors
|
|
|
|
def CheckNotInRuntime(self, files):
|
|
"""Check that given files do not depend on runtime layer."""
|
|
errors = []
|
|
for file in files:
|
|
if not os.path.exists(os.path.join(self.root, file)):
|
|
errors.append('File %s does not exist.' % (file))
|
|
if self.file_layers.get(file) is not None:
|
|
errors.append(
|
|
'LAYERING ERROR: %s includes object.h or raw_object.h' %
|
|
(file))
|
|
return errors
|
|
|
|
def BuildIncludesGraph(self):
|
|
while self.worklist:
|
|
file = self.worklist.pop()
|
|
deps = self.ExtractIncludes(file)
|
|
self.loaded.add(file)
|
|
for d in deps:
|
|
if d not in self.included_into:
|
|
self.included_into[d] = set()
|
|
self.included_into[d].add(file)
|
|
if d not in self.loaded:
|
|
self.worklist.add(d)
|
|
|
|
def PropagateLayers(self):
|
|
"""Propagate layering information through include graph.
|
|
|
|
If A is in layer L and A is included into B then B is in layer L.
|
|
"""
|
|
errors = []
|
|
self.worklist = set(self.file_layers.keys())
|
|
while self.worklist:
|
|
file = self.worklist.pop()
|
|
if file not in self.included_into:
|
|
continue
|
|
file_layer = self.file_layers[file]
|
|
for tgt in self.included_into[file]:
|
|
if tgt in self.file_layers:
|
|
if self.file_layers[tgt] != file_layer:
|
|
errors.add(
|
|
'Layer mismatch: %s (%s) is included into %s (%s)' %
|
|
(file, file_layer, tgt, self.file_layers[tgt]))
|
|
self.file_layers[tgt] = file_layer
|
|
self.worklist.add(tgt)
|
|
return errors
|
|
|
|
def AddAllSourcesToWorklist(self, dir):
|
|
"""Add all *.cc and *.h files from dir recursively into worklist."""
|
|
for file in os.listdir(dir):
|
|
path = os.path.join(dir, file)
|
|
if os.path.isdir(path):
|
|
self.AddAllSourcesToWorklist(path)
|
|
elif path.endswith('.cc') or path.endswith('.h'):
|
|
self.worklist.add(os.path.relpath(path, self.root))
|
|
|
|
def ExtractIncludes(self, file):
|
|
"""Extract the list of includes from the given file."""
|
|
deps = set()
|
|
with open(os.path.join(self.root, file), encoding='utf-8') as file:
|
|
for line in file:
|
|
if line.startswith('namespace dart {'):
|
|
break
|
|
|
|
m = INCLUDE_DIRECTIVE_RE.match(line)
|
|
if m is not None:
|
|
header = os.path.join('runtime', m.group(1))
|
|
if os.path.isfile(os.path.join(self.root, header)):
|
|
deps.add(header)
|
|
return deps
|
|
|
|
|
|
def DoCheck(sdk_root):
|
|
"""Run layering check at the given root folder."""
|
|
return LayeringChecker(sdk_root).Check()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
errors = DoCheck('.')
|
|
print('\n'.join(errors))
|
|
if errors:
|
|
sys.exit(-1)
|