xref: /aosp_15_r20/external/grpc-grpc/tools/distrib/check_naked_includes.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cc02d7e2SAndroid Build Coastguard Worker
3*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2022 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker#
5*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker#
11*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker
17*cc02d7e2SAndroid Build Coastguard Worker# Check for includes of the form `#include "bar.h"` - i.e. not including the subdirectory. We require instead `#include "foo/bar.h"`.
18*cc02d7e2SAndroid Build Coastguard Worker
19*cc02d7e2SAndroid Build Coastguard Workerimport argparse
20*cc02d7e2SAndroid Build Coastguard Workerimport os
21*cc02d7e2SAndroid Build Coastguard Workerimport re
22*cc02d7e2SAndroid Build Coastguard Workerimport sys
23*cc02d7e2SAndroid Build Coastguard Worker
24*cc02d7e2SAndroid Build Coastguard Worker# find our home
25*cc02d7e2SAndroid Build Coastguard WorkerROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../.."))
26*cc02d7e2SAndroid Build Coastguard Workeros.chdir(ROOT)
27*cc02d7e2SAndroid Build Coastguard Worker
28*cc02d7e2SAndroid Build Coastguard Worker# parse command line
29*cc02d7e2SAndroid Build Coastguard Workerargp = argparse.ArgumentParser(description="include guard checker")
30*cc02d7e2SAndroid Build Coastguard Workerargp.add_argument("-f", "--fix", default=False, action="store_true")
31*cc02d7e2SAndroid Build Coastguard Workerargs = argp.parse_args()
32*cc02d7e2SAndroid Build Coastguard Worker
33*cc02d7e2SAndroid Build Coastguard Worker# error count
34*cc02d7e2SAndroid Build Coastguard Workererrors = 0
35*cc02d7e2SAndroid Build Coastguard Worker
36*cc02d7e2SAndroid Build Coastguard WorkerCHECK_SUBDIRS = [
37*cc02d7e2SAndroid Build Coastguard Worker    "src/core",
38*cc02d7e2SAndroid Build Coastguard Worker    "src/cpp",
39*cc02d7e2SAndroid Build Coastguard Worker    "test/core",
40*cc02d7e2SAndroid Build Coastguard Worker    "test/cpp",
41*cc02d7e2SAndroid Build Coastguard Worker    "fuzztest",
42*cc02d7e2SAndroid Build Coastguard Worker]
43*cc02d7e2SAndroid Build Coastguard Worker
44*cc02d7e2SAndroid Build Coastguard Workerfor subdir in CHECK_SUBDIRS:
45*cc02d7e2SAndroid Build Coastguard Worker    for root, dirs, files in os.walk(subdir):
46*cc02d7e2SAndroid Build Coastguard Worker        for f in files:
47*cc02d7e2SAndroid Build Coastguard Worker            if f.endswith(".h") or f.endswith(".cc"):
48*cc02d7e2SAndroid Build Coastguard Worker                fpath = os.path.join(root, f)
49*cc02d7e2SAndroid Build Coastguard Worker                output = open(fpath, "r").readlines()
50*cc02d7e2SAndroid Build Coastguard Worker                changed = False
51*cc02d7e2SAndroid Build Coastguard Worker                for i, line in enumerate(output):
52*cc02d7e2SAndroid Build Coastguard Worker                    m = re.match(r'^#include "([^"]*)"(.*)', line)
53*cc02d7e2SAndroid Build Coastguard Worker                    if not m:
54*cc02d7e2SAndroid Build Coastguard Worker                        continue
55*cc02d7e2SAndroid Build Coastguard Worker                    include = m.group(1)
56*cc02d7e2SAndroid Build Coastguard Worker                    if "/" in include:
57*cc02d7e2SAndroid Build Coastguard Worker                        continue
58*cc02d7e2SAndroid Build Coastguard Worker                    expect_path = os.path.join(root, include)
59*cc02d7e2SAndroid Build Coastguard Worker                    trailing = m.group(2)
60*cc02d7e2SAndroid Build Coastguard Worker                    if not os.path.exists(expect_path):
61*cc02d7e2SAndroid Build Coastguard Worker                        continue
62*cc02d7e2SAndroid Build Coastguard Worker                    changed = True
63*cc02d7e2SAndroid Build Coastguard Worker                    errors += 1
64*cc02d7e2SAndroid Build Coastguard Worker                    output[i] = '#include "{0}"{1}\n'.format(
65*cc02d7e2SAndroid Build Coastguard Worker                        expect_path, trailing
66*cc02d7e2SAndroid Build Coastguard Worker                    )
67*cc02d7e2SAndroid Build Coastguard Worker                    print(
68*cc02d7e2SAndroid Build Coastguard Worker                        "Found naked include '{0}' in {1}".format(
69*cc02d7e2SAndroid Build Coastguard Worker                            include, fpath
70*cc02d7e2SAndroid Build Coastguard Worker                        )
71*cc02d7e2SAndroid Build Coastguard Worker                    )
72*cc02d7e2SAndroid Build Coastguard Worker                if changed and args.fix:
73*cc02d7e2SAndroid Build Coastguard Worker                    open(fpath, "w").writelines(output)
74*cc02d7e2SAndroid Build Coastguard Worker
75*cc02d7e2SAndroid Build Coastguard Workerif errors > 0:
76*cc02d7e2SAndroid Build Coastguard Worker    print("{} errors found.".format(errors))
77*cc02d7e2SAndroid Build Coastguard Worker    sys.exit(1)
78