Checking Rust code programmatically

Inside a development tool that I want to develop, I need to check that some text is valid Rust code, and, in case it is not, I want to get the generated compilation error. To do that, I can save that text into a file, and then run the command "cargo check". Though, it has not optimal performance, as it reads and writes files.

Is there any tool that performs such analysis receiving input from stdin or from a socket, and emitting output on stdout or on a socket, without touching the disk?

I know there is a tool named "Rust Language Server". Though, its documentation is not clear regarding how to send some Rust code to it, and receiving the corresponding error messages.

RLS communicates using the language server protocol. What kind of tool are you working on? Depending on whether it needs to get all errors or just syntax errors and some other kind of errors, you may want to use rust-analyzer instead. Unlike RLS it can compute syntax errors and some other kinds of errors itself without calling into rustc. This makes it much faster. It does also support getting errors directly from rustc, but this only happens when you actually save the files to the disk. This is because the interface to directly get errors from rustc without writing anything to the disk is unstable. RLS can use it as it is compiled with nightly rustc, but rust-analyzer is compiled using stable rustc and thus can't use it.

If you just want to check “is this valid syntax or not” and you’re not trying to check semantics, you can use syn to parse the file with syn::File. https://docs.rs/syn/1.0.54/syn/struct.File.html

Thank you, but I need semantic check also, not only syntax check.

For example, I need a library or a program that, when receiving the string "fn main() { let mut a = 2; a = 3; }", returns a success value, and when receiving the string "fn main() { let a = 2; a = 3; }" returns a failure value (in this case, regarding mutability).

I want to build a static analysis tool to verify that a library satisfies some requirements, so that some client code should be rejected by the compiler, and some other client code should be allowed. It is explained, for C++ language, in this paper I wrote 13 years ago: https://www.drdobbs.com/cpp/static-testing-c-code/205801074 .

In that paper the solution was to save a temporary source file, to launch the compiler on that file, capturing the output of the compiler. It isn't very fast, though, especially using the Rust compiler.

The last page of that paper sounds a lot like doc tests in rust. If you write code blocks in doc comments, running cargo test will execute them. If you use ```compile_fail, it will check that the code doesn't compile. For example

/// ```
/// assert!(my_true());
/// ```
fn my_true()  -> bool { true }

or

/// ```compile_fail
/// let a = Foo; // `a` is not mutable, ...
/// a.bar();     // ... but this requires `a` to be mutable
/// ```
struct Foo;

impl Foo {
    fn bar(&mut self) {}
}
1 Like