| 
 | 1 | +#!/usr/bin/env python3  | 
 | 2 | +# Rust is fairly relaxed in checking the validity of arguments passed to #[cfg].  | 
 | 3 | +# While it should probably be more strict when checking features, it cannot be  | 
 | 4 | +# strict when checking loose cfg tags, because those can be anything and are  | 
 | 5 | +# simply passed to rustc via unconstrained arguments.  | 
 | 6 | +#  | 
 | 7 | +# Thus, we do it for rustc manually, but scanning all our source and checking  | 
 | 8 | +# that all our cfg tags match a known cfg tag.  | 
 | 9 | +import sys, glob, re  | 
 | 10 | + | 
 | 11 | +def check_feature(feature):  | 
 | 12 | +    if feature == "std":  | 
 | 13 | +        pass  | 
 | 14 | +    elif feature == "no-std":  | 
 | 15 | +        pass  | 
 | 16 | +    elif feature == "hashbrown":  | 
 | 17 | +        pass  | 
 | 18 | +    elif feature == "backtrace":  | 
 | 19 | +        pass  | 
 | 20 | +    elif feature == "grind_signatures":  | 
 | 21 | +        pass  | 
 | 22 | +    elif feature == "unsafe_revoked_tx_signing":  | 
 | 23 | +        pass  | 
 | 24 | +    elif feature == "futures":  | 
 | 25 | +        pass  | 
 | 26 | +    elif feature == "tokio":  | 
 | 27 | +        pass  | 
 | 28 | +    elif feature == "rest-client":  | 
 | 29 | +        pass  | 
 | 30 | +    elif feature == "rpc-client":  | 
 | 31 | +        pass  | 
 | 32 | +    elif feature == "serde":  | 
 | 33 | +        pass  | 
 | 34 | +    elif feature == "esplora-blocking":  | 
 | 35 | +        pass  | 
 | 36 | +    elif feature == "esplora-async":  | 
 | 37 | +        pass  | 
 | 38 | +    elif feature == "async-interface":  | 
 | 39 | +        pass  | 
 | 40 | +    elif feature == "electrum":  | 
 | 41 | +        pass  | 
 | 42 | +    elif feature == "_test_utils":  | 
 | 43 | +        pass  | 
 | 44 | +    elif feature == "_test_vectors":  | 
 | 45 | +        pass  | 
 | 46 | +    elif feature == "afl":  | 
 | 47 | +        pass  | 
 | 48 | +    elif feature == "honggfuzz":  | 
 | 49 | +        pass  | 
 | 50 | +    elif feature == "libfuzzer_fuzz":  | 
 | 51 | +        pass  | 
 | 52 | +    elif feature == "stdin_fuzz":  | 
 | 53 | +        pass  | 
 | 54 | +    elif feature == "max_level_off":  | 
 | 55 | +        pass  | 
 | 56 | +    elif feature == "max_level_error":  | 
 | 57 | +        pass  | 
 | 58 | +    elif feature == "max_level_warn":  | 
 | 59 | +        pass  | 
 | 60 | +    elif feature == "max_level_info":  | 
 | 61 | +        pass  | 
 | 62 | +    elif feature == "max_level_debug":  | 
 | 63 | +        pass  | 
 | 64 | +    elif feature == "max_level_trace":  | 
 | 65 | +        pass  | 
 | 66 | +    else:  | 
 | 67 | +        print("Bad feature: " + feature)  | 
 | 68 | +        assert False  | 
 | 69 | + | 
 | 70 | +def check_target_os(os):  | 
 | 71 | +    if os == "windows":  | 
 | 72 | +        pass  | 
 | 73 | +    else:  | 
 | 74 | +        assert False  | 
 | 75 | + | 
 | 76 | +def check_cfg_tag(cfg):  | 
 | 77 | +    if cfg == "fuzzing":  | 
 | 78 | +        pass  | 
 | 79 | +    elif cfg == "test":  | 
 | 80 | +        pass  | 
 | 81 | +    elif cfg == "debug_assertions":  | 
 | 82 | +        pass  | 
 | 83 | +    elif cfg == "c_bindings":  | 
 | 84 | +        pass  | 
 | 85 | +    elif cfg == "ldk_bench":  | 
 | 86 | +        pass  | 
 | 87 | +    elif cfg == "taproot":  | 
 | 88 | +        pass  | 
 | 89 | +    elif cfg == "require_route_graph_test":  | 
 | 90 | +        pass  | 
 | 91 | +    else:  | 
 | 92 | +        print("Bad cfg tag: " + cfg)  | 
 | 93 | +        assert False  | 
 | 94 | + | 
 | 95 | +def check_cfg_args(cfg):  | 
 | 96 | +    if cfg.startswith("all(") or cfg.startswith("any(") or cfg.startswith("not("):  | 
 | 97 | +        brackets = 1  | 
 | 98 | +        pos = 4  | 
 | 99 | +        while pos < len(cfg):  | 
 | 100 | +            if cfg[pos] == "(":  | 
 | 101 | +                brackets += 1  | 
 | 102 | +            elif cfg[pos] == ")":  | 
 | 103 | +                brackets -= 1  | 
 | 104 | +                if brackets == 0:  | 
 | 105 | +                    check_cfg_args(cfg[4:pos])  | 
 | 106 | +                    if pos + 1 != len(cfg):  | 
 | 107 | +                        assert cfg[pos + 1] == ","  | 
 | 108 | +                        check_cfg_args(cfg[pos + 2:].strip())  | 
 | 109 | +                    return  | 
 | 110 | +            pos += 1  | 
 | 111 | +        assert False  | 
 | 112 | +        assert(cfg.endswith(")"))  | 
 | 113 | +        check_cfg_args(cfg[4:len(cfg)-1])  | 
 | 114 | +    else:  | 
 | 115 | +        parts = [part.strip() for part in cfg.split(",", 1)]  | 
 | 116 | +        if len(parts) > 1:  | 
 | 117 | +            for part in parts:  | 
 | 118 | +                check_cfg_args(part)  | 
 | 119 | +        elif cfg.startswith("feature") or cfg.startswith("target_os") or cfg.startswith("target_pointer_width"):  | 
 | 120 | +            arg = cfg  | 
 | 121 | +            if cfg.startswith("feature"):  | 
 | 122 | +                arg = arg[7:].strip()  | 
 | 123 | +            elif cfg.startswith("target_os"):  | 
 | 124 | +                arg = arg[9:].strip()  | 
 | 125 | +            else:  | 
 | 126 | +                arg = arg[20:].strip()  | 
 | 127 | +            assert arg.startswith("=")  | 
 | 128 | +            arg = arg[1:].strip()  | 
 | 129 | +            assert arg.startswith("\"")  | 
 | 130 | +            assert arg.endswith("\"")  | 
 | 131 | +            arg = arg[1:len(arg)-1]  | 
 | 132 | +            assert not "\"" in arg  | 
 | 133 | +            if cfg.startswith("feature"):  | 
 | 134 | +                check_feature(arg)  | 
 | 135 | +            elif cfg.startswith("target_os"):  | 
 | 136 | +                check_target_os(arg)  | 
 | 137 | +            else:  | 
 | 138 | +                assert arg == "32" or arg == "64"  | 
 | 139 | +        else:  | 
 | 140 | +            check_cfg_tag(cfg.strip())  | 
 | 141 | + | 
 | 142 | +cfg_regex = re.compile("#\[cfg\((.*)\)\]")  | 
 | 143 | +for path in glob.glob(sys.path[0] + "/../**/*.rs", recursive = True):  | 
 | 144 | +    with open(path, "r") as file:  | 
 | 145 | +        while True:  | 
 | 146 | +            line = file.readline()  | 
 | 147 | +            if not line:  | 
 | 148 | +                break  | 
 | 149 | +            if "#[cfg(" in line:  | 
 | 150 | +                if not line.strip().startswith("//"):  | 
 | 151 | +                    cfg_part = cfg_regex.match(line.strip()).group(1)  | 
 | 152 | +                    check_cfg_args(cfg_part)  | 
0 commit comments