1
+ //! Checks that text between tags unchanged, emitting warning otherwise,
2
+ //! allowing asserting that code in different places over codebase is in sync.
3
+ //!
4
+ //! This works via hashing text between tags and saving hash in tidy.
5
+ //!
6
+ //! Usage:
7
+ //!
8
+ //! some.rs:
9
+ //! // tidy-ticket-foo
10
+ //! const FOO: usize = 42;
11
+ //! // tidy-ticket-foo
12
+ //!
13
+ //! some.sh:
14
+ //! # tidy-ticket-foo
15
+ //! export FOO=42
16
+ //! # tidy-ticket-foo
17
+ use md5:: { Digest , Md5 } ;
18
+ use std:: fs;
19
+ use std:: path:: Path ;
20
+
21
+ #[ cfg( test) ]
22
+ mod tests;
23
+
24
+ /// Return hash for source text between 2 tag occurrence,
25
+ /// ignoring lines where tag written
26
+ ///
27
+ /// Expecting:
28
+ /// tag is not multiline
29
+ /// source always have at least 2 occurrence of tag (>2 ignored)
30
+ fn span_hash ( source : & str , tag : & str , bad : & mut bool ) -> Result < String , ( ) > {
31
+ let start_idx = match source. find ( tag) {
32
+ Some ( idx) => idx,
33
+ None => return Err ( tidy_error ! ( bad, "tag {} should exist in provided text" , tag) ) ,
34
+ } ;
35
+ let end_idx = {
36
+ let end = match source[ start_idx + tag. len ( ) ..] . find ( tag) {
37
+ // index from source start
38
+ Some ( idx) => start_idx + tag. len ( ) + idx,
39
+ None => return Err ( tidy_error ! ( bad, "tag end {} should exist in provided text" , tag) ) ,
40
+ } ;
41
+ // second line with tag can contain some other text before tag, ignore it
42
+ // by finding position of previous line ending
43
+ //
44
+ // FIXME: what if line ending is \r\n? In that case \r will be hashed too
45
+ let offset = source[ start_idx..end] . rfind ( '\n' ) . unwrap ( ) ;
46
+ start_idx + offset
47
+ } ;
48
+
49
+ let mut hasher = Md5 :: new ( ) ;
50
+
51
+ source[ start_idx..end_idx]
52
+ . lines ( )
53
+ // skip first line with tag
54
+ . skip ( 1 )
55
+ // hash next lines, ignoring end trailing whitespaces
56
+ . for_each ( |line| {
57
+ let trimmed = line. trim_end ( ) ;
58
+ hasher. update ( trimmed) ;
59
+ } ) ;
60
+ Ok ( format ! ( "{:x}" , hasher. finalize( ) ) )
61
+ }
62
+
63
+ fn check_entry ( entry : & ListEntry < ' _ > , group_idx : usize , bad : & mut bool , root_path : & Path ) {
64
+ let file = fs:: read_to_string ( root_path. join ( Path :: new ( entry. 0 ) ) )
65
+ . unwrap_or_else ( |e| panic ! ( "{:?}, path: {}" , e, entry. 0 ) ) ;
66
+ let actual_hash = span_hash ( & file, entry. 2 , bad) . unwrap ( ) ;
67
+ if actual_hash != entry. 1 {
68
+ // Write tidy error description for wather only once.
69
+ // Will not work if there was previous errors of other types.
70
+ if * bad == false {
71
+ tidy_error ! (
72
+ bad,
73
+ "The code blocks tagged with tidy watcher has changed.\n \
74
+ It's likely that code blocks with the following tags need to be changed too. Check src/tools/tidy/src/watcher.rs, find tag/hash in TIDY_WATCH_LIST list \
75
+ and verify that sources for provided group of tags in sync. Once that done, run tidy again and update hashes in TIDY_WATCH_LIST with provided actual hashes."
76
+ )
77
+ }
78
+ tidy_error ! (
79
+ bad,
80
+ "hash for tag `{}` in path `{}` mismatch:\n actual: `{}`, expected: `{}`\n \
81
+ Verify that tags `{:?}` in sync.",
82
+ entry. 2 ,
83
+ entry. 0 ,
84
+ actual_hash,
85
+ entry. 1 ,
86
+ TIDY_WATCH_LIST [ group_idx] . iter( ) . map( |e| e. 2 ) . collect:: <Vec <& str >>( )
87
+ ) ;
88
+ }
89
+ }
90
+
91
+ macro_rules! add_group {
92
+ ( $( $entry: expr) ,* ) => {
93
+ & [ $( $entry) ,* ]
94
+ } ;
95
+ }
96
+
97
+ /// (path, hash, tag)
98
+ type ListEntry < ' a > = ( & ' a str , & ' a str , & ' a str ) ;
99
+
100
+ /// List of tags to watch, along with paths and hashes
101
+ #[ rustfmt:: skip]
102
+ const TIDY_WATCH_LIST : & [ & [ ListEntry < ' _ > ] ] = & [
103
+ // sync perf commit across dockerfile and opt-dist
104
+ add_group ! (
105
+ ( "src/tools/opt-dist/src/main.rs" , "f99844fda86216628167cd3391844ed1" , "tidy-ticket-perf-commit" ) ,
106
+ ( "src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile" , "fa9a88e552735e9f93934501e9c8d87a" , "tidy-ticket-perf-commit" )
107
+ ) ,
108
+
109
+ add_group ! (
110
+ ( "compiler/rustc_ast/src/token.rs" , "0f6ba78f1007a398f01cc6217838cadc" , "tidy-ticket-ast-from_token" ) ,
111
+ ( "compiler/rustc_ast/src/token.rs" , "9a78008a2377486eadf19d67ee4fdce2" , "tidy-ticket-ast-can_begin_literal_maybe_minus" ) ,
112
+ ( "compiler/rustc_parse/src/parser/expr.rs" , "500240cdc80690209060fdce10ce065a" , "tidy-ticket-rustc_parse-can_begin_literal_maybe_minus" )
113
+ ) ,
114
+
115
+ add_group ! (
116
+ ( "compiler/rustc_builtin_macros/src/assert/context.rs" , "de6cc928308947a05a373a355e036f68" , "tidy-ticket-all-expr-kinds" ) ,
117
+ ( "tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs" , "78ce54cc25baeac3ae07c876db25180c" , "tidy-ticket-all-expr-kinds" )
118
+ ) ,
119
+
120
+ add_group ! (
121
+ ( "compiler/rustc_const_eval/src/interpret/validity.rs" , "91c69e391741f64b7624e1bda4b31bc3" , "tidy-ticket-try_visit_primitive" ) ,
122
+ ( "compiler/rustc_const_eval/src/interpret/validity.rs" , "763a70aa04279a7b1cd184b75f79751d" , "tidy-ticket-visit_value" )
123
+ ) ,
124
+
125
+ // sync self-profile-events help mesage with actual list of events
126
+ add_group ! (
127
+ ( "compiler/rustc_data_structures/src/profiling.rs" , "881e7899c7d6904af1bc000594ee0418" , "tidy-ticket-self-profile-events" ) ,
128
+ ( "compiler/rustc_session/src/options.rs" , "012ee5a3b61ee1377744e5c6913fa00a" , "tidy-ticket-self-profile-events" )
129
+ ) ,
130
+
131
+ add_group ! (
132
+ ( "compiler/rustc_errors/src/json.rs" , "5907da5c0476785fe2aae4d0d62f7171" , "tidy-ticket-UnusedExterns" ) ,
133
+ ( "src/librustdoc/doctest.rs" , "b5bb5128abb4a2dbb47bb1a1a083ba9b" , "tidy-ticket-UnusedExterns" )
134
+ ) ,
135
+
136
+ add_group ! (
137
+ ( "compiler/rustc_middle/src/ty/util.rs" , "cae64b1bc854e7ee81894212facb5bfa" , "tidy-ticket-static_ptr_ty" ) ,
138
+ ( "compiler/rustc_middle/src/ty/util.rs" , "6f5ead08474b4d3e358db5d3c7aef970" , "tidy-ticket-thread_local_ptr_ty" )
139
+ ) ,
140
+
141
+ add_group ! (
142
+ ( "compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs" , "c17706947fc814aa5648972a5b3dc143" , "tidy-ticket-arity" ) ,
143
+ ( "compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs" , "7ce77b84c142c22530b047703ef209f0" , "tidy-ticket-wildcards" )
144
+ ) ,
145
+
146
+ add_group ! (
147
+ ( "compiler/rustc_monomorphize/src/partitioning.rs" , "f4f33e9c14f4e0c3a20b5240ae36a7c8" , "tidy-ticket-short_description" ) ,
148
+ ( "compiler/rustc_codegen_ssa/src/back/write.rs" , "5286f7f76fcf564c98d7a8eaeec39b18" , "tidy-ticket-short_description" )
149
+ ) ,
150
+
151
+ add_group ! (
152
+ ( "compiler/rustc_session/src/config/sigpipe.rs" , "8d765a5c613d931852c0f59ed1997dcd" , "tidy-ticket-sigpipe" ) ,
153
+ ( "library/std/src/sys/unix/mod.rs" , "2cdc37081831cdcf44f3331efbe440af" , "tidy-ticket-sigpipe" )
154
+ ) ,
155
+
156
+ add_group ! (
157
+ ( "compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs" , "6b4ce7c9aa0e799618d53926fb3e9684" , "tidy-ticket-extract_tupled_inputs_and_output_from_callable" ) ,
158
+ ( "compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs" , "f1085622f189fc5ec2786e4abff67915" , "tidy-ticket-assemble_fn_pointer_candidates" )
159
+ ) ,
160
+
161
+ add_group ! (
162
+ ( "compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs" , "d0c807d90501f3f63dffc3e7ec046c20" , "tidy-ticket-rematch_unsize" ) ,
163
+ ( "compiler/rustc_trait_selection/src/solve/trait_goals.rs" , "f1b0ce28128b5d5a5b545af3f3cf55f4" , "tidy-ticket-consider_builtin_unsize_candidate" )
164
+ ) ,
165
+
166
+ add_group ! (
167
+ ( "compiler/rustc_trait_selection/src/traits/project.rs" , "66585f93352fe56a5be6cc5a63bcc756" , "tidy-ticket-assemble_candidates_from_impls-UserDefined" ) ,
168
+ ( "compiler/rustc_ty_utils/src/instance.rs" , "5ad30b96493636ba3357448f0b0a4d76" , "tidy-ticket-resolve_associated_item-UserDefined" )
169
+ ) ,
170
+
171
+ add_group ! (
172
+ ( "compiler/rustc_hir_analysis/src/lib.rs" , "842e23fb65caf3a96681686131093316" , "tidy-ticket-sess-time-item_types_checking" ) ,
173
+ ( "src/librustdoc/core.rs" , "85d9dd0cbb94fd521e2d15a8ed38a75f" , "tidy-ticket-sess-time-item_types_checking" )
174
+ ) ,
175
+
176
+ add_group ! (
177
+ ( "library/core/src/ptr/metadata.rs" , "57fc0e05c177c042c9766cc1134ae240" , "tidy-ticket-static_assert_expected_bounds_for_metadata" ) ,
178
+ ( "library/core/tests/ptr.rs" , "13ecb32e2a0db0998ff94f33a30f5cfd" , "tidy-ticket-static_assert_expected_bounds_for_metadata" )
179
+ ) ,
180
+ ] ;
181
+
182
+ pub fn check ( root_path : & Path , bad : & mut bool ) {
183
+ for ( group_idx, group) in TIDY_WATCH_LIST . iter ( ) . enumerate ( ) {
184
+ for entry in group. iter ( ) {
185
+ check_entry ( entry, group_idx, bad, root_path) ;
186
+ }
187
+ }
188
+ }
0 commit comments