diff --git a/src/Neo.Compiler.CSharp/CompilationContext.cs b/src/Neo.Compiler.CSharp/CompilationContext.cs index e745ad480..57b3a7653 100644 --- a/src/Neo.Compiler.CSharp/CompilationContext.cs +++ b/src/Neo.Compiler.CSharp/CompilationContext.cs @@ -426,31 +426,37 @@ private void ProcessClass(SemanticModel model, INamedTypeSymbol symbol) bool isSmartContract = isPublic && !isAbstract && isContractType; if (isSmartContract) { - if (scTypeFound) throw new CompilationException(DiagnosticId.MultiplyContracts, $"Only one smart contract is allowed."); + if (scTypeFound) throw new CompilationException(DiagnosticId.MultiplyContracts, "Only one smart contract is allowed."); scTypeFound = true; foreach (var attribute in symbol.GetAttributesWithInherited()) { + if (attribute.AttributeClass!.IsSubclassOf(nameof(ManifestExtraAttribute))) + { + manifestExtra[ManifestExtraAttribute.AttributeType[attribute.AttributeClass!.Name]] = (string)attribute.ConstructorArguments[0].Value!; + continue; + } + switch (attribute.AttributeClass!.Name) { case nameof(DisplayNameAttribute): displayName = (string)attribute.ConstructorArguments[0].Value!; break; - case nameof(scfx.Neo.SmartContract.Framework.Attributes.ContractSourceCodeAttribute): + case nameof(ContractSourceCodeAttribute): Source = (string)attribute.ConstructorArguments[0].Value!; break; - case nameof(scfx.Neo.SmartContract.Framework.Attributes.ManifestExtraAttribute): + case nameof(ManifestExtraAttribute): manifestExtra[(string)attribute.ConstructorArguments[0].Value!] = (string)attribute.ConstructorArguments[1].Value!; break; - case nameof(scfx.Neo.SmartContract.Framework.Attributes.ContractPermissionAttribute): + case nameof(ContractPermissionAttribute): permissions.Add((string)attribute.ConstructorArguments[0].Value!, attribute.ConstructorArguments[1].Values.Select(p => (string)p.Value!).ToArray()); break; - case nameof(scfx.Neo.SmartContract.Framework.Attributes.ContractTrustAttribute): + case nameof(ContractTrustAttribute): string trust = (string)attribute.ConstructorArguments[0].Value!; if (!ValidateContractTrust(trust)) throw new ArgumentException($"The value {trust} is not a valid one for ContractTrust"); trusts.Add(trust); break; - case nameof(scfx.Neo.SmartContract.Framework.Attributes.SupportedStandardsAttribute): + case nameof(SupportedStandardsAttribute): supportedStandards.UnionWith( attribute.ConstructorArguments[0].Values .Select(p => p.Value) diff --git a/src/Neo.SmartContract.Framework/Attributes/AuthorAttribute.cs b/src/Neo.SmartContract.Framework/Attributes/AuthorAttribute.cs new file mode 100644 index 000000000..bab7fb99d --- /dev/null +++ b/src/Neo.SmartContract.Framework/Attributes/AuthorAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.SmartContract.Framework.Attributes +{ + [AttributeUsage(AttributeTargets.Class)] + public class AuthorAttribute : ManifestExtraAttribute + { + public AuthorAttribute(string value) : base(AttributeType[nameof(AuthorAttribute)], value) + { + } + } +} diff --git a/src/Neo.SmartContract.Framework/Attributes/DescriptionAttribute.cs b/src/Neo.SmartContract.Framework/Attributes/DescriptionAttribute.cs new file mode 100644 index 000000000..ab1812bee --- /dev/null +++ b/src/Neo.SmartContract.Framework/Attributes/DescriptionAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.SmartContract.Framework.Attributes +{ + [AttributeUsage(AttributeTargets.Class)] + public class DescriptionAttribute : ManifestExtraAttribute + { + public DescriptionAttribute(string value) : base(AttributeType[nameof(DescriptionAttribute)], value) + { + } + } +} diff --git a/src/Neo.SmartContract.Framework/Attributes/EmailAttribute.cs b/src/Neo.SmartContract.Framework/Attributes/EmailAttribute.cs new file mode 100644 index 000000000..22c16a28d --- /dev/null +++ b/src/Neo.SmartContract.Framework/Attributes/EmailAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.SmartContract.Framework.Attributes +{ + [AttributeUsage(AttributeTargets.Class)] + public class EmailAttribute : ManifestExtraAttribute + { + public EmailAttribute(string value) : base(AttributeType[nameof(EmailAttribute)], value) + { + } + } +} diff --git a/src/Neo.SmartContract.Framework/Attributes/ManifestExtraAttribute.cs b/src/Neo.SmartContract.Framework/Attributes/ManifestExtraAttribute.cs index 0ce97cf59..cf4ac1a66 100644 --- a/src/Neo.SmartContract.Framework/Attributes/ManifestExtraAttribute.cs +++ b/src/Neo.SmartContract.Framework/Attributes/ManifestExtraAttribute.cs @@ -1,14 +1,15 @@ // Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.SmartContract.Framework is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// +// The Neo.SmartContract.Framework is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. using System; +using System.Collections.Generic; namespace Neo.SmartContract.Framework.Attributes { @@ -18,5 +19,13 @@ public class ManifestExtraAttribute : Attribute public ManifestExtraAttribute(string key, string value) { } + + internal static readonly Dictionary AttributeType = new Dictionary + { + { nameof(AuthorAttribute), "Author" }, + { nameof(EmailAttribute), "E-mail" }, + { nameof(DescriptionAttribute), "Description" }, + { nameof(VersionAttribute), "Version" }, + }; } } diff --git a/src/Neo.SmartContract.Framework/Attributes/VersionAttribute.cs b/src/Neo.SmartContract.Framework/Attributes/VersionAttribute.cs new file mode 100644 index 000000000..eb62fa3bf --- /dev/null +++ b/src/Neo.SmartContract.Framework/Attributes/VersionAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.SmartContract.Framework.Attributes +{ + [AttributeUsage(AttributeTargets.Class)] + public class VersionAttribute : ManifestExtraAttribute + { + public VersionAttribute(string value) : base(AttributeType[nameof(VersionAttribute)], value) + { + } + } +} diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs new file mode 100644 index 000000000..9e7aff6ea --- /dev/null +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs @@ -0,0 +1,22 @@ +using Neo.SmartContract.Framework.Attributes; + +namespace Neo.SmartContract.Framework.UnitTests.TestClasses +{ + [Author("core-dev")] + [Email("core@neo.org")] + [Version("v3.6.3")] + [Description("This is a test contract.")] + [ManifestExtra("ExtraKey", "ExtraValue")] + public class Contract_ManifestAttribute : SmartContract + { + [NoReentrant] + public void reentrantTest(int value) + { + if (value == 0) return; + if (value == 123) + { + reentrantTest(0); + } + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/ManifestAttributeTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/ManifestAttributeTest.cs new file mode 100644 index 000000000..d7d23bd26 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/ManifestAttributeTest.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Neo.SmartContract.Framework.UnitTests; + +[TestClass] +public class ManifestAttributeTest +{ + [TestMethod] + public void TestManifestAttribute() + { + var testEngine = new TestEngine.TestEngine(); + testEngine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_ManifestAttribute.cs"); + + var extra = testEngine.Manifest!.Extra; + + Assert.AreEqual(5, extra.Count); + // [Author("core-dev")] + // [Email("core@neo.org")] + // [Version("v3.6.3")] + // [Description("This is a test contract.")] + // [ManifestExtra("ExtraKey", "ExtraValue")] + Assert.AreEqual("core-dev", extra["Author"]!.GetString()); + Assert.AreEqual("core@neo.org", extra["E-mail"]!.GetString()); + Assert.AreEqual("v3.6.3", extra["Version"]!.GetString()); + Assert.AreEqual("This is a test contract.", extra["Description"]!.GetString()); + Assert.AreEqual("ExtraValue", extra["ExtraKey"]!.GetString()); + } +}