• Stars
    star
    1,812
  • Rank 25,628 (Top 0.6 %)
  • Language
    Rust
  • License
    MIT License
  • Created over 3 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Flowistry is an IDE plugin for Rust that helps you focus on relevant code.

Flowistry: Information Flow for Rust

tests crates.io docs

Flowistry is a tool that analyzes the information flow of Rust programs. Flowistry understands whether it's possible for one piece of code to affect another. Flowistry integrates into the IDE to provide a "focus mode" which helps you focus on the code that's related to your current task.

For example, this GIF shows the focus mode when reading a function that unions two sets together:



When the user clicks a given variable or expression, Flowistry fades out all code that does not influence that code, and is not influenced by that code. For example, orig_len is not influenced by the for-loop, while set.len() is.

Flowistry can be helpful when you're reading a function with a lot of code. For example, this GIF shows a real function in the Rust compiler. If you want to understand the role of a specific argument to the function, then Flowistry can filter out most of the code as irrelevant:



Table of contents

Installation

IDE plugin

Flowistry is available as a VSCode plugin. You can install Flowistry from the Visual Studio Marketplace or the Open VSX Registry. In VSCode:

  • Go to the Extensions pane by clicking this button in the left margin: Screen Shot 2021-09-20 at 9 30 43 AM
  • Search for "Flowistry" and then click "Install".
  • Open a Rust workspace and wait for the tool to finish installing.

Note on platform support: Flowistry does not yet support NixOS. Flowistry cannot provide pre-built binaries for ARM targets like M1 Macs, so Flowistry must be installed from scratch on these targets (this is done for you, but will take a few more minutes than usual).

Alternatively, you can install it from source:

# Install flowistry binaries
git clone https://github.com/willcrichton/flowistry
cd flowistry
cargo install --path crates/flowistry_ide

# Install vscode extension
cd ide
npm install
npm run build
ln -s $(pwd) ~/.vscode/extensions/flowistry

Rustc plugin

If you are interested in the underlying analysis, you can use the flowistry crate published to crates.io: https://crates.io/crates/flowistry

The documentation is published here: https://willcrichton.net/flowistry/flowistry/

Note: Docs.rs doesn't support documentation for crates that use #![feature(rustc_private)] so we have to host it ourselves.

Usage

Note that the latest Flowistry has a Maximum Supported Rust Version of Rust 1.73. Flowistry is not guaranteed to work with features implemented after 1.73.

Startup

Once you have installed Flowistry, open a Rust workspace in VSCode. You should see this icon in the bottom toolbar:

Screen Shot 2022-02-22 at 11 46 12 AM

Flowistry starts up by type-checking your codebase. This may take a few minutes if you have many dependencies.

Note: Flowistry type-checking results are cached in the target/flowistry directory. If you delete this folder, Flowistry will have to recompute types. Also for a large codebase this directory may take up a fair amount of disk space.

Entering focus mode

Once Flowistry has booted up, the loading icon will disappear. Then you can enter focus mode by running the "Toggle focus mode" command. By default the keyboard shortcut is Ctrl+R Ctrl+A (⌘+R ⌘+A on Mac), or you can use the Flowistry context menu:

Screen Shot 2022-02-22 at 11 52 39 AM

In focus mode, Flowistry will automatically compute the information flow within a given function once you put your cursor there. Once Flowistry has finished analysis, the status bar will look like this:

Screen Shot 2022-02-22 at 11 55 36 AM

Note: Flowistry can be a bit slow for larger functions. It may take up to 15 seconds to finish the analysis.

Flowistry infers what you want to focus on based on your cursor. So if you click on a variable, you should see the focus region of that variable. Flowistry will highlight the focused code in gray, and then fade out code outside the focus region. For example, because the user's cursor is on view_projection, that variable is highlighted in gray, and its focus region is shown.

Screen Shot 2022-02-22 at 12 00 22 PM

Setting a mark

Sometimes you want to keep the focus region where it is, and click on other code to inspect it without changing focus. For this purpose, Flowistry has a concept of a "mark". Once you have selected code to focus on, you can run the "Set mark" command (Ctrl+R Ctrl+S / ⌘+R ⌘+S). Then a mark is set at your cursor's current position, and the focus will stay there until you run the "Unset mark" command (Ctrl+R Ctrl+D / ⌘+R ⌘+D).

