From c159019b8cc95fc9d6324ba8640d1a6c0cf9176f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 14 Sep 2023 15:32:38 +0100 Subject: [PATCH] Add support for custom tags Fixes https://github.com/hyperledger/solang/issues/1524 Signed-off-by: Sean Young --- src/sema/tags.rs | 52 +++++++++++++++++++++++++------------- tests/solana_tests/tags.rs | 11 ++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/sema/tags.rs b/src/sema/tags.rs index a7aa8bcd5..26389348e 100644 --- a/src/sema/tags.rs +++ b/src/sema/tags.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 use super::ast::{Diagnostic, Namespace, Parameter, Tag}; -use solang_parser::{doccomment::DocComment, pt}; +use solang_parser::{ + doccomment::{DocComment, DocCommentTag}, + pt, +}; use std::fmt::Write; /// Resolve the tags for a type from parsed doccomment @@ -23,18 +26,7 @@ pub fn resolve_tags( match c.tag.as_str() { "notice" | "author" | "title" | "dev" => { - // fold fields with the same name - if let Some(prev) = res.iter_mut().find(|e| e.tag == c.tag) { - prev.value.push(' '); - prev.value.push_str(&c.value); - } else { - res.push(Tag { - loc, - tag: c.tag.to_owned(), - value: c.value.to_owned(), - no: 0, - }) - } + fold_tag(loc, &mut res, c); } "param" if params.is_some() => { let v: Vec<&str> = c.value.splitn(2, char::is_whitespace).collect(); @@ -167,10 +159,21 @@ pub fn resolve_tags( } } _ => { - ns.diagnostics.push(Diagnostic::error( - tag_loc, - format!("tag '@{}' is not valid for {}", c.tag, ty), - )); + if let Some(custom) = c.tag.strip_prefix("custom:") { + if custom.is_empty() { + ns.diagnostics.push(Diagnostic::error( + tag_loc, + format!("custom tag '@{}' is missing a name", c.tag), + )); + } else { + fold_tag(loc, &mut res, c); + } + } else { + ns.diagnostics.push(Diagnostic::error( + tag_loc, + format!("tag '@{}' is not valid for {}", c.tag, ty), + )); + } } } } @@ -178,6 +181,21 @@ pub fn resolve_tags( res } +fn fold_tag(loc: pt::Loc, res: &mut Vec, doc_comment: &DocCommentTag) { + // fold fields with the same name + if let Some(prev) = res.iter_mut().find(|e| e.tag == doc_comment.tag) { + prev.value.push(' '); + prev.value.push_str(&doc_comment.value); + } else { + res.push(Tag { + loc, + tag: doc_comment.tag.to_owned(), + value: doc_comment.value.to_owned(), + no: 0, + }) + } +} + /// Render tags as plain text string pub fn render(tags: &[Tag]) -> String { let mut s = String::new(); diff --git a/tests/solana_tests/tags.rs b/tests/solana_tests/tags.rs index 2b96453aa..18d7f33ee 100644 --- a/tests/solana_tests/tags.rs +++ b/tests/solana_tests/tags.rs @@ -15,6 +15,9 @@ fn contract() { /// @author Mr Foo /// @dev this is /// a contract + /// @custom:meh words for + /// @custom:meh custom tag + /// @custom: custom tag @program_id("Seed23VDZ9HFCfKvFwmemB6dpi25n5XjZdP52B2RUmh") contract test { /// @dev construct this @@ -24,6 +27,11 @@ fn contract() { Target::Solana, ); + assert_eq!( + ns.diagnostics.first_error(), + "custom tag '@custom:' is missing a name" + ); + assert_eq!(ns.contracts[0].tags[0].tag, "notice"); assert_eq!(ns.contracts[0].tags[0].value, "So Hello, World"); @@ -36,6 +44,9 @@ fn contract() { assert_eq!(ns.contracts[0].tags[3].tag, "dev"); assert_eq!(ns.contracts[0].tags[3].value, "this is\na contract"); + assert_eq!(ns.contracts[0].tags[4].tag, "custom:meh"); + assert_eq!(ns.contracts[0].tags[4].value, "words for custom tag"); + let constructor = ns .functions .iter()