Den Graphen navigieren
Die Navigationsbefehle beantworten Beziehungsfragen direkt aus dem typisierten Symbolgraphen. Du übergibst den Symbolnamen, ohne ihn vorher zu suchen.
greppy who-calls visit_content_map # wer ruft diese Funktion auf
greppy callees deserialize_body # was sie aufruft
greppy brief expand_derive_deserialize # was sie tut, ihr Körper skizziert, ihre Aufrufer
greppy impact Ctxt::error_spanned_by # was bricht, wenn ich sie ändere
greppy path --from derive_deserialize --to deserialize_body # jede Aufrufkette zwischen zwei Symbolen
Alle Beispiele auf dieser Seite laufen auf serde 1.0.229.
Symbole und Ergebnisse
Ein Symbol ist eine Funktion, eine Methode, eine Klasse oder ein Typ. Ist ein Name mehrfach definiert, listet der Befehl die Definitionen statt einer Antwort und endet mit Exit-Code 1:
$ greppy who-calls from_ast
`from_ast` is 2 definitions
serde_derive/src/internals/ast.rs:62
serde_derive/src/internals/attr.rs:237
Qualifiziere den Namen mit seiner Datei, relativ zur Repository-Wurzel:
$ greppy who-calls serde_derive/src/internals/ast.rs::from_ast
serde_derive/src/de.rs:29 expand_derive_deserialize
serde_derive/src/ser.rs:17 expand_derive_serialize
Typ::methode und die voll qualifizierten Namen, die andere Befehle ausgeben, nimmt greppy ebenso an. greppy who-calls Field::from_ast und greppy who-calls serde_derive/src/internals/attr.rs::Field::from_ast liefern dieselbe Antwort, serde_derive/src/internals/ast.rs:212 fields_from_ast.
Eine Ergebniszeile hat die Form datei:zeile name. Ein angehängtes test markiert ein Ergebnis, das in einem Test liegt. Ein Satz nach einem Gedankenstrich ist ein generierter Navigationshinweis, kein Quelltext.
who-calls
who-calls findet jede Stelle, die das Symbol nutzt: Aufrufe, Importe und Typreferenzen, aus eingehenden CALLS- und USAGE-Kanten. Eine lange Antwort beginnt mit der Anzahl pro Datei und zeigt die ersten Zeilen:
$ greppy who-calls Ctxt::error_spanned_by
27 callers: serde_derive/src/ser.rs 1, serde_derive/src/de.rs 2, serde_derive/src/internals/ast.rs 2, serde_derive/src/internals/check.rs 10, serde_derive/src/internals/attr.rs 12
serde_derive/src/ser.rs:73 precondition
serde_derive/src/de.rs:93 precondition_sized
serde_derive/src/de.rs:106 precondition_no_de_lifetime
serde_derive/src/internals/ast.rs:80 Container::from_ast
serde_derive/src/internals/ast.rs:166 enum_from_ast
Aufrufer in Tests tragen die Markierung test:
$ greppy who-calls test_suite/tests/test_de.rs::test --path test_suite/tests/test_de.rs
94 callers: test_suite/tests/test_de.rs 94
test_suite/tests/test_de.rs:216 test_bool test
test_suite/tests/test_de.rs:241 test_i8 test
…
who-calls beantwortet mehrere Symbole in einem Aufruf und gruppiert die Antwort nach Symbol. Mit --code druckt es zu jedem Aufrufer dessen ganze Quelltext-Spanne, gefolgt von einer handle:-Zeile für einen späteren Edit. Lange Spannen kürzt greppy mit … (truncated, N more line(s)):
$ greppy who-calls visit_content_seq visit_content_map --code
visit_content_seq
serde/src/private/de.rs:1126 ContentDeserializer::deserialize_any
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
…
serde/src/private/de.rs:1365 ContentDeserializer::deserialize_seq
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Seq(v) => visit_content_seq(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
…
visit_content_map
…
… 1 more — greppy who-calls visit_content_seq visit_content_map --code --offset 6
Die letzte Zeile nennt den Befehl, der die Antwort fortsetzt.
callees
callees liefert die indexierten Definitionen, die das Symbol direkt aufruft (ausgehende CALLS-Kanten), mit ihrem Definitionsort:
$ greppy callees deserialize_body
serde_derive/src/de/enum_.rs:15 deserialize
serde_derive/src/de/identifier.rs:14 deserialize_custom
serde_derive/src/de/struct_.rs:17 deserialize
serde_derive/src/de/tuple.rs:13 deserialize
serde_derive/src/de/unit.rs:8 deserialize
serde_derive/src/de.rs:383 deserialize_transparent
serde_derive/src/de.rs:426 deserialize_from
serde_derive/src/de.rs:435 deserialize_try_from
Externe und nicht aufgelöste Aufrufe stehen nicht in der Liste. Eine leere Antwort beweist deshalb nicht, dass der Code nichts aufruft. Wie who-calls nimmt callees mehrere Symbole in einem Aufruf an.
brief
brief ist die Orientierungshilfe. Es druckt in einem Satz, was das Symbol tut, dann seine Signatur und seinen Körper als Skizze: eine Zeile pro Schritt, mit dem Symbol, das dort verwendet wird. Danach folgen die Aufrufer und, wenn sich der Aufrufbaum darunter lohnt, ein expand-Angebot:
$ greppy brief expand_derive_deserialize
Expands a syn::DeriveInput into a TokenStream.
serde_derive/src/de.rs:25
pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
26 replace_receiver — rewrites a DeriveInput by replacing its receiver type
28 Ctxt::new — creates a new Ctxt with an empty errors vector
29 Container::from_ast — converts a syn::DeriveInput into a Container, handling enums and structs
31 Err
33 precondition — runs two precondition checks on cont
37 Parameters::new — constructs a Parameters struct from a Container
39 Stmts
39 deserialize_body — dispatches to the matching deserialize function based on the container's data type
41 allow_deprecated — returns a TokenStream with an allow(deprecated) attribute when enabled
45 pretend_used — generates TokenStream from Container's pretend fields and variants
60 deserialize_in_place_body — returns None unconditionally, ignoring its inputs
78 wrap_in_const — wraps serde code in a const attribute
}
called by derive_deserialize
expand be76477a311cb85b — the call tree below expand_derive_deserialize sketched, 100 functions, 1186 lines
greppy expand be76477a311cb85b druckt den skizzierten Aufrufbaum in einem Aufruf. Structs, Enums und Traits haben keinen Körper zum Skizzieren, darum druckt brief ihre ganze Definition:
$ greppy brief Ctxt
A type to collect errors together and format them. Dropping this object will cause a panic. It must be consumed using `check`. References can be shared since this type uses run-time exclusive mut checking.
serde_derive/src/internals/ctxt.rs:11-16
#[derive(Default)]
pub struct Ctxt {
// The contents will be set to `None` during checking. This is so that checking can be
// enforced.
errors: RefCell<Option<Vec<syn::Error>>>,
}
Mehrere Symbole briefst du in einem Aufruf, in der angegebenen Reihenfolge: greppy brief deserialize_body expand_derive_deserialize.
impact
impact zeigt den transitiven Wirkungsradius in einem Aufruf, als Baum, in dem jede Zeile sagt, was sie tut. Tests sind markiert, (above) verweist auf einen Knoten, der weiter oben schon steht:
$ greppy impact Ctxt::error_spanned_by
serde_derive/src/de.rs:89 precondition_sized — reports an error when a struct's last field is a slice
serde_derive/src/de.rs:84 precondition — runs two precondition checks on cont
serde_derive/src/de.rs:25 expand_derive_deserialize — expands a syn::DeriveInput into a TokenStream
serde_derive/src/lib.rs:122 derive_deserialize — derives deserialize code from a TokenStream
serde_derive/src/de.rs:102 precondition_no_de_lifetime — reports an error when the container contains a de lifetime parameter
serde_derive/src/de.rs:84 precondition (above)
serde_derive/src/internals/ast.rs:62 Container::from_ast — converts a syn::DeriveInput into a Container, handling enums and structs
serde_derive/src/de.rs:25 expand_derive_deserialize (above)
serde_derive/src/ser.rs:13 expand_derive_serialize — expands a syn::DeriveInput into a TokenStream of serialize methods
serde_derive/src/lib.rs:114 derive_serialize — derives serialization from a TokenStream
…
… 22 more reached — greppy impact Ctxt::error_spanned_by --all
greppy impact Ctxt::error_spanned_by # --direction incoming ist der Standard
greppy impact deserialize_body --direction outgoing # was deserialize_body am Ende erreicht
greppy impact deserialize_body --depth 3 --edge CALLS
$ greppy impact deserialize_body --depth 3 --edge CALLS
serde_derive/src/de.rs:25 expand_derive_deserialize — expands a syn::DeriveInput into a TokenStream
serde_derive/src/lib.rs:122 derive_deserialize — derives deserialize code from a TokenStream
| Flag | Wirkung |
|---|---|
--direction incoming |
transitive Aufrufer: was bricht, wenn du das Symbol änderst (Standard) |
--direction outgoing |
was das Symbol am Ende erreicht |
--depth N |
maximaler Abstand in Schritten (Standard 6) |
--edge TYPE |
einer Kantenart folgen; incoming folgt standardmäßig allen Referenzkanten, outgoing CALLS |
Nimm impact, statt who-calls von Hand Ebene für Ebene abzulaufen.
path
path zeigt jede Aufrufkette von A nach B als einen Baum der Aufrufstellen, an denen sie hängen. Der Start steht an seiner Definition. Jedes eingerückte Kind ist die Stelle in seinem Elternteil, die das nächste Symbol aufruft:
$ greppy path --from derive_deserialize --to deserialize_body
serde_derive/src/lib.rs:122 derive_deserialize
serde_derive/src/lib.rs:124 expand_derive_deserialize
serde_derive/src/de.rs:39 deserialize_body
Verzweigte Ketten druckt path als einen gemeinsamen Baum:
$ greppy path --from expand_derive_deserialize --to Ctxt::error_spanned_by
serde_derive/src/de.rs:25 expand_derive_deserialize
serde_derive/src/de.rs:29 Container::from_ast
serde_derive/src/internals/ast.rs:68 Container::from_ast
serde_derive/src/internals/attr.rs:350 parse_lit_into_expr_path
serde_derive/src/internals/attr.rs:1481 get_lit_str
serde_derive/src/internals/attr.rs:1416 get_lit_str2
serde_derive/src/internals/attr.rs:1444 Ctxt::error_spanned_by
serde_derive/src/internals/attr.rs:1488 Ctxt::error_spanned_by
serde_derive/src/internals/attr.rs:380 Ctxt::error_spanned_by
…
at least 8 paths shown
--edge nimmt CALLS (Standard), USAGE, TYPE_ASSIGN oder IMPORTS. path ist ein begrenzter Baum aus Aufrufstellen und lehnt --code mit Exit-Code 64 ab:
$ greppy path --from derive_deserialize --to deserialize_body --code
`path` prints the bounded call-site chain and does not accept `--code`; run it without `--code`, then use `greppy read SYMBOL` for a returned definition body
usage: greppy path --from SYMBOL --to SYMBOL [--root DIR]
Den Körper eines zurückgegebenen Symbols liest du mit greppy read.
Orientierung und Nachschlagen
| Befehl | Antwortet mit |
|---|---|
greppy where-am-i |
dem Repository auf einen Blick: Aufbau, Sprachen, Einstiegspunkte, Testwurzeln, jedes Modul mit seinen meistgenutzten Symbolen |
greppy graph-locate src/lib.rs:42 |
dem innersten Symbol, das eine Stelle datei:zeile umschließt; --file F --line N geht ebenso |
greppy fan-in / greppy fan-out |
den meistaufgerufenen und den am meisten aufrufenden Symbolen; --edge wählt die Kantenart (Standard CALLS) |
greppy trace --symbol S |
einem Trace durch den Aufrufgraphen; --direction outgoing (Standard) oder incoming, --edge, --depth (Standard 4) |
greppy search-graph --name NAME |
einer strukturierten Graph-Abfrage |
Die erste Zeile von where-am-i nennt den Pfad, die Sprachen und die Zahl der Dateien und Definitionen, für serde rust, toml, markdown, 339 files, 3,908 definitions. Danach folgt jedes Modul mit seinen meistgenutzten Symbolen und einem expand-Angebot:
$ greppy where-am-i
…
test_suite/ 271 files 1,949 defs — greppy expand da6c1ac451c40b4e
serde_core/ 22 files 735 defs — Type::Error, Deserializer, Serializer — greppy expand 362eb3329926c8b5
serde/ 7 files 696 defs — Type::Ok, Unsupported, Content — greppy expand 5618d48721fcf976
serde_derive/ 30 files 527 defs — Fragment, Ctxt, Container — greppy expand 26946d64ddc27ba5
serde_derive_internals/ 3 files 1 def — greppy expand c074986cbec47118
6 further files hold no definitions
docs: 4 files, 12 sections · config: 7 files, 169 keys
entry points: serde/build.rs, serde_core/build.rs, serde_derive/build.rs, serde_derive_internals/build.rs, test_suite/no_std/src/main.rs … 118 more — greppy expand 982c5556472e8a2e
tests: inline #[test] modules, test_suite/tests/
$ greppy graph-locate serde/src/private/de.rs:1105
Function serde/src/private/de.rs::Function::visit_content_map serde/src/private/de.rs:1103-1115 match=enclosing
Ausgabe-Flags
| Flag | Wirkung |
|---|---|
--code |
druckt zusätzlich Quelltext: bei who-calls die ganze Spanne jedes Aufrufers, bei callees die Definition jedes Aufgerufenen, jeweils mit Edit-Handle. brief und impact nehmen das Flag an und drucken dieselbe Antwort |
--all |
jedes Ergebnis statt der ersten |
--json |
dieselbe Antwort als Daten, mit exakten Zählern |
--path P |
Ergebnisse unterhalb dieser Datei oder dieses Verzeichnisses; wiederholbar. Das Flag filtert die Ergebnisse und wählt kein mehrdeutiges Zielsymbol aus |
--limit N, --offset K |
blättern durch eine --json-Antwort: höchstens N Ergebnisse ab dem K-ten. --offset setzt auch eine gekürzte Textantwort fort |
--root DIR |
arbeitet auf einem anderen Repository |
$ greppy who-calls Ctxt::error_spanned_by --path serde_derive/src/de.rs
serde_derive/src/de.rs:93 precondition_sized
serde_derive/src/de.rs:106 precondition_no_de_lifetime
Befehle verketten
Jeder Befehl nimmt seine Eingabe auch aus der Pipe, ein Ergebnis geht direkt in den nächsten Befehl:
$ greppy callees visit_content_map --json | greppy read -
serde/src/private/de.rs:1608-1615 MapDeserializer::new
fn new(content: Vec<(Content<'de>, Content<'de>)>) -> Self {
MapDeserializer {
iter: content.into_iter(),
value: None,
count: 0,
error: PhantomData,
}
}
Leere und unbeantwortbare Fragen
Eine Frage mit leerer Antwort, etwa ein existierendes Symbol ohne Aufrufer, sagt das und endet mit 0. Eine Frage, die sich nicht beantworten lässt, etwa ein unbekanntes Symbol oder ein mehrdeutiger Name, sagt warum und endet mit einem Exit-Code ungleich 0:
$ greppy who-calls derive_deserialize # Exit-Code 0
no callers
$ greppy who-calls deserialize_json_config # Exit-Code 1
no symbol `deserialize_json_config`
derive_deserialize ist ein gutes Beispiel für die Grenze jedes statischen Graphen: Der Compiler ruft die Funktion über #[proc_macro_derive(Deserialize, attributes(serde))] auf, kein Rust-Code im Repository tut es. Eine leere Graph-Antwort beweist also keine fehlende Beziehung. Reflection, Dependency Injection, dynamischer Dispatch und generierter Code liegen außerhalb jedes statischen Graphen. Wechsle mit search oder search-pattern die Methode, bevor du einen Schluss ziehst. Mehr dazu liest du unter Grenzen.