Selecting the focus region

If you want to modify all the code in the focus region, e.g. to comment it out or copy it, then you can run the "Select focused region" command (Ctrl+R Ctrl+T / ⌘+R ⌘+T). This will add the entire focus region into your editor's selection.

Limitations

Flowistry is an active research project into the applications of information flow analysis for Rust. It is continually evolving as we experiment with analysis techniques and interaction paradigms. So it's not quite as polished or efficient as tools like Rust Analyzer, but we hope you can still find it useful! Nevertheless, there are a number of important limitations you should understand when using Flowistry to avoid being surprised.

If you have questions or issues, please file a Github issue, join our Discord, or DM @wcrichton on Twitter.

Flowistry does not completely handle interior mutability

When your code has references, Flowistry needs to understand what that reference points-to. Flowistry uses Rust's lifetime information to determine points-to information. However, data structures that use interior mutability such as Arc<Mutex<T>> explicitly do not share lifetimes between pointers to the same data. For example, in this snippet:

let x = Arc::new(Mutex::new(0));
let y = x.clone();
*x.lock().unwrap() = 1;
println!("{}", y.lock().unwrap());

Flowistry can determine that *x.lock().unwrap() = 1 is a mutation to x, but it can not determine that it is a mutation to y. So if you focus on y, the assignment to 1 would be faded out, even though it is relevant to the value of y.

We are researching methods to overcome this limitation, but for now just be aware that this is the main case where Flowistry is known to provide an incorrect answer.

A focus region may include more code than you expect

Flowistry's analysis tries to include all code that could have an influence on a focal point. This analysis makes a number of assumptions for both practical and fundamental reasons. For example, in this snippet:

let mut v = vec![1, 2, 3];
let x = v.get_mut(0);
println!("{:?} {}", v, x);

If you focus on v on line 3, it will include v.get_mut(0) as an operation that could have modified v. The reason is that Flowistry does not actually analyze the bodies of called functions, but rather approximates based on their type signatures. Because get_mut takes &mut self as input, it assumes that the vector could be modified.

In general, you should use focus mode as a pruning tool. If code is faded out, then you don't have to read it (minus the limitation mentioned above!). If it isn't faded out, then it might be relevant to your task.

Not all code is selectable

Flowistry works by analyzing the MIR graph for a given function using the Rust compiler's API. Then the IDE extension lifts the analysis results from the MIR level back to the source level. However, a lot of information about the program is lost in the journey from source code to MIR.

For example, if the source contains an expression foo.whomp.bar().baz(), it's possible that a temporary variable is only generated for the expression foo.whomp.bar(). So if the user selects foo, Flowistry may not be able to determine that this corresponds to the MIR place that represents foo.

This is why the IDE extension highlights the focused code in gray, so you can understand what your cursor's selection actually maps to.

Nested functions cannot be analyzed together (including closures and async)

Flowistry analyzes a single function at a time. If a function contains other functions, e.g. fn definitions, or closures, or implicitly via async, then Flowistry will only show you focus regions within the smallest function body containing your cursor. This is usually well defined for function definitions and closures, but may be confusing for async since that depends on how rustc decides to carve up your async function.

FAQ

rustup fails on installation

If rustup fails, especially with an error like "could not rename downloaded file", this is probably because Flowistry is running rustup concurrently with another tool (like rust-analyzer). Until rustup#988 is resolved, there is unfortunately no automated way around this.

To solve the issue, go to the command line and run:

rustup toolchain install nightly-2023-08-25 -c rust-src -c rustc-dev -c llvm-tools-preview

Then go back to VSCode and click "Continue" to let Flowistry continue installing.

Why isn't Flowistry part of Rust Analyzer?

Rust Analyzer does not support MIR and the borrow checker, which are essential parts of Flowistry's analysis. That fact is unlikely to change for a long time, so Flowistry is a standalone tool.

Why does Flowistry highlight (or not) this code?

See Limitations for known issues. If that doesn't explain what you're seeing, please post it in the unexpected highlights issue or ask on Discord.

More Repositories

1

tyrade

A pure functional language for type-level programming in Rust
Rust
305
star
2

lia

A high-level language for Rust
Rust
305
star
3

terracuda

A high-level Lua API for GPU parallelism [15-418 final]
Perl
64
star
4

indexical

Human-friendly indexed collections
Rust
45
star
5

