summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/code_analysis/utils.py
blob: e3931aa7e4eba669b22ec632d8e610e3528c8a05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import logging

import mozpack.path as mozpath
import yaml

from mozbuild.util import memoized_property


class ClangTidyConfig(object):
    def __init__(self, mozilla_src):
        self._clang_tidy_config = self._get_clang_tidy_config(mozilla_src)

    def _get_clang_tidy_config(self, mozilla_src):
        try:
            file_handler = open(
                mozpath.join(mozilla_src, "tools", "clang-tidy", "config.yaml")
            )
            config = yaml.safe_load(file_handler)
        except Exception:
            self.log(
                logging.ERROR,
                "clang-tidy-config",
                {},
                "Looks like config.yaml is not valid, we are going to use default"
                " values for the rest of the analysis for clang-tidy.",
            )
            return None
        return config

    @memoized_property
    def checks(self):
        """
        Returns a list with all activated checks
        """

        checks = ["-*"]
        try:
            config = self._clang_tidy_config
            for item in config["clang_checkers"]:
                if item.get("publish", True):
                    checks.append(item["name"])
        except Exception:
            self.log(
                logging.ERROR,
                "clang-tidy-config",
                {},
                "Looks like config.yaml is not valid, so we are unable to "
                "determine default checkers, using '-checks=-*,mozilla-*'",
            )
            checks.append("mozilla-*")
        finally:
            return checks

    @memoized_property
    def checks_with_data(self):
        """
        Returns a list with all activated checks plus metadata for each check
        """

        checks_with_data = [{"name": "-*"}]
        try:
            config = self._clang_tidy_config
            for item in config["clang_checkers"]:
                if item.get("publish", True):
                    checks_with_data.append(item)
        except Exception:
            self.log(
                logging.ERROR,
                "clang-tidy-config",
                {},
                "Looks like config.yaml is not valid, so we are unable to "
                "determine default checkers, using '-checks=-*,mozilla-*'",
            )
            checks_with_data.append({"name": "mozilla-*", "reliability": "high"})
        finally:
            return checks_with_data

    @memoized_property
    def checks_config(self):
        """
        Returns the configuation for all checks
        """

        config_list = []
        checks_config = {}
        try:
            config = self._clang_tidy_config
            for checker in config["clang_checkers"]:
                if checker.get("publish", True) and "config" in checker:
                    for checker_option in checker["config"]:
                        # Verify if the format of the Option is correct,
                        # possibilities are:
                        # 1. CheckerName.Option
                        # 2. Option -> that will become CheckerName.Option
                        if not checker_option["key"].startswith(checker["name"]):
                            checker_option["key"] = "{}.{}".format(
                                checker["name"], checker_option["key"]
                            )
                    config_list += checker["config"]
            checks_config["CheckOptions"] = config_list
        except Exception:
            self.log(
                logging.ERROR,
                "clang-tidy-config",
                {},
                "Looks like config.yaml is not valid, so we are unable to "
                "determine configuration for checkers, so using default",
            )
            checks_config = None
        finally:
            return checks_config

    @memoized_property
    def version(self):
        """
        Returns version of clang-tidy suitable for this configuration file
        """

        if "package_version" in self._clang_tidy_config:
            return self._clang_tidy_config["package_version"]
        self.log(
            logging.ERROR,
            "clang-tidy-confis",
            {},
            "Unable to find 'package_version' in the config.yml",
        )
        return None

    @memoized_property
    def platforms(self):
        """
        Returns a list of platforms suitable to work with `clang-tidy`
        """
        return self._clang_tidy_config.get("platforms", [])