Эх сурвалжийг харах

solc allows @param tag for return values (#1539)

@return should be used, warn about this.

https://github.com/hyperledger/solang/issues/1533

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 жил өмнө
parent
commit
95f4ad0843

+ 26 - 2
src/sema/tags.rs

@@ -57,10 +57,34 @@ pub fn resolve_tags(
                             value,
                         });
                     }
+                } else if let Some(Some(no)) =
+                    returns.map(|params| params.iter().position(|p| p.name_as_str() == name))
+                {
+                    if let Some(other) = res.iter().find(|e| e.tag == "return" && e.no == no) {
+                        // Note: solc does not detect this problem
+                        ns.diagnostics.push(Diagnostic::warning_with_note(
+                            loc,
+                            format!("duplicate tag '@param' for '{name}'"),
+                            other.loc,
+                            format!("previous tag '@param' for '{name}'"),
+                        ));
+                    } else {
+                        ns.diagnostics.push(Diagnostic::warning(
+                            loc,
+                            format!("'@param' used in stead of '@return' for '{name}'"),
+                        ));
+
+                        res.push(Tag {
+                            loc,
+                            tag: String::from("return"),
+                            no,
+                            value,
+                        });
+                    }
                 } else {
                     ns.diagnostics.push(Diagnostic::error(
                         value_loc,
-                        format!("tag '@param' no field '{name}'"),
+                        format!("function parameter named '{name}' not found"),
                     ));
                 }
             }
@@ -128,7 +152,7 @@ pub fn resolve_tags(
                     } else {
                         ns.diagnostics.push(Diagnostic::error(
                             pt::Loc::File(file_no, c.value_offset, c.value_offset + c.value.len()),
-                            format!("tag '@return' no matching return value '{}'", c.value),
+                            format!("function return value named '{name}' not found"),
                         ));
                     }
                 }

+ 1 - 1
tests/contract_testcases/polkadot/tags/event_tag_01.sol

@@ -4,4 +4,4 @@
             uint32 f
         );
 // ---- Expect: diagnostics ----
-// error: 2:20-21: tag '@param' no field 'g'
+// error: 2:20-21: function parameter named 'g' not found

+ 1 - 1
tests/contract_testcases/polkadot/tags/functions_01.sol

@@ -5,4 +5,4 @@
             function foo(int f) public {}
         }
 // ---- Expect: diagnostics ----
-// error: 4:24-25: tag '@param' no field 'g'
+// error: 4:24-25: function parameter named 'g' not found

+ 1 - 1
tests/contract_testcases/polkadot/tags/struct_tag_01.sol

@@ -4,4 +4,4 @@
             uint32 f;
         }
 // ---- Expect: diagnostics ----
-// error: 2:20-21: tag '@param' no field 'g'
+// error: 2:20-21: function parameter named 'g' not found

+ 3 - 3
tests/contract_testcases/solana/tags.sol

@@ -31,6 +31,6 @@ contract C {
 }
 
 // ---- Expect: diagnostics ----
-// error: 21:15-18: tag '@return' no matching return value 'feh'
-// error: 22:15-18: tag '@return' no matching return value 'foo'
-// error: 28:15-18: tag '@return' no matching return value 'foo'
+// error: 21:15-18: function return value named 'feh' not found
+// error: 22:15-18: function return value named 'foo' not found
+// error: 28:15-18: function return value named 'foo' not found

+ 1 - 1
tests/evm.rs

@@ -249,7 +249,7 @@ fn ethereum_solidity_tests() {
         })
         .sum();
 
-    assert_eq!(errors, 1029);
+    assert_eq!(errors, 1024);
 }
 
 fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {

+ 34 - 0
tests/solana_tests/tags.rs

@@ -211,6 +211,40 @@ fn functions() {
     assert_eq!(func.tags[2].tag, "inheritdoc");
     assert_eq!(func.tags[2].value, "b");
     assert_eq!(func.tags[2].no, 0);
+
+    let ns = parse_and_resolve(
+        r#"
+        contract c is b {
+            /// @return x sadad
+            /// @param k is a boolean
+            /// @custom:smtchecker abstract-function-nondet
+            function foo(int x) public pure returns (int a, bool k) {}
+        }
+
+        contract b {}"#,
+        Target::Solana,
+    );
+
+    assert_eq!(ns.diagnostics.len(), 4);
+
+    assert_eq!(
+        ns.diagnostics.first_error(),
+        "function return value named 'x' not found"
+    );
+
+    assert_eq!(
+        ns.diagnostics.first_warning().message,
+        "'@param' used in stead of '@return' for 'k'"
+    );
+
+    let func = ns.functions.iter().find(|func| func.name == "foo").unwrap();
+
+    assert_eq!(func.tags[0].tag, "return");
+    assert_eq!(func.tags[0].value, "is a boolean");
+    assert_eq!(func.tags[0].no, 1);
+    assert_eq!(func.tags[1].tag, "custom:smtchecker");
+    assert_eq!(func.tags[1].value, "abstract-function-nondet");
+    assert_eq!(func.tags[1].no, 0);
 }
 
 #[test]