Jelajahi Sumber

Add support for custom tags (#1529)

Fixes https://github.com/hyperledger/solang/issues/1524

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 tahun lalu
induk
melakukan
f8d5a142c7
2 mengubah file dengan 46 tambahan dan 17 penghapusan
  1. 35 17
      src/sema/tags.rs
  2. 11 0
      tests/solana_tests/tags.rs

+ 35 - 17
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,
-                    })
-                }
+                add_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 {
+                        add_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
 }
 
+/// Add a new doc comment as a tag, or append to existing one
+fn add_tag(loc: pt::Loc, res: &mut Vec<Tag>, doc_comment: &DocCommentTag) {
+    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();

+ 11 - 0
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()