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