Giter Site home page Giter Site logo

mre / cargo-inspect Goto Github PK

View Code? Open in Web Editor NEW
384.0 8.0 13.0 575 KB

Pssst!... see what Rust is doing behind the curtains ๐Ÿ•ต๐Ÿคซ

Home Page: https://endler.dev/2018/cargo-inspect

License: Apache License 2.0

Makefile 3.12% Rust 96.88%
syntactic-sugar desugar unpretty inspect static-analysis

cargo-inspect's Introduction

cargo-inspect

Logo

docs Build Status

Thanks All!

โ„น๏ธ This crate was superceded by cargo-expand, which added support for all the features that were missing when we started to work on cargo-inspect. Thanks all for your feedback and support.

What is Rust doing behind the scenes?

There are only two ways to live your life.
One is as though nothing is a miracle. The other is as though everything is a miracle. -- Albert Einstein

Installation

You need Rust nightly and rustfmt to get started.
You can install those via rustup:

rustup install nightly
rustup component add rustfmt

All set? Let's get cracking!

cargo install cargo-inspect

Usage

Call it on any Rust file:

cargo inspect main.rs

If you don't specify a file, the current crate will be analyzed instead.

cargo inspect

Depending on the size of the crate, this might take a while.
Please be patient.

It can also compare two file outputs! Try this:

cargo inspect --diff examples/range.rs,examples/range_inclusive.rs --plain

Configuration

USAGE:
    cargo inspect [FLAGS] [OPTIONS] [INPUT_FILE]

FLAGS:
    -h, --help
            Prints help information

        --list-themes
            Should we list all pretty printer themes?

        --plain
            Don't highlight output

    -V, --version
            Prints version information

    -v, --verbose
            Print the original code as a comment above the desugared code


OPTIONS:
        --theme <THEME>
            Specify a theme override for the pretty printer

        --diff <files>
            Diff input files

        --format <format>
            Override for the format that gets outputted when the `unpretty` mode is set to `flowgraph` [default: svg]

        --unpretty <unpretty>
            rustc "unpretty" parameters

            *Note*: For `--unpretty=flowgraph=[symbol]` you need to have `dot` on your PATH. [default: hir]

ARGS:
    <INPUT_FILE>
            Input file

Background

Rust allows for a lot of syntactic sugar, that makes it a pleasure to write. It is sometimes hard, however, to look behind the curtain and see what the compiler is really doing with our code.

To quote @tshepang, "It is good to know what these conveniences are, to avoid being mystified by what's going on under the hood... the less magical thinking we have of the world, the better."

  • lifetime elisions
  • type inference
  • syntactic sugar
  • implicit dereferencing
  • type coercions
  • hidden code (e.g. the prelude)

I was always interested in how programming languages work in the background, how my code was unrolled to make the compiler backend easier to maintain.

The goal is to make the compiler more approachable for mere mortals.
Mystery! Exploration! Discovery!

Read more on the background of cargo-inspect on my blog.

Code Examples

If-let gets desugared into match

Consider the following code snippet:

fn main() {
    if let Some(x) = Some(1) {
        // Do something with x
    }
}

When you compile it, the first thing Rust does is desugar it. To see what the code looks like after this step, run

cargo inspect examples/if_let.rs

This produces the following output:

Please run the command to reproduce the desugared output

You can see that the if let was desugared into a match statement.

To change the colorscheme, try cargo-inspect --list-themes, e.g.

cargo inspect examples/if_let.rs --theme GitHub

Please run the command to reproduce the desugared output

Oh, and if you have graphviz installed, you can also print a pretty flowgraph from your code:

cargo inspect --unpretty=flowgraph=main examples/if_let.rs

Please run the command to reproduce the desugared output

More examples

Please find more examples in the examples folder. You can also contribute more.

The Magic Sauce

The best things in the world are assembled from simple building blocks. This tool stands on the shoulders of giants. To work its magic, it runs the following commands:

  1. rustc -Zinspect=hir, for retrieving the HIR.
  2. rustfmt, for formatting the output.
  3. prettyprint, for syntax-highlighting, which is just a wrapper around the awesome syntect and bat crates.

Contributing

This is a young project, which has downsides and upsides.

  • Everything is in flux and things can break at any time. ๐Ÿ˜ซ
  • There's plenty of opportunity to shape and form the project. ๐Ÿ˜Š

Thus, become a contributor today!

Known issues

As of now, this is a very fragile tool. If it fails, it might will produce horrible output. You have been warned. That said, it won't eat your code, of course. ๐Ÿ˜Š

License

Licensed under either of

at your option.

Credits

Magnifying glass designed by Rawpixel.com

cargo-inspect's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar emanon42 avatar jonathansty avatar minijackson avatar mre avatar rafspiny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cargo-inspect's Issues

Is this tool working?

Hi! This looks like a useful tool. Is it expected to work?

I ask because, on current stable/nightly, it prints nothing. Specifically,

[cbiffle@coyote elfinject-rs]$ cargo inspect
โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
     โ”‚ /home/cbiffle/proj/elfinject-rs
โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
   1 โ”‚ 
โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
[cbiffle@coyote elfinject-rs]$

bin crates, lib crates, host crates, cross-compiled crates, workspaces, no workspaces -- they all look like that. (Tested on 1.49 stable and a recent nightly.)

I had assumed the crate was not abandoned because of recent commits, but it looks like all commits since ~August are from a bot.

cannot inspect async code

hello.

Cargo.toml

[package]
name = "async-programming"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { workspace = true, features = ["full"] }
futures = { workspace = true }

main.rs

// use futures::executor::block_on;
use tokio::runtime::{Runtime, Builder as RuntimeBuilder};
use tokio::time::sleep as asleep;
use tokio::join as ajoin;
use std::time::Duration;

async fn task_function(task_name: &str) -> usize {
    let mut sum = 0usize;
    println!("start!");
    for index in 0..10 {
        asleep(Duration::from_secs_f32(0.5)).await;
        println!("{task_name}: {index}");
        sum += index;
    }
    println!("stop!");
    sum
}

async fn async_main() {
    let task1 = task_function("task-1");
    let task2 = task_function("task-2");
    // task1.await;
    // task2.await;
    let (r1, r2) = ajoin!(task1, task2);
}

fn main() {
    let rt = RuntimeBuilder::new_multi_thread()
        // this is for the async sleep
        .enable_time()
        .worker_threads(1)
        .thread_name("main-workter")
        .thread_stack_size(3 * 1024 * 1024)
        .build()
        .unwrap();
    rt.block_on(async_main());
}

the error

โฑ  cargo inspect examples/simple.rs
Command failed:
error[E0670]: `async fn` is not permitted in Rust 2015
 --> examples/simple.rs:7:1
  |
