From c89acda9ab20710299e285dc81f315353d7c3f5d Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 7 May 2024 09:52:50 -0700 Subject: [PATCH 1/5] feat: add candid-checker --- Cargo.lock | 168 +++++++++++++++++++++-- src/candid-checker/Cargo.toml | 27 ++++ src/candid-checker/src/lib.rs | 237 +++++++++++++++++++++++++++++++++ src/candid-checker/src/main.rs | 22 +++ src/candid-checker/test.did | 7 + src/candid-checker/test.rs | 32 +++++ src/candid-checker/test.toml | 3 + 7 files changed, 485 insertions(+), 11 deletions(-) create mode 100644 src/candid-checker/Cargo.toml create mode 100644 src/candid-checker/src/lib.rs create mode 100644 src/candid-checker/src/main.rs create mode 100644 src/candid-checker/test.did create mode 100644 src/candid-checker/test.rs create mode 100644 src/candid-checker/test.toml diff --git a/Cargo.lock b/Cargo.lock index 049f28038..26ae30fdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,9 +234,9 @@ dependencies = [ "anyhow", "binread", "byteorder", - "candid_derive", + "candid_derive 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "hex", - "ic_principal", + "ic_principal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "leb128", "num-bigint", "num-traits", @@ -248,6 +248,40 @@ dependencies = [ "thiserror", ] +[[package]] +name = "candid" +version = "0.10.8" +source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive 0.6.6 (git+https://github.com/dfinity/candid.git?branch=configs)", + "hex", + "ic_principal 0.1.1 (git+https://github.com/dfinity/candid.git?branch=configs)", + "leb128", + "num-bigint", + "num-traits", + "paste", + "pretty", + "serde", + "serde_bytes", + "stacker", + "thiserror", +] + +[[package]] +name = "candid-checker" +version = "0.1.0" +dependencies = [ + "anyhow", + "candid_parser 0.2.0-beta.0", + "clap", + "codespan-reporting", + "proc-macro2", + "syn 2.0.60", +] + [[package]] name = "candid-extractor" version = "0.1.3" @@ -271,6 +305,17 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "candid_derive" +version = "0.6.6" +source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "candid_parser" version = "0.1.4" @@ -278,7 +323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48a3da76f989cd350b7342c64c6c6008341bb6186f6832ef04e56dc50ba0fd76" dependencies = [ "anyhow", - "candid", + "candid 0.10.7", "codespan-reporting", "convert_case", "hex", @@ -290,6 +335,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "candid_parser" +version = "0.2.0-beta.0" +source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +dependencies = [ + "anyhow", + "candid 0.10.8", + "codespan-reporting", + "convert_case", + "handlebars", + "hex", + "lalrpop", + "lalrpop-util", + "logos", + "num-bigint", + "pretty", + "proc-macro2", + "serde", + "syn 2.0.60", + "thiserror", + "toml", +] + [[package]] name = "cargo-platform" version = "0.1.8" @@ -889,6 +957,20 @@ dependencies = [ "crunchy", ] +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -930,7 +1012,7 @@ name = "ic-cdk" version = "0.13.2" dependencies = [ "anyhow", - "candid", + "candid 0.10.7", "ic-cdk-macros", "ic0", "rstest", @@ -944,8 +1026,8 @@ dependencies = [ name = "ic-cdk-bindgen" version = "0.1.3" dependencies = [ - "candid", - "candid_parser", + "candid 0.10.7", + "candid_parser 0.1.4", "convert_case", "pretty", ] @@ -954,7 +1036,7 @@ dependencies = [ name = "ic-cdk-e2e-tests" version = "0.1.0" dependencies = [ - "candid", + "candid 0.10.7", "cargo_metadata", "escargot", "futures", @@ -971,7 +1053,7 @@ dependencies = [ name = "ic-cdk-macros" version = "0.13.2" dependencies = [ - "candid", + "candid 0.10.7", "proc-macro2", "quote", "serde", @@ -996,7 +1078,7 @@ name = "ic-certified-map" version = "0.4.0" dependencies = [ "bincode", - "candid", + "candid 0.10.7", "hex", "ic-cdk", "serde", @@ -1009,7 +1091,7 @@ dependencies = [ name = "ic-ledger-types" version = "0.10.0" dependencies = [ - "candid", + "candid 0.10.7", "crc32fast", "hex", "ic-cdk", @@ -1024,7 +1106,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e05a81e0cbdf178228d72ace06c60ac7fa99927b49a238f9ccf5ef82eaced6" dependencies = [ - "candid", + "candid 0.10.7", "ciborium", "serde", "serde_bytes", @@ -1052,6 +1134,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ic_principal" +version = "0.1.1" +source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +dependencies = [ + "arbitrary", + "crc32fast", + "data-encoding", + "serde", + "sha2", + "thiserror", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -1351,6 +1446,51 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.60", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -1909,6 +2049,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/src/candid-checker/Cargo.toml b/src/candid-checker/Cargo.toml new file mode 100644 index 000000000..5e25a3d29 --- /dev/null +++ b/src/candid-checker/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "candid-checker" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +repository.workspace = true +rust-version.workspace = true +license.workspace = true +description = "CLI tool to check if Rust code implements a given did file" + +[[bin]] +name = "candid-checker" +path = "src/main.rs" +required-features = ["exe"] + +[dependencies] +syn = { version = "2.0", features = ["full", "visit", "extra-traits"] } +proc-macro2 = { version = "1.0", features = ["span-locations"] } +candid_parser = { git = "https://github.com/dfinity/candid.git", branch = "configs" } +codespan-reporting = "0.11" + +clap = { version = "4", features = ["derive"], optional = true } +anyhow = { version = "1.0", optional = true } + +[features] +exe = ["dep:clap", "dep:anyhow"] + diff --git a/src/candid-checker/src/lib.rs b/src/candid-checker/src/lib.rs new file mode 100644 index 000000000..ca1397773 --- /dev/null +++ b/src/candid-checker/src/lib.rs @@ -0,0 +1,237 @@ +use codespan_reporting::{ + diagnostic::{Diagnostic, Label}, + files::SimpleFile, + term::{self, termcolor::StandardStream}, +}; +use syn::{Expr, ExprLit, FnArg, Lit, Meta, ReturnType, Attribute, Signature}; +use candid_parser::bindings::rust::{Output, Config, emit_bindgen}; +use candid_parser::configs::Configs; +use candid_parser::{Result, utils::CandidSource}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::fs; +use std::ops::Range; + +pub fn check_rust(rust: &Path, candid: &Path, config: &Option) -> Result<()> { + let candid = CandidSource::File(candid); + let (env, actor) = candid.load()?; + let config = if let Some(config) = config { + fs::read_to_string(config)? + } else { + "".to_string() + }; + let config: Configs = config.parse()?; + let config = Config::new(config); + let (output, unused) = emit_bindgen(&config, &env, &actor); + let name = rust.file_name().unwrap().to_str().unwrap(); + let source = fs::read_to_string(rust)?; + report_errors(&name, &source, &output); + Ok(()) +} + +fn report_errors(name: &str, source: &str, candid: &Output) { + let rust = get_endpoint_from_rust_source(source); + let diags = diff_did_and_rust(candid, &rust); + let writer = StandardStream::stderr(term::termcolor::ColorChoice::Auto); + let config = term::Config::default(); + let file = SimpleFile::new(name, source); + for diag in diags { + term::emit(&mut writer.lock(), &config, &file, &diag).unwrap(); + } +} +fn get_endpoint_from_rust_source(source: &str) -> Vec { + use syn::visit::{self, Visit}; + use syn::{ImplItemFn, ItemFn}; + struct FnVisitor(Vec); + impl<'ast> Visit<'ast> for FnVisitor { + fn visit_item_fn(&mut self, node: &'ast ItemFn) { + if let Some(m) = get_cdk_function(&node.attrs, &node.sig) { + self.0.push(m); + } + // handle nested functions + visit::visit_item_fn(self, node); + } + fn visit_impl_item_fn(&mut self, node: &'ast ImplItemFn) { + if let Some(m) = get_cdk_function(&node.attrs, &node.sig) { + self.0.push(m); + } + // handle nested functions + visit::visit_impl_item_fn(self, node); + } + } + let ast = syn::parse_file(source).unwrap(); + let mut visitor = FnVisitor(Vec::new()); + visitor.visit_file(&ast); + for m in &visitor.0 { + m.debug_print(source); + } + visitor.0 +} +fn diff_did_and_rust(candid: &Output, rust: &[CDKMethod]) -> Vec> { + use syn::spanned::Spanned; + let mut res = Vec::new(); + let rust: BTreeMap<_, _> = rust + .iter() + .map(|m| { + let name = m + .export_name + .as_ref() + .map(|x| x.0.clone()) + .unwrap_or(m.func_name.to_string()); + (name, m) + }) + .collect(); + for m in &candid.methods { + let diag = Diagnostic::error() + .with_message(format!("Error with Candid method {}", m.original_name)); + let mut labels = Vec::new(); + let mut notes = Vec::new(); + if let Some(func) = rust.get(&m.original_name) { + if m.original_name == m.name { + } else { + if let Some((name, meta)) = &func.export_name { + if *name != m.original_name { + labels + .push(Label::primary((), meta.span().byte_range()).with_message( + format!("expect {}", m.original_name.escape_debug()), + )); + } + } else { + labels.push( + Label::primary((), func.mode.span().byte_range()).with_message(format!( + "missing (name = \"{}\")", + m.original_name.escape_debug() + )), + ); + } + } + let args = func.args.iter().zip(m.args.iter().map(|x| &x.1)); + for (rust_arg, candid_arg) in args { + let parsed_candid_arg: syn::Type = syn::parse_str(candid_arg).unwrap(); + if parsed_candid_arg != *rust_arg { + labels.push( + Label::primary((), rust_arg.span().byte_range()) + .with_message(format!("expect type: {}", candid_arg)), + ); + } + } + } else { + notes.push(format!( + "method \"{}\" missing from Rust code", + m.original_name + )); + } + if labels.is_empty() && notes.is_empty() { + continue; + } + res.push(diag.with_labels(labels).with_notes(notes)); + } + res +} +struct CDKMethod { + func_name: syn::Ident, + export_name: Option<(String, syn::Meta)>, + composite: Option, + mode: syn::Ident, + args: Vec, + rets: Vec, + attr_span: Range, + fn_span: Range, + args_span: Range, + rets_span: Range, +} +fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { + use syn::parse::Parser; + use syn::spanned::Spanned; + let func_name = sig.ident.clone(); + let mut mode = None; + let mut export_name = None; + let mut composite = None; + let mut attr_span = None; + let mut fn_span = None; + for attr in attrs { + let attr_name = &attr.meta.path().segments.last().unwrap().ident; + if attr_name != "update" && attr_name != "query" && attr_name != "init" { + continue; + } + mode = Some(attr_name.clone()); + attr_span = Some(attr.span().byte_range()); + fn_span = Some(sig.span().byte_range()); + if let Meta::List(list) = &attr.meta { + let nested = syn::punctuated::Punctuated::::parse_terminated + .parse2(list.tokens.clone()) + .unwrap(); + for meta in nested { + if let Meta::NameValue(ref m) = meta { + if m.path.is_ident("name") { + if let Expr::Lit(ExprLit { + lit: Lit::Str(name), + .. + }) = &m.value + { + export_name = Some((name.value(), meta)); + } + } else if m.path.is_ident("composite") { + if let Expr::Lit(ExprLit { + lit: Lit::Bool(b), .. + }) = &m.value + { + if b.value { + composite = Some(meta); + } + } + } + } + } + } + } + let args = sig + .inputs + .iter() + .filter_map(|arg| match arg { + FnArg::Receiver(_) => None, + FnArg::Typed(pat) => Some(*pat.ty.clone()), + }) + .collect(); + let rets = match &sig.output { + ReturnType::Default => Vec::new(), + ReturnType::Type(_, ty) => match ty.as_ref() { + syn::Type::Tuple(ty) => ty.elems.iter().map(|t| (*t).clone()).collect(), + _ => vec![*ty.clone()], + }, + }; + mode.map(|mode| CDKMethod { + func_name, + export_name, + composite, + args, + rets, + mode, + attr_span: attr_span.unwrap(), + fn_span: fn_span.unwrap(), + args_span: sig.inputs.span().byte_range(), + rets_span: sig.output.span().byte_range(), + }) +} +impl CDKMethod { + fn debug_print(&self, source: &str) { + use syn::spanned::Spanned; + println!("{} {}", self.func_name, self.mode); + if let Some((_, meta)) = &self.export_name { + let range = meta.span().byte_range(); + println!(" export {}", &source[range]); + } + if let Some(composite) = &self.composite { + let range = composite.span().byte_range(); + println!(" composite {}", &source[range]); + } + for arg in &self.args { + let range = arg.span().byte_range(); + println!(" arg {}", &source[range]); + } + for ret in &self.rets { + let range = ret.span().byte_range(); + println!(" ret {}", &source[range]); + } + } +} diff --git a/src/candid-checker/src/main.rs b/src/candid-checker/src/main.rs new file mode 100644 index 000000000..438db3a14 --- /dev/null +++ b/src/candid-checker/src/main.rs @@ -0,0 +1,22 @@ +use clap::Parser; +use std::path::PathBuf; +use anyhow::Result; + +use candid_checker::check_rust; + +#[derive(Parser)] +#[command(version, about)] +struct Opts { + /// Rust source file + rust: PathBuf, + /// Candid file + candid: PathBuf, + /// TOML config file + config: Option, +} + +fn main() -> Result<()> { + let opts = Opts::parse(); + check_rust(&opts.rust, &opts.candid, &opts.config)?; + Ok(()) +} diff --git a/src/candid-checker/test.did b/src/candid-checker/test.did new file mode 100644 index 000000000..151edaa92 --- /dev/null +++ b/src/candid-checker/test.did @@ -0,0 +1,7 @@ +type my_type = principal; +type Profile = record { name: text; age: nat8; country: text }; +type List = opt record { head: blob; tail: List }; +service : { + f:(my_type, vec Profile)->(List) composite_query; + g:() -> (); +} diff --git a/src/candid-checker/test.rs b/src/candid-checker/test.rs new file mode 100644 index 000000000..5bfac5c75 --- /dev/null +++ b/src/candid-checker/test.rs @@ -0,0 +1,32 @@ +// This is an experimental feature to generate Rust binding from Candid. +// You may want to manually adjust some of the types. +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal}; + +pub type MyType = Principal; +#[derive(CandidType, Deserialize)] +pub struct Profile { pub age: u8, pub country: String, pub name: String } +#[derive(CandidType, Deserialize)] +pub struct ListInner { pub head: serde_bytes::ByteBuf, pub tail: Box } +#[derive(CandidType, Deserialize)] +pub struct List(Option); + +#[ic_cdk::update] +#[candid_method(update)] +pub async fn f(test: MyType, argument: Vec/* whatever */) -> List { +} + +fn not_candid() {} + +mod A { + #[query(composite = true, name="INNER")] + async fn inner(a: List) -> Result {} +} + +#[::ic_cdk::query(name="test")] +fn g() -> () { +} +impl T { + #[query] + fn h(&mut self) -> (u8,u16) {} +} diff --git a/src/candid-checker/test.toml b/src/candid-checker/test.toml new file mode 100644 index 000000000..4995d7274 --- /dev/null +++ b/src/candid-checker/test.toml @@ -0,0 +1,3 @@ +f.name = "FFF" +my_type.name = "CanisterId2" + From e90d63cf81742c649abb2572893bdc6ec9da9121 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 7 May 2024 12:57:47 -0700 Subject: [PATCH 2/5] fix --- Cargo.lock | 10 ++- src/candid-checker/src/lib.rs | 126 +++++++++++++++++++++------------ src/candid-checker/src/main.rs | 2 +- src/candid-checker/test.did | 2 + src/candid-checker/test.rs | 2 +- 5 files changed, 90 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26ae30fdf..abe3b7a6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ [[package]] name = "candid" version = "0.10.8" -source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" dependencies = [ "anyhow", "binread", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "candid_derive" version = "0.6.6" -source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" dependencies = [ "lazy_static", "proc-macro2", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "candid_parser" version = "0.2.0-beta.0" -source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" dependencies = [ "anyhow", "candid 0.10.8", @@ -351,9 +351,7 @@ dependencies = [ "logos", "num-bigint", "pretty", - "proc-macro2", "serde", - "syn 2.0.60", "thiserror", "toml", ] @@ -1137,7 +1135,7 @@ dependencies = [ [[package]] name = "ic_principal" version = "0.1.1" -source = "git+https://github.com/dfinity/candid.git?branch=configs#221422f495fa7ec12df32bd4e0fd40dd1d9f0704" +source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" dependencies = [ "arbitrary", "crc32fast", diff --git a/src/candid-checker/src/lib.rs b/src/candid-checker/src/lib.rs index ca1397773..39ea9409c 100644 --- a/src/candid-checker/src/lib.rs +++ b/src/candid-checker/src/lib.rs @@ -1,16 +1,17 @@ +use candid_parser::bindings::rust::{emit_bindgen, Config, Output}; +use candid_parser::configs::Configs; +use candid_parser::{utils::CandidSource, Result}; use codespan_reporting::{ diagnostic::{Diagnostic, Label}, files::SimpleFile, term::{self, termcolor::StandardStream}, }; -use syn::{Expr, ExprLit, FnArg, Lit, Meta, ReturnType, Attribute, Signature}; -use candid_parser::bindings::rust::{Output, Config, emit_bindgen}; -use candid_parser::configs::Configs; -use candid_parser::{Result, utils::CandidSource}; use std::collections::BTreeMap; -use std::path::{Path, PathBuf}; use std::fs; use std::ops::Range; +use std::path::{Path, PathBuf}; +use syn::spanned::Spanned; +use syn::{Attribute, Expr, ExprLit, FnArg, Lit, Meta, ReturnType, Signature}; pub fn check_rust(rust: &Path, candid: &Path, config: &Option) -> Result<()> { let candid = CandidSource::File(candid); @@ -25,7 +26,7 @@ pub fn check_rust(rust: &Path, candid: &Path, config: &Option) -> Resul let (output, unused) = emit_bindgen(&config, &env, &actor); let name = rust.file_name().unwrap().to_str().unwrap(); let source = fs::read_to_string(rust)?; - report_errors(&name, &source, &output); + report_errors(name, &source, &output); Ok(()) } @@ -67,10 +68,9 @@ fn get_endpoint_from_rust_source(source: &str) -> Vec { } visitor.0 } -fn diff_did_and_rust(candid: &Output, rust: &[CDKMethod]) -> Vec> { - use syn::spanned::Spanned; +fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec> { let mut res = Vec::new(); - let rust: BTreeMap<_, _> = rust + let rust: BTreeMap<_, _> = rust_list .iter() .map(|m| { let name = m @@ -87,39 +87,65 @@ fn diff_did_and_rust(candid: &Output, rust: &[CDKMethod]) -> Vec> let mut labels = Vec::new(); let mut notes = Vec::new(); if let Some(func) = rust.get(&m.original_name) { - if m.original_name == m.name { + // check function name + if func.func_name != m.name { + labels.push( + Label::primary((), func.func_name.span().byte_range()) + .with_message(format!("Expect function name: {}", m.name)), + ); + } + // check mode + let mode = if m.mode == "update" { + "update" } else { - if let Some((name, meta)) = &func.export_name { - if *name != m.original_name { - labels - .push(Label::primary((), meta.span().byte_range()).with_message( - format!("expect {}", m.original_name.escape_debug()), - )); - } - } else { - labels.push( - Label::primary((), func.mode.span().byte_range()).with_message(format!( - "missing (name = \"{}\")", - m.original_name.escape_debug() - )), - ); - } + "query" + }; + if func.mode != mode { + labels.push( + Label::primary((), func.mode.span().byte_range()) + .with_message(format!("Expect mode: {}", mode)), + ); } - let args = func.args.iter().zip(m.args.iter().map(|x| &x.1)); - for (rust_arg, candid_arg) in args { - let parsed_candid_arg: syn::Type = syn::parse_str(candid_arg).unwrap(); - if parsed_candid_arg != *rust_arg { - labels.push( - Label::primary((), rust_arg.span().byte_range()) - .with_message(format!("expect type: {}", candid_arg)), - ); - } + if m.mode == "composite_query" && func.composite.is_none() { + labels.push( + Label::primary((), func.mode.span().byte_range()) + .with_message("Expect attribute: composite = true"), + ); + } + // check rename attribute + if m.original_name != m.name && func.export_name.is_none() { + // no need to check func.export_name != m.original_name, since we already found the function + labels.push( + Label::primary((), func.mode.span().byte_range()).with_message(format!( + "Expect attribute: name = \"{}\"", + m.original_name.escape_debug() + )), + ); + } + // check args + let args = m.args.iter().map(|x| x.1.clone()).collect::>(); + labels.extend(check_args(&func.args, &args, &func.args_span)); + labels.extend(check_args(&func.rets, &m.rets, &func.rets_span)); + if !labels.is_empty() { + labels.push(Label::secondary((), func.fn_span.clone())); } } else { - notes.push(format!( - "method \"{}\" missing from Rust code", - m.original_name - )); + if let Some(func) = rust_list.iter().find(|x| x.func_name == m.original_name) { + let (_, meta) = func.export_name.as_ref().unwrap(); + labels.push( + Label::primary((), meta.span().byte_range()) + .with_message("You may want to remove the name attribute"), + ); + labels.push( + Label::secondary((), func.func_name.span().byte_range()) + .with_message("This function name matches the Candid method name"), + ); + } else { + notes.push(format!( + "method \"{}\" missing from Rust code", + m.original_name + )); + } } if labels.is_empty() && notes.is_empty() { continue; @@ -128,6 +154,24 @@ fn diff_did_and_rust(candid: &Output, rust: &[CDKMethod]) -> Vec> } res } +fn check_args(rust: &[syn::Type], candid: &[String], span: &Range) -> Vec> { + let mut labels = Vec::new(); + if rust.len() != candid.len() { + labels.push(Label::primary((), span.clone()).with_message("Argument count mismatch")); + return labels; + } + let args = rust.iter().zip(candid.iter()); + for (rust_arg, candid_arg) in args { + let parsed_candid_arg: syn::Type = syn::parse_str(candid_arg).unwrap(); + if parsed_candid_arg != *rust_arg { + labels.push( + Label::primary((), rust_arg.span().byte_range()) + .with_message(format!("Expect type: {}", candid_arg)), + ); + } + } + labels +} struct CDKMethod { func_name: syn::Ident, export_name: Option<(String, syn::Meta)>, @@ -135,19 +179,16 @@ struct CDKMethod { mode: syn::Ident, args: Vec, rets: Vec, - attr_span: Range, fn_span: Range, args_span: Range, rets_span: Range, } fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { use syn::parse::Parser; - use syn::spanned::Spanned; let func_name = sig.ident.clone(); let mut mode = None; let mut export_name = None; let mut composite = None; - let mut attr_span = None; let mut fn_span = None; for attr in attrs { let attr_name = &attr.meta.path().segments.last().unwrap().ident; @@ -155,7 +196,6 @@ fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { continue; } mode = Some(attr_name.clone()); - attr_span = Some(attr.span().byte_range()); fn_span = Some(sig.span().byte_range()); if let Meta::List(list) = &attr.meta { let nested = syn::punctuated::Punctuated::::parse_terminated @@ -207,7 +247,6 @@ fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { args, rets, mode, - attr_span: attr_span.unwrap(), fn_span: fn_span.unwrap(), args_span: sig.inputs.span().byte_range(), rets_span: sig.output.span().byte_range(), @@ -215,7 +254,6 @@ fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { } impl CDKMethod { fn debug_print(&self, source: &str) { - use syn::spanned::Spanned; println!("{} {}", self.func_name, self.mode); if let Some((_, meta)) = &self.export_name { let range = meta.span().byte_range(); diff --git a/src/candid-checker/src/main.rs b/src/candid-checker/src/main.rs index 438db3a14..0b365302a 100644 --- a/src/candid-checker/src/main.rs +++ b/src/candid-checker/src/main.rs @@ -1,6 +1,6 @@ +use anyhow::Result; use clap::Parser; use std::path::PathBuf; -use anyhow::Result; use candid_checker::check_rust; diff --git a/src/candid-checker/test.did b/src/candid-checker/test.did index 151edaa92..88667942f 100644 --- a/src/candid-checker/test.did +++ b/src/candid-checker/test.did @@ -4,4 +4,6 @@ type List = opt record { head: blob; tail: List }; service : { f:(my_type, vec Profile)->(List) composite_query; g:() -> (); + inner:()->(); + missing:() -> () query; } diff --git a/src/candid-checker/test.rs b/src/candid-checker/test.rs index 5bfac5c75..a5fdbb770 100644 --- a/src/candid-checker/test.rs +++ b/src/candid-checker/test.rs @@ -19,7 +19,7 @@ pub async fn f(test: MyType, argument: Vec/* whatever */) -> List { fn not_candid() {} mod A { - #[query(composite = true, name="INNER")] + #[query(composite = true)] async fn inner(a: List) -> Result {} } From 79c342ae4781cdf9b2f9279255bceefb9333037b Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 7 May 2024 18:02:19 -0700 Subject: [PATCH 3/5] fix --- src/candid-checker/src/lib.rs | 132 ++++++++++++++++++++++++++++------ src/candid-checker/test.did | 2 +- src/candid-checker/test.rs | 2 +- 3 files changed, 114 insertions(+), 22 deletions(-) diff --git a/src/candid-checker/src/lib.rs b/src/candid-checker/src/lib.rs index 39ea9409c..708837873 100644 --- a/src/candid-checker/src/lib.rs +++ b/src/candid-checker/src/lib.rs @@ -1,4 +1,4 @@ -use candid_parser::bindings::rust::{emit_bindgen, Config, Output}; +use candid_parser::bindings::rust::{emit_bindgen, Config, Method, Output}; use candid_parser::configs::Configs; use candid_parser::{utils::CandidSource, Result}; use codespan_reporting::{ @@ -24,20 +24,32 @@ pub fn check_rust(rust: &Path, candid: &Path, config: &Option) -> Resul let config: Configs = config.parse()?; let config = Config::new(config); let (output, unused) = emit_bindgen(&config, &env, &actor); + report_unused(unused); let name = rust.file_name().unwrap().to_str().unwrap(); let source = fs::read_to_string(rust)?; - report_errors(name, &source, &output); + let rust = get_endpoint_from_rust_source(&source); + let diags = diff_did_and_rust(&output, &rust); + report_errors(name, &source, &diags); Ok(()) } - -fn report_errors(name: &str, source: &str, candid: &Output) { - let rust = get_endpoint_from_rust_source(source); - let diags = diff_did_and_rust(candid, &rust); +fn report_unused(unused: Vec) { + if !unused.is_empty() { + let unused = unused + .iter() + .map(|x| format!("{x} is not used")) + .collect::>(); + let diag = Diagnostic::warning() + .with_message("Unused paths from the config file") + .with_notes(unused); + report_errors("config", "", &[diag]); + } +} +fn report_errors(name: &str, source: &str, diags: &[Diagnostic<()>]) { let writer = StandardStream::stderr(term::termcolor::ColorChoice::Auto); let config = term::Config::default(); let file = SimpleFile::new(name, source); for diag in diags { - term::emit(&mut writer.lock(), &config, &file, &diag).unwrap(); + term::emit(&mut writer.lock(), &config, &file, diag).unwrap(); } } fn get_endpoint_from_rust_source(source: &str) -> Vec { @@ -63,13 +75,14 @@ fn get_endpoint_from_rust_source(source: &str) -> Vec { let ast = syn::parse_file(source).unwrap(); let mut visitor = FnVisitor(Vec::new()); visitor.visit_file(&ast); - for m in &visitor.0 { - m.debug_print(source); - } visitor.0 } fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec> { let mut res = Vec::new(); + let mut ids: BTreeMap<_, _> = rust_list + .iter() + .map(|m| (m.func_name.to_string(), m)) + .collect(); let rust: BTreeMap<_, _> = rust_list .iter() .map(|m| { @@ -82,11 +95,12 @@ fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec Vec>(); - labels.extend(check_args(&func.args, &args, &func.args_span)); - labels.extend(check_args(&func.rets, &m.rets, &func.rets_span)); + let (mut labs, need_pp) = check_args(&func.args, &args, &func.args_span); + if need_pp { + let mut pp = pp_args(&m.args); + if pp.is_empty() { + pp = "remove the input argument".to_string(); + } + labs.push( + Label::secondary((), func.args_span.clone()) + .with_message(format!("Suggestion: {}", pp)), + ); + } + labels.extend(labs); + let (mut labs, need_pp) = check_args(&func.rets, &m.rets, &func.rets_span); + if need_pp { + let mut pp = pp_rets(&m.rets); + if pp.is_empty() { + pp = "remove the return type".to_string(); + } + labs.push( + Label::secondary((), func.rets_span.clone()) + .with_message(format!("Suggestion: {}", pp)), + ); + } + labels.extend(labs); if !labels.is_empty() { labels.push(Label::secondary((), func.fn_span.clone())); } } else { - if let Some(func) = rust_list.iter().find(|x| x.func_name == m.original_name) { + if let Some(func) = ids.remove(&m.original_name) { let (_, meta) = func.export_name.as_ref().unwrap(); labels.push( Label::primary((), meta.span().byte_range()) @@ -142,8 +178,8 @@ fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec Vec) -> Vec> { +fn check_args( + rust: &[syn::Type], + candid: &[String], + span: &Range, +) -> (Vec>, bool) { let mut labels = Vec::new(); if rust.len() != candid.len() { labels.push(Label::primary((), span.clone()).with_message("Argument count mismatch")); - return labels; + return (labels, true); } let args = rust.iter().zip(candid.iter()); for (rust_arg, candid_arg) in args { @@ -170,7 +220,49 @@ fn check_args(rust: &[syn::Type], candid: &[String], span: &Range) -> Vec ); } } - labels + (labels, false) +} +fn pp_args(args: &[(String, String)]) -> String { + args.iter() + .map(|(id, ty)| format!("{id}: {ty}")) + .collect::>() + .join(", ") +} +fn pp_rets(rets: &[String]) -> String { + match rets.len() { + 0 => "".to_string(), + 1 => format!("-> {}", rets[0]), + _ => format!("-> ({})", rets.join(", ")), + } +} +fn pp_attr(m: &Method) -> String { + let mode = if m.mode == "update" { + "update" + } else { + "query" + }; + let mut attr = Vec::new(); + if m.mode == "composite_query" { + attr.push("composite = true".to_string()); + } + if m.original_name != m.name { + attr.push(format!("name = \"{}\"", m.original_name.escape_debug())); + } + let attr = if attr.is_empty() { + String::new() + } else { + format!("({})", attr.join(", ")) + }; + format!("#[{mode}{attr}]") +} +fn pp_func(m: &Method) -> String { + format!( + "{}\nfn {}({}) {}", + pp_attr(m), + m.name, + pp_args(&m.args), + pp_rets(&m.rets) + ) } struct CDKMethod { func_name: syn::Ident, diff --git a/src/candid-checker/test.did b/src/candid-checker/test.did index 88667942f..dc872521a 100644 --- a/src/candid-checker/test.did +++ b/src/candid-checker/test.did @@ -5,5 +5,5 @@ service : { f:(my_type, vec Profile)->(List) composite_query; g:() -> (); inner:()->(); - missing:() -> () query; + missing:(int) -> (nat) query; } diff --git a/src/candid-checker/test.rs b/src/candid-checker/test.rs index a5fdbb770..b399bd79c 100644 --- a/src/candid-checker/test.rs +++ b/src/candid-checker/test.rs @@ -13,7 +13,7 @@ pub struct List(Option); #[ic_cdk::update] #[candid_method(update)] -pub async fn f(test: MyType, argument: Vec/* whatever */) -> List { +pub async fn f(test: MyType, argument: Vec/* whatever */) -> (List, u8) { } fn not_candid() {} From 2ac5884650bb644df4afd24ae60f820621b193ff Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 8 May 2024 11:33:06 -0700 Subject: [PATCH 4/5] add init args --- src/candid-checker/src/lib.rs | 64 +++++++++++++++++++++++++++++------ src/candid-checker/test.did | 2 +- src/candid-checker/test.rs | 3 ++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/candid-checker/src/lib.rs b/src/candid-checker/src/lib.rs index 708837873..338d29cb7 100644 --- a/src/candid-checker/src/lib.rs +++ b/src/candid-checker/src/lib.rs @@ -140,10 +140,7 @@ fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec>(); let (mut labs, need_pp) = check_args(&func.args, &args, &func.args_span); if need_pp { - let mut pp = pp_args(&m.args); - if pp.is_empty() { - pp = "remove the input argument".to_string(); - } + let pp = pp_args(&m.args); labs.push( Label::secondary((), func.args_span.clone()) .with_message(format!("Suggestion: {}", pp)), @@ -188,8 +185,13 @@ fn diff_did_and_rust(candid: &Output, rust_list: &[CDKMethod]) -> Vec Vec, +) -> Vec> { + let diag = Diagnostic::error().with_message("Checking init args"); + let mut notes = Vec::new(); + let mut labels = Vec::new(); + if let Some((name, func)) = rust.iter().find(|(_, m)| m.mode == "init") { + let args = candid.iter().map(|x| x.1.clone()).collect::>(); + let (mut labs, need_pp) = check_args(&func.args, &args, &func.args_span); + if need_pp { + let pp = pp_args(candid); + labs.push( + Label::secondary((), func.args_span.clone()) + .with_message(format!("Suggestion: {}", pp)), + ); + } + labels.extend(labs); + rust.remove(&name.clone()); + } else { + notes.push(format!( + "Init args is missing from Rust code. Use this signature to get started:\n{}", + pp_init_args(candid) + )); + } + if notes.is_empty() && labels.is_empty() { + Vec::new() + } else { + vec![diag.with_notes(notes).with_labels(labels)] + } +} fn check_args( rust: &[syn::Type], candid: &[String], @@ -223,10 +256,12 @@ fn check_args( (labels, false) } fn pp_args(args: &[(String, String)]) -> String { - args.iter() + let body = args + .iter() .map(|(id, ty)| format!("{id}: {ty}")) .collect::>() - .join(", ") + .join(", "); + format!("({body})") } fn pp_rets(rets: &[String]) -> String { match rets.len() { @@ -235,6 +270,9 @@ fn pp_rets(rets: &[String]) -> String { _ => format!("-> ({})", rets.join(", ")), } } +fn pp_init_args(args: &[(String, String)]) -> String { + format!("#[init]\nfn init{}", pp_args(args)) +} fn pp_attr(m: &Method) -> String { let mode = if m.mode == "update" { "update" @@ -257,7 +295,7 @@ fn pp_attr(m: &Method) -> String { } fn pp_func(m: &Method) -> String { format!( - "{}\nfn {}({}) {}", + "{}\nfn {}{} {}", pp_attr(m), m.name, pp_args(&m.args), @@ -332,6 +370,12 @@ fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { _ => vec![*ty.clone()], }, }; + let args_span = sig.paren_token.span; + let args_span = args_span.open().byte_range().start..args_span.close().byte_range().end; + let mut rets_span = sig.output.span().byte_range(); + if rets_span.end == 0 { + rets_span = args_span.end..args_span.end; + } mode.map(|mode| CDKMethod { func_name, export_name, @@ -340,8 +384,8 @@ fn get_cdk_function(attrs: &[Attribute], sig: &Signature) -> Option { rets, mode, fn_span: fn_span.unwrap(), - args_span: sig.inputs.span().byte_range(), - rets_span: sig.output.span().byte_range(), + args_span, + rets_span, }) } impl CDKMethod { diff --git a/src/candid-checker/test.did b/src/candid-checker/test.did index dc872521a..160b6569d 100644 --- a/src/candid-checker/test.did +++ b/src/candid-checker/test.did @@ -1,7 +1,7 @@ type my_type = principal; type Profile = record { name: text; age: nat8; country: text }; type List = opt record { head: blob; tail: List }; -service : { +service : (Profile) -> { f:(my_type, vec Profile)->(List) composite_query; g:() -> (); inner:()->(); diff --git a/src/candid-checker/test.rs b/src/candid-checker/test.rs index b399bd79c..ce7e54ca2 100644 --- a/src/candid-checker/test.rs +++ b/src/candid-checker/test.rs @@ -18,6 +18,9 @@ pub async fn f(test: MyType, argument: Vec/* whatever */) -> (List, u8) fn not_candid() {} +#[init] +fn take_init() {} + mod A { #[query(composite = true)] async fn inner(a: List) -> Result {} From efce935491cdf4bd5af1f0bf143123dee4b36bc0 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Wed, 15 May 2024 09:05:04 -0700 Subject: [PATCH 5/5] bump candid --- Cargo.lock | 116 +++++++++++++++------------------- src/candid-checker/Cargo.toml | 2 +- 2 files changed, 53 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abe3b7a6d..e6ac1380e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,31 +234,9 @@ dependencies = [ "anyhow", "binread", "byteorder", - "candid_derive 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "candid_derive", "hex", - "ic_principal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "leb128", - "num-bigint", - "num-traits", - "paste", - "pretty", - "serde", - "serde_bytes", - "stacker", - "thiserror", -] - -[[package]] -name = "candid" -version = "0.10.8" -source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" -dependencies = [ - "anyhow", - "binread", - "byteorder", - "candid_derive 0.6.6 (git+https://github.com/dfinity/candid.git?branch=configs)", - "hex", - "ic_principal 0.1.1 (git+https://github.com/dfinity/candid.git?branch=configs)", + "ic_principal", "leb128", "num-bigint", "num-traits", @@ -275,7 +253,7 @@ name = "candid-checker" version = "0.1.0" dependencies = [ "anyhow", - "candid_parser 0.2.0-beta.0", + "candid_parser 0.2.0-beta.1", "clap", "codespan-reporting", "proc-macro2", @@ -305,17 +283,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "candid_derive" -version = "0.6.6" -source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "candid_parser" version = "0.1.4" @@ -323,13 +290,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48a3da76f989cd350b7342c64c6c6008341bb6186f6832ef04e56dc50ba0fd76" dependencies = [ "anyhow", - "candid 0.10.7", + "candid", "codespan-reporting", "convert_case", "hex", "lalrpop", "lalrpop-util", - "logos", + "logos 0.13.0", "num-bigint", "pretty", "thiserror", @@ -337,18 +304,19 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.2.0-beta.0" -source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" +version = "0.2.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d55a6757ccf6afca45b37eacd5ed554287e42842a724b5d86a96db1809d802" dependencies = [ "anyhow", - "candid 0.10.8", + "candid", "codespan-reporting", "convert_case", "handlebars", "hex", "lalrpop", "lalrpop-util", - "logos", + "logos 0.14.0", "num-bigint", "pretty", "serde", @@ -1010,7 +978,7 @@ name = "ic-cdk" version = "0.13.2" dependencies = [ "anyhow", - "candid 0.10.7", + "candid", "ic-cdk-macros", "ic0", "rstest", @@ -1024,7 +992,7 @@ dependencies = [ name = "ic-cdk-bindgen" version = "0.1.3" dependencies = [ - "candid 0.10.7", + "candid", "candid_parser 0.1.4", "convert_case", "pretty", @@ -1034,7 +1002,7 @@ dependencies = [ name = "ic-cdk-e2e-tests" version = "0.1.0" dependencies = [ - "candid 0.10.7", + "candid", "cargo_metadata", "escargot", "futures", @@ -1051,7 +1019,7 @@ dependencies = [ name = "ic-cdk-macros" version = "0.13.2" dependencies = [ - "candid 0.10.7", + "candid", "proc-macro2", "quote", "serde", @@ -1076,7 +1044,7 @@ name = "ic-certified-map" version = "0.4.0" dependencies = [ "bincode", - "candid 0.10.7", + "candid", "hex", "ic-cdk", "serde", @@ -1089,7 +1057,7 @@ dependencies = [ name = "ic-ledger-types" version = "0.10.0" dependencies = [ - "candid 0.10.7", + "candid", "crc32fast", "hex", "ic-cdk", @@ -1104,7 +1072,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e05a81e0cbdf178228d72ace06c60ac7fa99927b49a238f9ccf5ef82eaced6" dependencies = [ - "candid 0.10.7", + "candid", "ciborium", "serde", "serde_bytes", @@ -1132,19 +1100,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "ic_principal" -version = "0.1.1" -source = "git+https://github.com/dfinity/candid.git?branch=configs#511629bd611b820d449c38f8b4ad96ac0b29a6b8" -dependencies = [ - "arbitrary", - "crc32fast", - "data-encoding", - "serde", - "sha2", - "thiserror", -] - [[package]] name = "id-arena" version = "2.2.1" @@ -1302,7 +1257,16 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" dependencies = [ - "logos-derive", + "logos-derive 0.13.0", +] + +[[package]] +name = "logos" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8" +dependencies = [ + "logos-derive 0.14.0", ] [[package]] @@ -1319,13 +1283,37 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "logos-codegen" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e31badd9de5131fdf4921f6473d457e3dd85b11b7f091ceb50e4df7c3eeb12a" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax 0.8.3", + "syn 2.0.60", +] + [[package]] name = "logos-derive" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" dependencies = [ - "logos-codegen", + "logos-codegen 0.13.0", +] + +[[package]] +name = "logos-derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" +dependencies = [ + "logos-codegen 0.14.0", ] [[package]] diff --git a/src/candid-checker/Cargo.toml b/src/candid-checker/Cargo.toml index 5e25a3d29..96b8b8883 100644 --- a/src/candid-checker/Cargo.toml +++ b/src/candid-checker/Cargo.toml @@ -16,7 +16,7 @@ required-features = ["exe"] [dependencies] syn = { version = "2.0", features = ["full", "visit", "extra-traits"] } proc-macro2 = { version = "1.0", features = ["span-locations"] } -candid_parser = { git = "https://github.com/dfinity/candid.git", branch = "configs" } +candid_parser = "0.2.0-beta.1" codespan-reporting = "0.11" clap = { version = "4", features = ["derive"], optional = true }