sevenwonders

The popular Seven Wonders board game on the web
PHP
40
star
6

corrset-benchmark

A repository to test different performance optimizations in a sparse matrix computation.
Jupyter Notebook
37
star
7

rabbot

Abstract binding tree code generator
Rust
35
star
8

inliner

Programmable, human-readable inlining of Python code
Python
29
star
9

rustc-type-metaprogramming

Rust
24
star
10

cmu-grades

Gets your grades from CMU services
Python
21
star
11

wordtree

A Python library for generating word tree diagrams
Python
20
star
12

learn-opengl-rust

Learn OpenGL in Rust with web compatibility
Rust
16
star
13

model-js-workspace

My personal standard for how to set up a Javascript workspace
TypeScript
13
star
14

rust-book-exercises

Rust
12
star
15

types-over-strings

Rust
12
star
16

pyro-under-the-hood

Jupyter Notebook
8
star
17

cargo-single-pyo3

Generate a Python module from a single Rust file.
Rust
8
star
18

hyperlapse

Open-source implementation of MSR Hyperlapse
C++
8
star
19

gcp-job-queue

Python
7
star
20

r-autota

A tool to make R error messages easier to understand
HTML
6
star
21

rust-editor

Rust
6
star
22

web-logger

A prototype Rust logger that uses the browser instead of the console.
Rust
5
star
23

411-rust-starter-code

Rust
5
star
24

example-analyzer

Rust
5
star
25

rust-api-type-patterns

5
star
26

algo-rs

Assorted algorithms implemented in Rust
Rust
4
star
27

simple-bind

One-line non-exhaustive binds in Rust
Rust
4
star
28

aoc2021

q
4
star
29

dotfiles

My emacs configuration
Emacs Lisp
4
star
30

cmu_auth

Simple Python methods for authenticating to CMU services
Python
4
star
31

so-lang-diversity-analysis

Analysis of diversity in language communities based on the Stack Overflow Developer Survey 2022
Jupyter Notebook
3
star
32

expressiveness-benchmark

Jupyter Notebook
3
star
33

dml

Derma Markup Language, for HTML-style UI creation (for Garry's Mod)
Lua
3
star
34

classity

Remote lecturing tool [hackathon project]
CSS
3
star
35

y0

A language?
OCaml
3
star
36

tquery

jQuery, but for types
Rust
2
star
37

psypl-experiments

Jupyter Notebook
2
star
38

nota

JavaScript
2
star
39

gentle_whisper

Automatic transcription + fine-grained time-alignment
Python
2
star
40

tacticalassault

Class-based FPS gamemode (for Garry's Mod)
Lua
2
star
41

mdbook-preprocessor-utils

Rust
2
star
42

pickle-cache

Small utility for easily and efficiently saving/loading Python values to disk.
Python
2
star
43

utilikilt

CMU services on your phone
Objective-C
2
star
44

autoplan

Jupyter Notebook
2
star
45

glen

Three.js extension for creating games in the browser.
JavaScript
2
star
46

willcrichton.github.io

Github site
HTML
2
star
47

react-sequence-typed

TypeScript
2
star
48

rustc-embed

Rust
1
star
49

walrus-locator

In search of places to put a walrus
1
star
50

crashcourse-chat

For CrashCourse at CMU
JavaScript
1
star
51

bevy_world_visualizer

Rust
1
star
52

lagooned

A game of exploration and mystery
JavaScript
1
star
53

tetedoro

JavaScript
1
star
54

context-var

React-style context variables (i.e. dynamic scoping)
Python
1
star
55

semantic-divergence

Rust
1
star
56

fishies

A Paper.js game about fish. [98-232 sample project]
JavaScript
1
star
57

rlu-rs

A Rust implementation of the Read-Log-Update concurrency mechanism
Rust
1
star
58

notifier

Python
1
star
59

lecture-intelligence

A tool for scraping and analyzing lecture video viewing data from Panopto.
Jupyter Notebook
1
star
60

hudd

HUD Designer - intuitive menu creator for Garry's Mod
Lua
1
star
61

awap-2015

Official repository for Algorithms with a Purpose 2015: Startup Tycoon
Python
1
star
62

regulair

Regex library for FPGAs
Python
1
star
63

status-protect

Chrome extension designed to folly malicious Facebook status-updaters
JavaScript
1
star