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