7 | async fn task_function(task_name: &str) -> usize {
  | ^^^^^ to use `async fn`, switch to Rust 2018 or later
  |
  = help: set `edition = "2021"` in `Cargo.toml`
  = note: for more on editions, read https://doc.rust-lang.org/edition-guide

error[E0670]: `async fn` is not permitted in Rust 2015
  --> examples/simple.rs:19:1
   |
19 | async fn async_main() {
   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
   |
   = help: set `edition = "2021"` in `Cargo.toml`
   = note: for more on editions, read https://doc.rust-lang.org/edition-guide

error[E0433]: failed to resolve: maybe a missing crate `tokio`?
 --> examples/simple.rs:2:5
  |
2 | use tokio::runtime::{Runtime, Builder as RuntimeBuilder};
  |     ^^^^^ maybe a missing crate `tokio`?
  |
  = help: consider adding `extern crate tokio` to use the `tokio` crate

error[E0433]: failed to resolve: maybe a missing crate `tokio`?
 --> examples/simple.rs:3:5
  |
3 | use tokio::time::sleep as asleep;
  |     ^^^^^ maybe a missing crate `tokio`?
  |
  = help: consider adding `extern crate tokio` to use the `tokio` crate

error[E0432]: unresolved import `tokio`
 --> examples/simple.rs:4:5
  |
4 | use tokio::join as ajoin;
  |     ^^^^^ maybe a missing crate `tokio`?
  |
  = help: consider adding `extern crate tokio` to use the `tokio` crate

error: cannot determine resolution for the macro `ajoin`
  --> examples/simple.rs:24:20
   |
24 |     let (r1, r2) = ajoin!(task1, task2);
   |                    ^^^^^
   |
   = note: import resolution is stuck, try simplifying macro imports

any ideas? thanks in advance.

Add `verbose` flag

In #18, @eddyp mentioned a confusing error message when compiling a crate. rustfmt was triggering an error, in which case we print the unformatted compiler output.

It might be helpful to hide internal error messages behind a verbose flag as they are not very actionable and might just confuse users. After all, the program works but it's simply producing uglier code.

Const Function Evaluation

I've enjoyed using cargo inspect to help debug during procedural macro development but I was wondering if it would be possible to make it capable of showing the compile time execution of const functions. I believe this execution happens at the MIR level instead of the HIR level.

The reason I ask is I have a project I'm working on right now where the goal is to compile a builder pattern down to its built output when all of the parameters are known at compile time. I need a tool to prove that it is actually happening though.

Beautiful error messages

Right now we panic when there is an error.
This leads to all sorts of problems (e.g. the colors don't get reset).

We should handle errors gracefully and print some beautiful error messages instead.

Add links to documentation

In some outputs, e.g. the HTML version (#6), we could provide links to common traits and to the docs.

Add travis setup

As the project grows, we might want to make sure that our code compiles and that the tests run.
There are no tests yet, but at least we should add a .travis.yml to build the project on every PR.

Make `diff` output work with prettyprint

We recently added support for diffing output like so:

cargo inspect --diff examples/range.rs,examples/range_inclusive.rs --plain

While diffing works quite well, it would be nice to also make it work without the plain flag.
The problem right now is, that there are ANSI control codes in the output. I haven't looked into how to get rid of them, but if someone finds the time, that would be much appreciated.

Add line numbers

Would be nice to look at bat and see what they are doing over there, because their output looks really nice.

Installation fails while building a dep `onig_sys v69.5.0`

This is the traceback I get while cargo installing this crate

   Compiling darling_macro v0.9.0
error: failed to run custom build command for `onig_sys v69.5.0`

Caused by:
  process didn't exit successfully: `/tmp/cargo-installedrsNz/release/build/onig_sys-1e6f2f943c42c112/build-script-build` (exit code: 101)
--- stdout
cargo:warning=couldn't execute `llvm-config --prefix` (error: No such file or directory (os error 2))
cargo:warning=set the LLVM_CONFIG_PATH environment variable to the full path to a valid `llvm-config` executable (including the executable itself)

--- stderr
thread 'main' panicked at 'Unable to find libclang: "couldn\'t find any valid shared libraries matching: [\'libclang.so\', \'libclang-*.so\', \'libclang.so.*\', \'libclang-*.so.*\'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [])"', /home/palash25/.cargo/registry/src/github.com-1ecc6299db9ec823/bindgen-0.53.3/src/lib.rs:1956:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

warning: build failed, waiting for other jobs to finish...
error: failed to compile `cargo-inspect v0.10.0`, intermediate artifacts can be found at `/tmp/cargo-installedrsNz`

Caused by:
  build failed

Looks like that onig_sys needs llvm and clang to be able to build maybe it should be mentioned in the README to have these installed as a pre-requisite?

Support graphviz/dot files

rustc supports graphviz/dot output using the flowgraph flag (see @jonathansty's post here):

rustc +nightly -Zunpretty=flowgraph=main foo.rs

This can already be triggered with cargo-inspect:

cargo inspect --unpretty=flowgraph=main

Unfortunately, this is just syntax-highlighting the dot-file itself and not showing a pretty graph.
It would be nice to have an option like cargo inspect --graph, which renders the dot file as a graph in a new window or as an ASCII representation. We would have to do some research to find a crate which allows this. Help wanted. :)

Fix issue with structopt

In #31, our lovely dependabot tried to update structopt. The CI pipeline failed however.
Here is the relevant snippet:

error: `parse` argument must be a function path

  --> src/config.rs:28:53

   |

28 |     #[structopt(long = "diff", parse(try_from_str = "parse_tuple"))]

   |                                                     ^^^^^^^^^^^^^

warning: trait objects without an explicit `dyn` are deprecated

 --> src/config.rs:5:50

  |

5 | fn parse_tuple<T>(s: &str) -> Result<(T, T), Box<Error>>

  |                                                  ^^^^^ help: use `dyn`: `dyn Error`

  |

  = note: `#[warn(bare_trait_objects)]` on by default

error[E0599]: no function or associated item named `augment_clap` found for type `config::Config` in the current scope

  --> src/config.rs:67:12

   |

22 | pub struct Config {

   | ----------------- function or associated item `augment_clap` not found for this

...

67 |     Config(Config),

   |            ^^^^^^ function or associated item not found in `config::Config`

error[E0599]: no function or associated item named `is_subcommand` found for type `config::Config` in the current scope

  --> src/config.rs:67:12

   |

22 | pub struct Config {

   | ----------------- function or associated item `is_subcommand` not found for this

...

67 |     Config(Config),

   |            ^^^^^^ function or associated item not found in `config::Config`

error: aborting due to 3 previous errors

I think the main problem is this:
28 | #[structopt(long = "diff", parse(try_from_str = "parse_tuple"))]

Probably the syntax changed a bit.
If someone wants to tackle that, please go ahead and create a PR. ๐Ÿ˜Š

Make rustfmt more robust on crates

@Florob had the nice idea to try and replace $crate with the crate name when inspecting crates. Maybe that will make rustfmt crash less and make the output more readable.

Support line ranges

cargo inspect --range 5,9

should work and print the expanded code for the lines 5 to 9.

Cargo inspect fails on 2018 edition use syntax

When running cargo inspect on a 2018 project using regex crate, it complains about it not using 2015 syntax:

eddy@feodora:~/usr/src/rust/c_unit_test_parser$ cargo inspect src/main.rs 
Command failed:
error[E0432]: unresolved import `regex`
 --> src/main.rs:1:5
  |
1 | use regex::Regex;
  |     ^^^^^ maybe a missing `extern crate regex;`?

error: aborting due to previous error

For more information about this error, try `rustc --explain E0432`.

eddy@feodora:~/usr/src/rust/c_unit_test_parser$ grep 2018 Cargo.toml 
edition = "2018"

Show memory dropping

I'd like cargo-inspect to show when rustc drops memory (and probably injects calls to std::mem::drop or something similar).

Happy to support tackling this, although I'd need some guidance ๐Ÿ˜ธ

Add support for diffing two programs

While working on some example code, I had the following two programs:

fn main() {
  for n in 1..3 {
    // Do something with n
  }
}

and

fn main() {
  for n in 1..=3 {
    // Do something with n
  }
}

Running this through cargo-inspect produced almost the same output, except for a call to ::std::ops::RangeInclusive instead of ::std::ops::Range.

Would be nice to highlight those differences in the output somehow.

I think, we could do that with a --compare flag, which takes two programs and diffs the output.

cargo inspect --compare <file1> <file2>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.