diff --git a/src/Neo.SmartContract.Analyzer/AnalyzerReleases.Unshipped.md b/src/Neo.SmartContract.Analyzer/AnalyzerReleases.Unshipped.md index c194dea6d..72a71f3b2 100644 --- a/src/Neo.SmartContract.Analyzer/AnalyzerReleases.Unshipped.md +++ b/src/Neo.SmartContract.Analyzer/AnalyzerReleases.Unshipped.md @@ -28,3 +28,6 @@ | NC4026 | Usage | Error | SystemDiagnosticsUsageAnalyzer | | NC4027 | Usage | Warning | CatchOnlySystemExceptionAnalyzer | | NC4028 | Usage | Error | SystemThreadingUsageAnalyzer | +| NC5050 | Performance | Warning | StoragePatternAnalyzer - Repeated Access | +| NC5051 | Performance | Warning | StoragePatternAnalyzer - Large Key | +| NC5052 | Performance | Warning | StoragePatternAnalyzer - Storage In Loop | diff --git a/src/Neo.SmartContract.Analyzer/ArrayMethodsUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/ArrayMethodsUsageAnalyzer.cs new file mode 100644 index 000000000..f52971723 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/ArrayMethodsUsageAnalyzer.cs @@ -0,0 +1,88 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// ArrayMethodsUsageAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ArrayMethodsUsageAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4042"; + + // Array methods that are not supported in Neo smart contracts + // Based on the methods implemented in src\Neo.Compiler.CSharp\MethodConvert\System\SystemCall.Array.cs + private readonly string[] _unsupportedArrayMethods = { + "AsReadOnly", "BinarySearch", "Clear", "ConstrainedCopy", "ConvertAll", + "Copy", "CopyTo", "CreateInstance", "Exists", "Fill", + "Find", "FindAll", "FindIndex", "FindLast", "FindLastIndex", + "ForEach", "GetEnumerator", "GetHashCode", "GetLongLength", "GetLowerBound", + "GetType", "GetUpperBound", "GetValue", "IndexOf", "Initialize", + "LastIndexOf", "Resize", "SetValue", "Sort", "TrueForAll" + // Supported Array methods (not in this list): + // - Length (property) + // - Reverse + }; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + "Unsupported Array method is used", + "Unsupported Array method: {0}", + "Method", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.InvocationExpression); + } + + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) + { + if (context.Node is not InvocationExpressionSyntax invocationExpression) return; + + // Check if it's a static Array method + if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccess && + memberAccess.Expression is IdentifierNameSyntax identifier && + identifier.Identifier.Text == "Array") + { + var methodName = memberAccess.Name.Identifier.Text; + if (_unsupportedArrayMethods.Contains(methodName)) + { + var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), methodName); + context.ReportDiagnostic(diagnostic); + } + return; + } + + // Check if it's an instance method on an array + var methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; + if (methodSymbol != null && + methodSymbol.ReceiverType != null && + methodSymbol.ReceiverType.TypeKind == TypeKind.Array && + _unsupportedArrayMethods.Contains(methodSymbol.Name)) + { + var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), methodSymbol.Name); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/BitOperationsUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/BitOperationsUsageAnalyzer.cs new file mode 100644 index 000000000..caface225 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/BitOperationsUsageAnalyzer.cs @@ -0,0 +1,86 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// BitOperationsUsageAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class BitOperationsUsageAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4043"; + + // BitOperations methods that are not supported in Neo smart contracts + // Based on the methods implemented in src\Neo.Compiler.CSharp\MethodConvert\System\SystemCall.Register.cs + private readonly string[] _unsupportedBitOperationsMethods = { + "TrailingZeroCount", + "IsPow2", + "RotateRight" + // Supported BitOperations methods (not in this list): + // - LeadingZeroCount + // - Log2 + // - PopCount + // - RotateLeft + }; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + "Unsupported BitOperations method is used", + "Unsupported BitOperations method: {0}", + "Method", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.InvocationExpression); + } + + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) + { + if (context.Node is not InvocationExpressionSyntax invocationExpression) return; + + // Check if it's a BitOperations method + if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccess && + memberAccess.Expression is IdentifierNameSyntax identifier && + identifier.Identifier.Text == "BitOperations") + { + var methodName = memberAccess.Name.Identifier.Text; + if (_unsupportedBitOperationsMethods.Contains(methodName)) + { + var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), methodName); + context.ReportDiagnostic(diagnostic); + } + return; + } + + // Check if it's a method from System.Numerics.BitOperations + var methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; + if (methodSymbol != null && + methodSymbol.ContainingType?.ToString() == "System.Numerics.BitOperations" && + _unsupportedBitOperationsMethods.Contains(methodSymbol.Name)) + { + var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), methodSymbol.Name); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/CheckWitnessUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/CheckWitnessUsageAnalyzer.cs new file mode 100644 index 000000000..60d0bc32f --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/CheckWitnessUsageAnalyzer.cs @@ -0,0 +1,100 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// CheckWitnessUsageAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class CheckWitnessUsageAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4029"; + + private static readonly LocalizableString Title = "CheckWitness result should be used"; + private static readonly LocalizableString MessageFormat = "The result of CheckWitness should be used: {0}"; + private static readonly LocalizableString Description = "CheckWitness results should be used to ensure proper authentication."; + private const string Category = "Security"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); + } + + private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) + { + var invocation = (InvocationExpressionSyntax)context.Node; + + // Check if this is a call to Runtime.CheckWitness + if (IsCheckWitnessCall(invocation, context.SemanticModel)) + { + // Check if the result is being used properly + if (!IsResultVerified(invocation)) + { + var diagnostic = Diagnostic.Create(Rule, invocation.GetLocation(), "The result of Runtime.CheckWitness(...) should be used in a condition, assigned to a variable, passed to ExecutionEngine.Assert, or otherwise utilized"); + context.ReportDiagnostic(diagnostic); + } + } + } + + private bool IsCheckWitnessCall(InvocationExpressionSyntax invocation, SemanticModel semanticModel) + { + if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) + { + var symbol = semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null) return false; + + // Check if it's Runtime.CheckWitness + if (symbol.Name == "CheckWitness" && + symbol.ContainingType.Name == "Runtime" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + return true; + } + } + return false; + } + + private bool IsResultVerified(InvocationExpressionSyntax invocation) + { + // Get the parent of the invocation + var parent = invocation.Parent; + + // The only case where the result is not being used is when the invocation + // is directly used as a statement without capturing the result + if (parent is ExpressionStatementSyntax) + { + return false; + } + + // In all other cases, the result is being used in some way + // (as a condition, in an expression, assigned to a variable, etc.) + return true; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/CheckWitnessUsageCodeFixProvider.cs b/src/Neo.SmartContract.Analyzer/CheckWitnessUsageCodeFixProvider.cs new file mode 100644 index 000000000..cadd8f75b --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/CheckWitnessUsageCodeFixProvider.cs @@ -0,0 +1,160 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// CheckWitnessUsageCodeFixProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.SmartContract.Analyzer +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CheckWitnessUsageCodeFixProvider)), Shared] + public class CheckWitnessUsageCodeFixProvider : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds => + ImmutableArray.Create(CheckWitnessUsageAnalyzer.DiagnosticId); + + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root == null) return; + + var diagnostic = context.Diagnostics.First(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var node = root.FindNode(diagnosticSpan); + + if (node is InvocationExpressionSyntax invocation) + { + // Register code fix for wrapping with ExecutionEngine.Assert + context.RegisterCodeFix( + CodeAction.Create( + title: "Wrap with ExecutionEngine.Assert", + createChangedDocument: c => WrapWithAssertAsync(context.Document, invocation, c), + equivalenceKey: "WrapWithAssert"), + diagnostic); + + // Register code fix for using in if condition + context.RegisterCodeFix( + CodeAction.Create( + title: "Use in if condition", + createChangedDocument: c => UseInIfConditionAsync(context.Document, invocation, c), + equivalenceKey: "UseInIfCondition"), + diagnostic); + } + } + + private async Task WrapWithAssertAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root == null) return document; + + // Create ExecutionEngine.Assert(Runtime.CheckWitness(...)) + var assertInvocation = SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("ExecutionEngine"), + SyntaxFactory.IdentifierName("Assert") + ), + SyntaxFactory.ArgumentList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.Argument(invocation.WithoutLeadingTrivia()) + ) + ) + ).WithLeadingTrivia(invocation.GetLeadingTrivia()) + .WithAdditionalAnnotations(Formatter.Annotation); + + // If the invocation is part of an expression statement, replace the entire statement + if (invocation.Parent is ExpressionStatementSyntax expressionStatement) + { + var newExpressionStatement = SyntaxFactory.ExpressionStatement(assertInvocation) + .WithTrailingTrivia(expressionStatement.GetTrailingTrivia()); + var newRoot = root.ReplaceNode(expressionStatement, newExpressionStatement); + return document.WithSyntaxRoot(newRoot); + } + else + { + // Otherwise just replace the invocation + var newRoot = root.ReplaceNode(invocation, assertInvocation); + return document.WithSyntaxRoot(newRoot); + } + } + + private async Task UseInIfConditionAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root == null) return document; + + // Find the containing statement + var containingStatement = invocation.FirstAncestorOrSelf(); + if (containingStatement == null) return document; + + // Create if statement with CheckWitness as condition + var ifStatement = SyntaxFactory.IfStatement( + invocation.WithoutLeadingTrivia(), + SyntaxFactory.Block( + SyntaxFactory.List() + ) + ).WithLeadingTrivia(invocation.GetLeadingTrivia()) + .WithAdditionalAnnotations(Formatter.Annotation); + + // Add a comment to the empty block + var commentTrivia = SyntaxFactory.Comment("// Add your code here"); + var emptyStatement = SyntaxFactory.EmptyStatement() + .WithLeadingTrivia(commentTrivia) + .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); + + ifStatement = ifStatement.WithStatement( + SyntaxFactory.Block( + SyntaxFactory.SingletonList(emptyStatement) + ) + ); + + // Add else block with throw + var throwStatement = SyntaxFactory.ThrowStatement( + SyntaxFactory.ObjectCreationExpression( + SyntaxFactory.IdentifierName("Exception"), + SyntaxFactory.ArgumentList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.Argument( + SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, + SyntaxFactory.Literal("No authorization.") + ) + ) + ) + ), + null + ) + ); + + ifStatement = ifStatement.WithElse( + SyntaxFactory.ElseClause( + SyntaxFactory.Block( + SyntaxFactory.SingletonList(throwStatement) + ) + ) + ); + + // Replace the containing statement with the if statement + var newRoot = root.ReplaceNode(containingStatement, ifStatement); + return document.WithSyntaxRoot(newRoot); + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/CollectionTypesUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/CollectionTypesUsageAnalyzer.cs index 1d0a124f7..a0d508f6c 100644 --- a/src/Neo.SmartContract.Analyzer/CollectionTypesUsageAnalyzer.cs +++ b/src/Neo.SmartContract.Analyzer/CollectionTypesUsageAnalyzer.cs @@ -24,7 +24,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Xunit.Sdk; namespace Neo.SmartContract.Analyzer { @@ -91,7 +90,9 @@ private void AnalyzeOperation(OperationAnalysisContext context) if (context.Operation is not IVariableDeclarationOperation variableDeclaration) return; var variableType = variableDeclaration.GetDeclaredVariables()[0].Type; - var originalType = variableType.OriginalDefinition.ToString() ?? throw new NullException("originalType is null"); + var originalType = variableType.OriginalDefinition.ToString(); + if (originalType is null) + throw new InvalidOperationException("Original type definition is null"); if (_unsupportedCollectionTypes.Contains(originalType)) { diff --git a/src/Neo.SmartContract.Analyzer/ContractAttributeAnalyzer.cs b/src/Neo.SmartContract.Analyzer/ContractAttributeAnalyzer.cs new file mode 100644 index 000000000..6ba389ab4 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/ContractAttributeAnalyzer.cs @@ -0,0 +1,251 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// ContractAttributeAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ContractAttributeAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticIdMissingAttributes = "NC4046"; + public const string DiagnosticIdInvalidAttribute = "NC4047"; + + private static readonly LocalizableString TitleMissingAttributes = "Missing recommended contract attributes"; + private static readonly LocalizableString MessageFormatMissingAttributes = "Smart contract class is missing recommended attributes: {0}"; + private static readonly LocalizableString DescriptionMissingAttributes = "Smart contract classes should include recommended attributes for better metadata."; + + private static readonly LocalizableString TitleInvalidAttribute = "Invalid contract attribute usage"; + private static readonly LocalizableString MessageFormatInvalidAttribute = "Invalid usage of contract attribute: {0}"; + private static readonly LocalizableString DescriptionInvalidAttribute = "Contract attributes should be used correctly according to Neo smart contract specifications."; + + private const string Category = "Usage"; + + private static readonly DiagnosticDescriptor RuleMissingAttributes = new( + DiagnosticIdMissingAttributes, + TitleMissingAttributes, + MessageFormatMissingAttributes, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionMissingAttributes); + + private static readonly DiagnosticDescriptor RuleInvalidAttribute = new( + DiagnosticIdInvalidAttribute, + TitleInvalidAttribute, + MessageFormatInvalidAttribute, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionInvalidAttribute); + + // List of recommended contract attributes + private readonly string[] _recommendedAttributes = { + // "DisplayName", + "ContractDescription", + "ContractVersion", + "ContractPermission" + }; + + // List of all valid contract attributes + private readonly string[] _validAttributes = { + "DisplayName", + "ContractDescription", + "ContractVersion", + "ContractPermission", + "ContractAuthor", + "ContractEmail", + "ContractSourceCode", + "SupportedStandards", + "ManifestExtra", + "Contract", + "ContractHash" + }; + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(RuleMissingAttributes, RuleInvalidAttribute); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeClassDeclaration, SyntaxKind.ClassDeclaration); + context.RegisterSyntaxNodeAction(AnalyzeAttribute, SyntaxKind.Attribute); + } + + private void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context) + { + var classDeclaration = (ClassDeclarationSyntax)context.Node; + + // Check if this is a smart contract class (inherits from SmartContract) + if (!IsSmartContractClass(context.SemanticModel, classDeclaration)) + return; + + // Check for recommended attributes + var presentAttributes = new HashSet(); + foreach (var attributeList in classDeclaration.AttributeLists) + { + foreach (var attribute in attributeList.Attributes) + { + var attributeName = GetAttributeName(attribute); + if (_recommendedAttributes.Contains(attributeName)) + { + presentAttributes.Add(attributeName); + } + } + } + + // Report missing recommended attributes + var missingAttributes = _recommendedAttributes.Except(presentAttributes).ToList(); + if (missingAttributes.Count > 0) + { + var diagnostic = Diagnostic.Create(RuleMissingAttributes, + classDeclaration.Identifier.GetLocation(), + string.Join(", ", missingAttributes)); + context.ReportDiagnostic(diagnostic); + } + } + + private void AnalyzeAttribute(SyntaxNodeAnalysisContext context) + { + var attribute = (AttributeSyntax)context.Node; + var attributeName = GetAttributeName(attribute); + + // Check if this is a contract attribute + if (!_validAttributes.Contains(attributeName)) + return; + + // Get the parent class + var classDeclaration = attribute.FirstAncestorOrSelf(); + if (classDeclaration == null) + return; + + // Check if this is a smart contract class + if (!IsSmartContractClass(context.SemanticModel, classDeclaration)) + return; + + // Validate specific attributes + switch (attributeName) + { + case "DisplayName": + ValidateDisplayNameAttribute(context, attribute); + break; + case "ContractVersion": + ValidateContractVersionAttribute(context, attribute); + break; + case "ContractPermission": + ValidateContractPermissionAttribute(context, attribute); + break; + case "SupportedStandards": + ValidateSupportedStandardsAttribute(context, attribute); + break; + } + } + + private bool IsSmartContractClass(SemanticModel semanticModel, ClassDeclarationSyntax classDeclaration) + { + if (classDeclaration.BaseList == null) + return false; + + foreach (var baseType in classDeclaration.BaseList.Types) + { + var typeInfo = semanticModel.GetTypeInfo(baseType.Type); + if (typeInfo.Type?.Name == "SmartContract" && + typeInfo.Type.ContainingNamespace?.ToString() == "Neo.SmartContract.Framework") + { + return true; + } + } + + return false; + } + + private string GetAttributeName(AttributeSyntax attribute) + { + var name = attribute.Name.ToString(); + if (name.EndsWith("Attribute")) + name = name.Substring(0, name.Length - "Attribute".Length); + return name; + } + + private void ValidateDisplayNameAttribute(SyntaxNodeAnalysisContext context, AttributeSyntax attribute) + { + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + attribute.GetLocation(), + "DisplayName attribute requires a string parameter"); + context.ReportDiagnostic(diagnostic); + return; + } + + var argument = attribute.ArgumentList.Arguments[0].Expression; + if (argument is not LiteralExpressionSyntax literalExpression || + literalExpression.Kind() != SyntaxKind.StringLiteralExpression) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + argument.GetLocation(), + "DisplayName attribute parameter must be a string literal"); + context.ReportDiagnostic(diagnostic); + } + } + + private void ValidateContractVersionAttribute(SyntaxNodeAnalysisContext context, AttributeSyntax attribute) + { + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + attribute.GetLocation(), + "ContractVersion attribute requires a string parameter"); + context.ReportDiagnostic(diagnostic); + return; + } + + var argument = attribute.ArgumentList.Arguments[0].Expression; + if (argument is not LiteralExpressionSyntax literalExpression || + literalExpression.Kind() != SyntaxKind.StringLiteralExpression) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + argument.GetLocation(), + "ContractVersion attribute parameter must be a string literal"); + context.ReportDiagnostic(diagnostic); + } + } + + private void ValidateContractPermissionAttribute(SyntaxNodeAnalysisContext context, AttributeSyntax attribute) + { + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + attribute.GetLocation(), + "ContractPermission attribute requires at least one parameter"); + context.ReportDiagnostic(diagnostic); + } + } + + private void ValidateSupportedStandardsAttribute(SyntaxNodeAnalysisContext context, AttributeSyntax attribute) + { + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + var diagnostic = Diagnostic.Create(RuleInvalidAttribute, + attribute.GetLocation(), + "SupportedStandards attribute requires at least one parameter"); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/ContractAttributeCodeFixProvider.cs b/src/Neo.SmartContract.Analyzer/ContractAttributeCodeFixProvider.cs new file mode 100644 index 000000000..7ff11d412 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/ContractAttributeCodeFixProvider.cs @@ -0,0 +1,256 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// ContractAttributeCodeFixProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.SmartContract.Analyzer +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ContractAttributeCodeFixProvider)), Shared] + public class ContractAttributeCodeFixProvider : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds => + ImmutableArray.Create(ContractAttributeAnalyzer.DiagnosticIdMissingAttributes, + ContractAttributeAnalyzer.DiagnosticIdInvalidAttribute); + + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root == null) return; + + var diagnostic = context.Diagnostics.First(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var node = root.FindNode(diagnosticSpan); + + // Handle different diagnostic IDs + switch (diagnostic.Id) + { + case ContractAttributeAnalyzer.DiagnosticIdMissingAttributes: + if (node is IdentifierNameSyntax identifier && + node.Parent is ClassDeclarationSyntax classDeclaration) + { + // Get the missing attributes from the diagnostic message + var message = diagnostic.GetMessage(); + var startIndex = message.IndexOf(':') + 1; + var missingAttributesString = message.Substring(startIndex).Trim(); + var missingAttributes = missingAttributesString.Split(',').Select(a => a.Trim()).ToList(); + + // Register code fix for missing attributes + context.RegisterCodeFix( + CodeAction.Create( + title: "Add missing contract attributes", + createChangedDocument: c => AddMissingAttributesAsync(context.Document, classDeclaration, missingAttributes, c), + equivalenceKey: "AddMissingAttributes"), + diagnostic); + } + break; + + case ContractAttributeAnalyzer.DiagnosticIdInvalidAttribute: + if (node is AttributeSyntax attribute) + { + // Register code fix for invalid attribute + context.RegisterCodeFix( + CodeAction.Create( + title: "Fix attribute usage", + createChangedDocument: c => FixAttributeUsageAsync(context.Document, attribute, c), + equivalenceKey: "FixAttributeUsage"), + diagnostic); + } + break; + } + } + + private async Task AddMissingAttributesAsync(Document document, ClassDeclarationSyntax classDeclaration, List missingAttributes, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root == null) return document; + + var newAttributeLists = classDeclaration.AttributeLists.ToList(); + + foreach (var attributeName in missingAttributes) + { + AttributeSyntax newAttribute; + + switch (attributeName) + { + case "DisplayName": + newAttribute = CreateAttributeWithStringArgument("DisplayName", classDeclaration.Identifier.Text); + break; + case "ContractDescription": + newAttribute = CreateAttributeWithStringArgument("ContractDescription", "Description of " + classDeclaration.Identifier.Text); + break; + case "ContractVersion": + newAttribute = CreateAttributeWithStringArgument("ContractVersion", "1.0.0"); + break; + case "ContractPermission": + newAttribute = SyntaxFactory.Attribute( + SyntaxFactory.IdentifierName("ContractPermission"), + SyntaxFactory.AttributeArgumentList( + SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.AttributeArgument( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("Permission"), + SyntaxFactory.IdentifierName("Any"))), + SyntaxFactory.AttributeArgument( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("Method"), + SyntaxFactory.IdentifierName("Any"))) + }) + ) + ); + break; + default: + continue; + } + + var newAttributeList = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(newAttribute)) + .WithAdditionalAnnotations(Formatter.Annotation); + newAttributeLists.Add(newAttributeList); + } + + var newClassDeclaration = classDeclaration.WithAttributeLists(SyntaxFactory.List(newAttributeLists)); + var newRoot = root.ReplaceNode(classDeclaration, newClassDeclaration); + + return document.WithSyntaxRoot(newRoot); + } + + private AttributeSyntax CreateAttributeWithStringArgument(string attributeName, string argumentValue) + { + return SyntaxFactory.Attribute( + SyntaxFactory.IdentifierName(attributeName), + SyntaxFactory.AttributeArgumentList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.AttributeArgument( + SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, + SyntaxFactory.Literal(argumentValue) + ) + ) + ) + ) + ); + } + + private async Task FixAttributeUsageAsync(Document document, AttributeSyntax attribute, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root == null) return document; + + var attributeName = attribute.Name.ToString(); + if (attributeName.EndsWith("Attribute")) + attributeName = attributeName.Substring(0, attributeName.Length - "Attribute".Length); + + AttributeSyntax newAttribute; + + switch (attributeName) + { + case "DisplayName": + case "ContractDescription": + case "ContractVersion": + // Fix string argument attributes + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + var defaultValue = attributeName == "DisplayName" ? "MyContract" : + attributeName == "ContractDescription" ? "Contract Description" : "1.0.0"; + + newAttribute = CreateAttributeWithStringArgument(attributeName, defaultValue); + } + else + { + // Ensure the argument is a string literal + var argument = attribute.ArgumentList.Arguments[0]; + if (argument.Expression is not LiteralExpressionSyntax literalExpression || + literalExpression.Kind() != SyntaxKind.StringLiteralExpression) + { + newAttribute = CreateAttributeWithStringArgument(attributeName, "DefaultValue"); + } + else + { + return document; // Already correct + } + } + break; + + case "ContractPermission": + // Fix ContractPermission attribute + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + newAttribute = SyntaxFactory.Attribute( + SyntaxFactory.IdentifierName("ContractPermission"), + SyntaxFactory.AttributeArgumentList( + SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.AttributeArgument( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("Permission"), + SyntaxFactory.IdentifierName("Any"))), + SyntaxFactory.AttributeArgument( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("Method"), + SyntaxFactory.IdentifierName("Any"))) + }) + ) + ); + } + else + { + return document; // Already has arguments, assume they're correct + } + break; + + case "SupportedStandards": + // Fix SupportedStandards attribute + if (attribute.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0) + { + newAttribute = SyntaxFactory.Attribute( + SyntaxFactory.IdentifierName("SupportedStandards"), + SyntaxFactory.AttributeArgumentList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.AttributeArgument( + SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName("NepStandard"), + SyntaxFactory.IdentifierName("Nep17")) + ) + ) + ) + ); + } + else + { + return document; // Already has arguments, assume they're correct + } + break; + + default: + return document; // Can't fix unknown attribute + } + + var newRoot = root.ReplaceNode(attribute, newAttribute.WithAdditionalAnnotations(Formatter.Annotation)); + return document.WithSyntaxRoot(newRoot); + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/EventRegistrationAnalyzer.cs b/src/Neo.SmartContract.Analyzer/EventRegistrationAnalyzer.cs new file mode 100644 index 000000000..8459679d1 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/EventRegistrationAnalyzer.cs @@ -0,0 +1,225 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// EventRegistrationAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class EventRegistrationAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticIdUnregisteredEvent = "NC4049"; + public const string DiagnosticIdImproperEventDefinition = "NC4050"; + + private static readonly LocalizableString TitleUnregisteredEvent = "Unregistered event usage"; + private static readonly LocalizableString MessageFormatUnregisteredEvent = "Event '{0}' is used but not properly registered as a delegate"; + private static readonly LocalizableString DescriptionUnregisteredEvent = "Events must be registered as delegates before being used in Runtime.Notify calls."; + + private static readonly LocalizableString TitleImproperEventDefinition = "Improper event definition"; + private static readonly LocalizableString MessageFormatImproperEventDefinition = "Event '{0}' is not properly defined: {1}"; + private static readonly LocalizableString DescriptionImproperEventDefinition = "Events in Neo smart contracts should be defined as delegates with proper parameter types."; + + private const string Category = "Usage"; + + private static readonly DiagnosticDescriptor RuleUnregisteredEvent = new( + DiagnosticIdUnregisteredEvent, + TitleUnregisteredEvent, + MessageFormatUnregisteredEvent, + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: DescriptionUnregisteredEvent); + + private static readonly DiagnosticDescriptor RuleImproperEventDefinition = new( + DiagnosticIdImproperEventDefinition, + TitleImproperEventDefinition, + MessageFormatImproperEventDefinition, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionImproperEventDefinition); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(RuleUnregisteredEvent, RuleImproperEventDefinition); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterCompilationStartAction(compilationStartContext => + { + // Track registered events and their usage + var registeredEvents = new Dictionary(); + var eventUsages = new Dictionary>(); + + // Register for delegate declarations to find event definitions + compilationStartContext.RegisterSyntaxNodeAction( + context => CollectEventDefinition(context, registeredEvents), + SyntaxKind.DelegateDeclaration); + + // Register for field declarations to find event definitions + compilationStartContext.RegisterSyntaxNodeAction( + context => CollectEventField(context, registeredEvents), + SyntaxKind.FieldDeclaration); + + // Register for method invocations to find Runtime.Notify calls + compilationStartContext.RegisterSyntaxNodeAction( + context => CollectEventUsage(context, eventUsages), + SyntaxKind.InvocationExpression); + + // At the end of compilation, check for unregistered events + compilationStartContext.RegisterCompilationEndAction( + context => VerifyEventRegistration(context, registeredEvents, eventUsages)); + }); + } + + private void CollectEventDefinition(SyntaxNodeAnalysisContext context, Dictionary registeredEvents) + { + var delegateDeclaration = (DelegateDeclarationSyntax)context.Node; + + // Check if this is in a smart contract class + if (!IsInSmartContractClass(context.SemanticModel, delegateDeclaration)) + return; + + // Get the delegate symbol + var delegateSymbol = context.SemanticModel.GetDeclaredSymbol(delegateDeclaration); + if (delegateSymbol == null) + return; + + // No longer checking if the delegate is static - events don't need to be static + + // Add to registered events + registeredEvents[delegateSymbol.Name] = delegateSymbol; + } + + private void CollectEventField(SyntaxNodeAnalysisContext context, Dictionary registeredEvents) + { + var fieldDeclaration = (FieldDeclarationSyntax)context.Node; + + // Check if this is in a smart contract class + if (!IsInSmartContractClass(context.SemanticModel, fieldDeclaration)) + return; + + // Check if this is a delegate field + if (!IsDelegateType(context.SemanticModel, fieldDeclaration.Declaration.Type)) + return; + + foreach (var variable in fieldDeclaration.Declaration.Variables) + { + var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol; + if (fieldSymbol == null) + continue; + + // No longer checking if the field is static - events don't need to be static + + // Add to registered events + registeredEvents[fieldSymbol.Name] = fieldSymbol; + } + } + + private void CollectEventUsage(SyntaxNodeAnalysisContext context, Dictionary> eventUsages) + { + var invocation = (InvocationExpressionSyntax)context.Node; + + // Check if this is a Runtime.Notify call + if (!IsRuntimeNotifyCall(context.SemanticModel, invocation)) + return; + + // Check if the first argument is an event name + if (invocation.ArgumentList.Arguments.Count == 0) + return; + + var firstArg = invocation.ArgumentList.Arguments[0].Expression; + if (firstArg is IdentifierNameSyntax identifierName) + { + var eventName = identifierName.Identifier.Text; + if (!eventUsages.TryGetValue(eventName, out var usages)) + { + usages = new List(); + eventUsages[eventName] = usages; + } + usages.Add(invocation); + } + } + + private void VerifyEventRegistration(CompilationAnalysisContext context, Dictionary registeredEvents, Dictionary> eventUsages) + { + foreach (var usage in eventUsages) + { + var eventName = usage.Key; + var usageNodes = usage.Value; + + // Check if the event is registered + if (!registeredEvents.ContainsKey(eventName)) + { + foreach (var node in usageNodes) + { + var diagnostic = Diagnostic.Create(RuleUnregisteredEvent, + node.GetLocation(), + eventName); + context.ReportDiagnostic(diagnostic); + } + } + } + } + + private bool IsInSmartContractClass(SemanticModel semanticModel, SyntaxNode node) + { + var classDeclaration = node.FirstAncestorOrSelf(); + if (classDeclaration == null) + return false; + + if (classDeclaration.BaseList == null) + return false; + + foreach (var baseType in classDeclaration.BaseList.Types) + { + var typeInfo = semanticModel.GetTypeInfo(baseType.Type); + if (typeInfo.Type?.Name == "SmartContract" && + typeInfo.Type.ContainingNamespace?.ToString() == "Neo.SmartContract.Framework") + { + return true; + } + } + + return false; + } + + private bool IsDelegateType(SemanticModel semanticModel, TypeSyntax typeSyntax) + { + var typeSymbol = semanticModel.GetTypeInfo(typeSyntax).Type; + return typeSymbol?.TypeKind == TypeKind.Delegate; + } + + private bool IsRuntimeNotifyCall(SemanticModel semanticModel, InvocationExpressionSyntax invocation) + { + if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) + { + if (memberAccess.Name.Identifier.Text != "Notify") + return false; + + if (memberAccess.Expression is IdentifierNameSyntax identifier && identifier.Identifier.Text == "Runtime") + { + var symbol = semanticModel.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol; + return symbol?.ContainingType?.Name == "Runtime" && + symbol.ContainingNamespace?.ToString() == "Neo.SmartContract.Framework.Services"; + } + } + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/EventRegistrationCodeFixProvider.cs b/src/Neo.SmartContract.Analyzer/EventRegistrationCodeFixProvider.cs new file mode 100644 index 000000000..386f2e244 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/EventRegistrationCodeFixProvider.cs @@ -0,0 +1,108 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// EventRegistrationCodeFixProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.SmartContract.Analyzer +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(EventRegistrationCodeFixProvider)), Shared] + public class EventRegistrationCodeFixProvider : CodeFixProvider + { + public sealed override ImmutableArray FixableDiagnosticIds => + ImmutableArray.Create(EventRegistrationAnalyzer.DiagnosticIdUnregisteredEvent, + EventRegistrationAnalyzer.DiagnosticIdImproperEventDefinition); + + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root == null) return; + + var diagnostic = context.Diagnostics.First(); + var diagnosticSpan = diagnostic.Location.SourceSpan; + var node = root.FindNode(diagnosticSpan); + + // Handle different diagnostic IDs + switch (diagnostic.Id) + { + case EventRegistrationAnalyzer.DiagnosticIdUnregisteredEvent: + if (node.Parent is ArgumentSyntax argument && + argument.Parent is ArgumentListSyntax argumentList && + argumentList.Parent is InvocationExpressionSyntax invocation) + { + // Register code fix for unregistered event + context.RegisterCodeFix( + CodeAction.Create( + title: "Register event delegate", + createChangedDocument: c => RegisterEventDelegateAsync(context.Document, invocation, node, c), + equivalenceKey: "RegisterEventDelegate"), + diagnostic); + } + break; + + case EventRegistrationAnalyzer.DiagnosticIdImproperEventDefinition: + // No longer providing a code fix for making events static since it's not required + break; + } + } + + private async Task RegisterEventDelegateAsync(Document document, InvocationExpressionSyntax invocation, SyntaxNode eventNode, CancellationToken cancellationToken) + { + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root == null) return document; + + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (semanticModel == null) return document; + + // Find the containing class + var classDeclaration = invocation.FirstAncestorOrSelf(); + if (classDeclaration == null) return document; + + // Create a new delegate declaration + var eventName = eventNode.ToString(); + var delegateDeclaration = SyntaxFactory.DelegateDeclaration( + SyntaxFactory.List(), + SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)), + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), + SyntaxFactory.Identifier(eventName), + null, + SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.Parameter( + SyntaxFactory.List(), + SyntaxFactory.TokenList(), + SyntaxFactory.IdentifierName("string"), + SyntaxFactory.Identifier("name"), + null) + })), + SyntaxFactory.List()) + .WithAdditionalAnnotations(Formatter.Annotation); + + // Add the delegate declaration to the class + var newClassDeclaration = classDeclaration.AddMembers(delegateDeclaration); + var newRoot = root.ReplaceNode(classDeclaration, newClassDeclaration); + + return document.WithSyntaxRoot(newRoot); + } + + // MakeEventStaticAsync method removed since events don't need to be static + } +} diff --git a/src/Neo.SmartContract.Analyzer/GasOptimizationAnalyzer.cs b/src/Neo.SmartContract.Analyzer/GasOptimizationAnalyzer.cs new file mode 100644 index 000000000..b96acdd0e --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/GasOptimizationAnalyzer.cs @@ -0,0 +1,208 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// GasOptimizationAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class GasOptimizationAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticIdNestedLoop = "NC4039"; + public const string DiagnosticIdLargeString = "NC4040"; + public const string DiagnosticIdUnnecessaryConversion = "NC4041"; + + private static readonly LocalizableString TitleNestedLoop = "Nested loop detected"; + private static readonly LocalizableString MessageFormatNestedLoop = "Nested loops can consume excessive gas: {0}"; + private static readonly LocalizableString DescriptionNestedLoop = "Nested loops can consume excessive gas. Consider refactoring to reduce nesting."; + + private static readonly LocalizableString TitleLargeString = "Large string literal"; + private static readonly LocalizableString MessageFormatLargeString = "Large string literal detected: {0}"; + private static readonly LocalizableString DescriptionLargeString = "Large string literals consume more gas. Consider storing large strings off-chain."; + + private static readonly LocalizableString TitleUnnecessaryConversion = "Unnecessary type conversion"; + private static readonly LocalizableString MessageFormatUnnecessaryConversion = "Unnecessary type conversion detected: {0}"; + private static readonly LocalizableString DescriptionUnnecessaryConversion = "Unnecessary type conversions consume more gas. Use the appropriate type directly."; + + private const string Category = "Performance"; + + private static readonly DiagnosticDescriptor RuleNestedLoop = new( + DiagnosticIdNestedLoop, + TitleNestedLoop, + MessageFormatNestedLoop, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionNestedLoop); + + private static readonly DiagnosticDescriptor RuleLargeString = new( + DiagnosticIdLargeString, + TitleLargeString, + MessageFormatLargeString, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionLargeString); + + private static readonly DiagnosticDescriptor RuleUnnecessaryConversion = new( + DiagnosticIdUnnecessaryConversion, + TitleUnnecessaryConversion, + MessageFormatUnnecessaryConversion, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: DescriptionUnnecessaryConversion); + + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(RuleNestedLoop, RuleLargeString, RuleUnnecessaryConversion); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeForStatement, SyntaxKind.ForStatement); + context.RegisterSyntaxNodeAction(AnalyzeForEachStatement, SyntaxKind.ForEachStatement); + context.RegisterSyntaxNodeAction(AnalyzeWhileStatement, SyntaxKind.WhileStatement); + context.RegisterSyntaxNodeAction(AnalyzeDoStatement, SyntaxKind.DoStatement); + context.RegisterSyntaxNodeAction(AnalyzeLiteralExpression, SyntaxKind.StringLiteralExpression); + context.RegisterSyntaxNodeAction(AnalyzeCastExpression, SyntaxKind.CastExpression); + } + + private void AnalyzeForStatement(SyntaxNodeAnalysisContext context) + { + var forStatement = (ForStatementSyntax)context.Node; + CheckNestedLoops(context, forStatement); + } + + private void AnalyzeForEachStatement(SyntaxNodeAnalysisContext context) + { + var forEachStatement = (ForEachStatementSyntax)context.Node; + CheckNestedLoops(context, forEachStatement); + } + + private void AnalyzeWhileStatement(SyntaxNodeAnalysisContext context) + { + var whileStatement = (WhileStatementSyntax)context.Node; + CheckNestedLoops(context, whileStatement); + } + + private void AnalyzeDoStatement(SyntaxNodeAnalysisContext context) + { + var doStatement = (DoStatementSyntax)context.Node; + CheckNestedLoops(context, doStatement); + } + + private void CheckNestedLoops(SyntaxNodeAnalysisContext context, SyntaxNode loopNode) + { + // Check if this loop is nested inside another loop + SyntaxNode parent = loopNode.Parent; + while (parent != null) + { + if (parent is ForStatementSyntax || + parent is ForEachStatementSyntax || + parent is WhileStatementSyntax || + parent is DoStatementSyntax) + { + var diagnostic = Diagnostic.Create(RuleNestedLoop, loopNode.GetLocation(), + "Consider refactoring to reduce loop nesting"); + context.ReportDiagnostic(diagnostic); + break; + } + parent = parent.Parent; + } + } + + private void AnalyzeLiteralExpression(SyntaxNodeAnalysisContext context) + { + var literalExpression = (LiteralExpressionSyntax)context.Node; + + // Check if it's a string literal + if (literalExpression.Token.Value is string stringValue && stringValue.Length > 100) + { + // Skip checking string literals in contract attributes + if (IsPartOfContractAttribute(literalExpression)) + { + return; + } + + var diagnostic = Diagnostic.Create(RuleLargeString, literalExpression.GetLocation(), + $"String of length {stringValue.Length} characters"); + context.ReportDiagnostic(diagnostic); + } + } + + private static bool IsPartOfContractAttribute(LiteralExpressionSyntax literalExpression) + { + // Check if the literal is part of an attribute argument + var attributeArgument = literalExpression.Ancestors().OfType().FirstOrDefault(); + if (attributeArgument == null) + return false; + + // Check if the attribute is a contract attribute + var attribute = attributeArgument.Ancestors().OfType().FirstOrDefault(); + if (attribute == null) + return false; + + // Get the attribute name + var attributeName = attribute.Name.ToString(); + + // Check if it's a contract attribute + return attributeName.Contains("Contract") || + attributeName.EndsWith("Attribute") && attributeName.Contains("Contract"); + } + + private void AnalyzeCastExpression(SyntaxNodeAnalysisContext context) + { + var castExpression = (CastExpressionSyntax)context.Node; + var semanticModel = context.SemanticModel; + + // Get the type of the expression being cast + var expressionType = semanticModel.GetTypeInfo(castExpression.Expression).Type; + if (expressionType == null) return; + + // Get the type being cast to + var targetType = semanticModel.GetTypeInfo(castExpression.Type).Type; + if (targetType == null) return; + + // Check for unnecessary conversions + if (IsUnnecessaryConversion(expressionType, targetType)) + { + var diagnostic = Diagnostic.Create(RuleUnnecessaryConversion, castExpression.GetLocation(), + $"Conversion from {expressionType.Name} to {targetType.Name}"); + context.ReportDiagnostic(diagnostic); + } + } + + private static bool IsUnnecessaryConversion(ITypeSymbol sourceType, ITypeSymbol targetType) + { + // Check for common unnecessary conversions in Neo smart contracts + + // ByteString to byte[] + if (sourceType.Name == "ByteString" && targetType.Name == "Byte[]") + return true; + + // byte[] to ByteString + if (sourceType.Name == "Byte[]" && targetType.Name == "ByteString") + return true; + + // int to BigInteger + if (sourceType.SpecialType == SpecialType.System_Int32 && targetType.Name == "BigInteger") + return true; + + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/NEP11ComplianceAnalyzer.cs b/src/Neo.SmartContract.Analyzer/NEP11ComplianceAnalyzer.cs new file mode 100644 index 000000000..78420f053 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/NEP11ComplianceAnalyzer.cs @@ -0,0 +1,151 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// NEP11ComplianceAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NEP11ComplianceAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4031"; + + private static readonly LocalizableString Title = "NEP-11 compliance"; + private static readonly LocalizableString MessageFormat = "NEP-11 token standard requires method: {0}"; + private static readonly LocalizableString Description = "NEP-11 token standard requires specific methods to be implemented."; + private const string Category = "Standard"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + // Required methods for NEP-11 compliance + private static readonly Dictionary RequiredMethods = new() + { + { "symbol", (new string[] { }, "string") }, + { "decimals", (new string[] { }, "byte") }, + { "totalSupply", (new string[] { }, "BigInteger") }, + { "balanceOf", (new string[] { "UInt160" }, "BigInteger") }, + { "ownerOf", (new string[] { "string" }, "UInt160") }, + { "properties", (new string[] { "string" }, "Map") }, + { "tokens", (new string[] { }, "Iterator") }, + { "tokensOf", (new string[] { "UInt160" }, "Iterator") }, + { "transfer", (new string[] { "UInt160", "UInt160", "string", "object" }, "bool") } + }; + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType); + } + + private void AnalyzeNamedType(SymbolAnalysisContext context) + { + var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; + + // Check if the class has the SupportedStandards attribute with NEP-11 + if (!HasNEP11SupportedStandard(namedTypeSymbol)) + return; + + // Check if all required methods are implemented + foreach (var requiredMethod in RequiredMethods) + { + if (!HasRequiredMethod(namedTypeSymbol, requiredMethod.Key, requiredMethod.Value.Parameters, requiredMethod.Value.ReturnType)) + { + var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], + $"{requiredMethod.Key}({string.Join(", ", requiredMethod.Value.Parameters)}) -> {requiredMethod.Value.ReturnType}"); + context.ReportDiagnostic(diagnostic); + } + } + } + + private bool HasNEP11SupportedStandard(INamedTypeSymbol typeSymbol) + { + foreach (var attribute in typeSymbol.GetAttributes()) + { + if (attribute.AttributeClass?.Name == "SupportedStandardsAttribute") + { + foreach (var arg in attribute.ConstructorArguments) + { + if (arg.Kind == TypedConstantKind.Array) + { + foreach (var value in arg.Values) + { + if (value.Value?.ToString() == "NepStandard.Nep11" || + value.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep11") + { + return true; + } + } + } + else if (arg.Value?.ToString() == "NepStandard.Nep11" || + arg.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep11") + { + return true; + } + } + } + } + return false; + } + + private bool HasRequiredMethod(INamedTypeSymbol typeSymbol, string methodName, string[] parameterTypes, string returnType) + { + foreach (var member in typeSymbol.GetMembers()) + { + if (member is IMethodSymbol method && + method.Name.ToLowerInvariant() == methodName.ToLowerInvariant() && + method.IsStatic && + method.DeclaredAccessibility == Accessibility.Public) + { + // Check return type + string typeName = method.ReturnType.ToString(); + if (!typeName.EndsWith(returnType, System.StringComparison.OrdinalIgnoreCase)) + continue; + + // Check parameters + if (method.Parameters.Length != parameterTypes.Length) + continue; + + bool parametersMatch = true; + for (int i = 0; i < parameterTypes.Length; i++) + { + string paramTypeName = method.Parameters[i].Type.ToString(); + if (!paramTypeName.EndsWith(parameterTypes[i], System.StringComparison.OrdinalIgnoreCase)) + { + parametersMatch = false; + break; + } + } + + if (parametersMatch) + return true; + } + } + + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/NEP17ComplianceAnalyzer.cs b/src/Neo.SmartContract.Analyzer/NEP17ComplianceAnalyzer.cs new file mode 100644 index 000000000..92f1c547a --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/NEP17ComplianceAnalyzer.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// NEP17ComplianceAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NEP17ComplianceAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4030"; + + private static readonly LocalizableString Title = "NEP-17 compliance"; + private static readonly LocalizableString MessageFormat = "NEP-17 token standard requires method: {0}"; + private static readonly LocalizableString Description = "NEP-17 token standard requires specific methods to be implemented."; + private const string Category = "Standard"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + // Required methods for NEP-17 compliance + private static readonly Dictionary RequiredMethods = new() + { + { "symbol", (new string[] { }, "string") }, + { "decimals", (new string[] { }, "byte") }, + { "totalSupply", (new string[] { }, "BigInteger") }, + { "balanceOf", (new string[] { "UInt160" }, "BigInteger") }, + { "transfer", (new string[] { "UInt160", "UInt160", "BigInteger", "object" }, "bool") } + }; + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType); + } + + private void AnalyzeNamedType(SymbolAnalysisContext context) + { + var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; + + // Check if the class has the SupportedStandards attribute with NEP-17 + if (!HasNEP17SupportedStandard(namedTypeSymbol)) + return; + + // Check if all required methods are implemented + foreach (var requiredMethod in RequiredMethods) + { + if (!HasRequiredMethod(namedTypeSymbol, requiredMethod.Key, requiredMethod.Value.Parameters, requiredMethod.Value.ReturnType)) + { + var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], + $"{requiredMethod.Key}({string.Join(", ", requiredMethod.Value.Parameters)}) -> {requiredMethod.Value.ReturnType}"); + context.ReportDiagnostic(diagnostic); + } + } + } + + private bool HasNEP17SupportedStandard(INamedTypeSymbol typeSymbol) + { + foreach (var attribute in typeSymbol.GetAttributes()) + { + if (attribute.AttributeClass?.Name == "SupportedStandardsAttribute") + { + foreach (var arg in attribute.ConstructorArguments) + { + if (arg.Kind == TypedConstantKind.Array) + { + foreach (var value in arg.Values) + { + if (value.Value?.ToString() == "NepStandard.Nep17" || + value.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep17") + { + return true; + } + } + } + else if (arg.Value?.ToString() == "NepStandard.Nep17" || + arg.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep17") + { + return true; + } + } + } + } + return false; + } + + private bool HasRequiredMethod(INamedTypeSymbol typeSymbol, string methodName, string[] parameterTypes, string returnType) + { + foreach (var member in typeSymbol.GetMembers()) + { + if (member is IMethodSymbol method && + method.Name.ToLowerInvariant() == methodName.ToLowerInvariant() && + method.IsStatic && + method.DeclaredAccessibility == Accessibility.Public) + { + // Check return type + if (!method.ReturnType.Name.EndsWith(returnType, System.StringComparison.OrdinalIgnoreCase)) + continue; + + // Check parameters + if (method.Parameters.Length != parameterTypes.Length) + continue; + + bool parametersMatch = true; + for (int i = 0; i < parameterTypes.Length; i++) + { + if (!method.Parameters[i].Type.Name.EndsWith(parameterTypes[i], System.StringComparison.OrdinalIgnoreCase)) + { + parametersMatch = false; + break; + } + } + + if (parametersMatch) + return true; + } + } + + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/NEP26ComplianceAnalyzer.cs b/src/Neo.SmartContract.Analyzer/NEP26ComplianceAnalyzer.cs new file mode 100644 index 000000000..50122d852 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/NEP26ComplianceAnalyzer.cs @@ -0,0 +1,143 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// NEP26ComplianceAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NEP26ComplianceAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4038"; + + private static readonly LocalizableString Title = "NEP-26 compliance"; + private static readonly LocalizableString MessageFormat = "NEP-26 standard requires method: {0}"; + private static readonly LocalizableString Description = "NEP-26 standard requires specific methods to be implemented."; + private const string Category = "Standard"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType); + } + + private void AnalyzeNamedType(SymbolAnalysisContext context) + { + var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; + + // Check if the class has the SupportedStandards attribute with NEP-26 + if (!HasNEP26SupportedStandard(namedTypeSymbol)) + return; + + // Check if the OnNEP11Payment method is implemented + if (!HasOnNEP11PaymentMethod(namedTypeSymbol)) + { + var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], + "OnNEP11Payment(UInt160 from, BigInteger amount, string tokenId, object? data = null)"); + context.ReportDiagnostic(diagnostic); + } + + // Check if the class implements INEP26 interface + if (!ImplementsINEP26Interface(namedTypeSymbol)) + { + var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], + "Class should implement INEP26 interface"); + context.ReportDiagnostic(diagnostic); + } + } + + private bool HasNEP26SupportedStandard(INamedTypeSymbol typeSymbol) + { + foreach (var attribute in typeSymbol.GetAttributes()) + { + if (attribute.AttributeClass?.Name == "SupportedStandardsAttribute") + { + foreach (var arg in attribute.ConstructorArguments) + { + if (arg.Kind == TypedConstantKind.Array) + { + foreach (var value in arg.Values) + { + if (value.Value?.ToString() == "NepStandard.Nep26" || + value.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep26") + { + return true; + } + } + } + else if (arg.Value?.ToString() == "NepStandard.Nep26" || + arg.Value?.ToString() == "Neo.SmartContract.Framework.NepStandard.Nep26") + { + return true; + } + } + } + } + return false; + } + + private bool HasOnNEP11PaymentMethod(INamedTypeSymbol typeSymbol) + { + foreach (var member in typeSymbol.GetMembers()) + { + if (member is IMethodSymbol method && + method.Name == "OnNEP11Payment" && + method.DeclaredAccessibility == Accessibility.Public) + { + // Check parameters + if (method.Parameters.Length >= 3) + { + var param1 = method.Parameters[0]; + var param2 = method.Parameters[1]; + var param3 = method.Parameters[2]; + + if (param1.Type.Name.EndsWith("UInt160") && + param2.Type.Name.EndsWith("BigInteger") && + param3.Type.Name.EndsWith("String")) + { + return true; + } + } + } + } + return false; + } + + private bool ImplementsINEP26Interface(INamedTypeSymbol typeSymbol) + { + foreach (var iface in typeSymbol.AllInterfaces) + { + if (iface.Name == "INEP26") + { + return true; + } + } + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/Neo.SmartContract.Analyzer.csproj b/src/Neo.SmartContract.Analyzer/Neo.SmartContract.Analyzer.csproj index 1daf27b2f..c1aae7a53 100644 --- a/src/Neo.SmartContract.Analyzer/Neo.SmartContract.Analyzer.csproj +++ b/src/Neo.SmartContract.Analyzer/Neo.SmartContract.Analyzer.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Neo.SmartContract.Analyzer/NullableTypeUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/NullableTypeUsageAnalyzer.cs new file mode 100644 index 000000000..f66a38017 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/NullableTypeUsageAnalyzer.cs @@ -0,0 +1,112 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// NullableTypeUsageAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NullableTypeUsageAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4044"; + + // Nullable types that are not supported in Neo smart contracts + // Based on the methods implemented in src\Neo.Compiler.CSharp\MethodConvert\System\SystemCall.Nullable.cs + private readonly string[] _unsupportedNullableTypes = { + "float?", "double?", "decimal?" + // Supported nullable types (not in this list): + // - byte? + // - sbyte? + // - short? + // - ushort? + // - int? + // - uint? + // - long? + // - ulong? + // - bool? + // - BigInteger? + }; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + "Unsupported nullable type is used", + "Unsupported nullable type: {0}", + "Type", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeVariableDeclaration, SyntaxKind.VariableDeclaration); + context.RegisterSyntaxNodeAction(AnalyzeParameter, SyntaxKind.Parameter); + context.RegisterSyntaxNodeAction(AnalyzePropertyDeclaration, SyntaxKind.PropertyDeclaration); + context.RegisterSyntaxNodeAction(AnalyzeFieldDeclaration, SyntaxKind.FieldDeclaration); + } + + private void AnalyzeVariableDeclaration(SyntaxNodeAnalysisContext context) + { + var variableDeclaration = (VariableDeclarationSyntax)context.Node; + CheckType(context, variableDeclaration.Type); + } + + private void AnalyzeParameter(SyntaxNodeAnalysisContext context) + { + var parameter = (ParameterSyntax)context.Node; + if (parameter.Type != null) + { + CheckType(context, parameter.Type); + } + } + + private void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context) + { + var property = (PropertyDeclarationSyntax)context.Node; + CheckType(context, property.Type); + } + + private void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context) + { + var field = (FieldDeclarationSyntax)context.Node; + CheckType(context, field.Declaration.Type); + } + + private void CheckType(SyntaxNodeAnalysisContext context, TypeSyntax typeSyntax) + { + var typeSymbol = context.SemanticModel.GetTypeInfo(typeSyntax).Type; + if (typeSymbol == null) return; + + if (typeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) + { + var nullableType = typeSymbol.ToString(); + + foreach (var unsupportedType in _unsupportedNullableTypes) + { + if (nullableType.StartsWith(unsupportedType)) + { + var diagnostic = Diagnostic.Create(Rule, typeSyntax.GetLocation(), nullableType); + context.ReportDiagnostic(diagnostic); + break; + } + } + } + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/NumericMethodsUsageAnalyzer.cs b/src/Neo.SmartContract.Analyzer/NumericMethodsUsageAnalyzer.cs new file mode 100644 index 000000000..d000e2c16 --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/NumericMethodsUsageAnalyzer.cs @@ -0,0 +1,219 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// NumericMethodsUsageAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class NumericMethodsUsageAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4045"; + + // Dictionary of numeric types and their unsupported methods + // Based on the methods implemented in src\Neo.Compiler.CSharp\MethodConvert\System\ + private readonly Dictionary _unsupportedNumericMethods = new Dictionary + { + { + "byte", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + } + }, + { + "sbyte", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + // - CopySign + } + }, + { + "short", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + // - CopySign + } + }, + { + "ushort", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + } + }, + { + "int", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + // - CopySign + } + }, + { + "uint", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + } + }, + { + "long", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + // - CopySign + } + }, + { + "ulong", new[] + { + "GetHashCode", "GetType", "GetTypeCode", "TryFormat" + // Supported methods (not in this list): + // - Parse + // - ToString + // - RotateLeft + // - RotateRight + // - PopCount + // - LeadingZeroCount + // - TrailingZeroCount + } + } + }; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + "Unsupported numeric method is used", + "Unsupported method '{0}' on type '{1}'", + "Method", + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.InvocationExpression); + } + + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) + { + if (context.Node is not InvocationExpressionSyntax invocationExpression) return; + + // Get the method symbol + var methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; + if (methodSymbol == null) return; + + // Check if the method is on a numeric type + var containingType = methodSymbol.ContainingType?.SpecialType.ToString(); + if (containingType == null) return; + + string numericType = null; + switch (containingType) + { + case "System_Byte": + numericType = "byte"; + break; + case "System_SByte": + numericType = "sbyte"; + break; + case "System_Int16": + numericType = "short"; + break; + case "System_UInt16": + numericType = "ushort"; + break; + case "System_Int32": + numericType = "int"; + break; + case "System_UInt32": + numericType = "uint"; + break; + case "System_Int64": + numericType = "long"; + break; + case "System_UInt64": + numericType = "ulong"; + break; + default: + return; + } + + // Check if the method is unsupported + if (_unsupportedNumericMethods.TryGetValue(numericType, out var unsupportedMethods) && + unsupportedMethods.Contains(methodSymbol.Name)) + { + var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), methodSymbol.Name, numericType); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/ReentrancyPatternAnalyzer.cs b/src/Neo.SmartContract.Analyzer/ReentrancyPatternAnalyzer.cs new file mode 100644 index 000000000..1a3c2d60e --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/ReentrancyPatternAnalyzer.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// ReentrancyPatternAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ReentrancyPatternAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4035"; + + private static readonly LocalizableString Title = "Potential reentrancy vulnerability"; + private static readonly LocalizableString MessageFormat = "Potential reentrancy vulnerability: {0}"; + private static readonly LocalizableString Description = "Writing to storage after calling an external contract can lead to reentrancy vulnerabilities."; + private const string Category = "Security"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration); + } + + private void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) + { + var methodDeclaration = (MethodDeclarationSyntax)context.Node; + + if (methodDeclaration.Body == null) + return; + + // Find all external contract calls and storage writes + var externalCalls = new List(); + var storageWrites = new List(); + + foreach (var statement in methodDeclaration.Body.Statements) + { + if (ContainsExternalContractCall(statement, context.SemanticModel)) + { + externalCalls.Add(statement); + } + + if (ContainsStorageWrite(statement, context.SemanticModel)) + { + storageWrites.Add(statement); + } + } + + // Check if there are storage writes after external calls + foreach (var externalCall in externalCalls) + { + int externalCallIndex = methodDeclaration.Body.Statements.IndexOf(externalCall); + + foreach (var storageWrite in storageWrites) + { + int storageWriteIndex = methodDeclaration.Body.Statements.IndexOf(storageWrite); + + if (storageWriteIndex > externalCallIndex) + { + var diagnostic = Diagnostic.Create(Rule, storageWrite.GetLocation(), + "Storage write after external contract call. Consider using the checks-effects-interactions pattern."); + context.ReportDiagnostic(diagnostic); + } + } + } + } + + private bool ContainsExternalContractCall(StatementSyntax statement, SemanticModel semanticModel) + { + // Look for Contract.Call invocations + return statement.DescendantNodes() + .OfType() + .Any(i => IsExternalContractCall(i, semanticModel)); + } + + private bool IsExternalContractCall(InvocationExpressionSyntax invocation, SemanticModel semanticModel) + { + if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) + { + var symbol = semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null) return false; + + // Check if it's Contract.Call + if (symbol.Name == "Call" && + symbol.ContainingType.Name == "Contract" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + return true; + } + } + return false; + } + + private bool ContainsStorageWrite(StatementSyntax statement, SemanticModel semanticModel) + { + // Look for Storage.Put or Storage.Delete invocations + return statement.DescendantNodes() + .OfType() + .Any(i => IsStorageWrite(i, semanticModel)); + } + + private bool IsStorageWrite(InvocationExpressionSyntax invocation, SemanticModel semanticModel) + { + if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) + { + var symbol = semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null) return false; + + // Check if it's Storage.Put or Storage.Delete + if ((symbol.Name == "Put" || symbol.Name == "Delete") && + symbol.ContainingType.Name == "Storage" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + return true; + } + } + return false; + } + } +} diff --git a/src/Neo.SmartContract.Analyzer/SafeAttributeAnalyzer.cs b/src/Neo.SmartContract.Analyzer/SafeAttributeAnalyzer.cs new file mode 100644 index 000000000..9b50fdffd --- /dev/null +++ b/src/Neo.SmartContract.Analyzer/SafeAttributeAnalyzer.cs @@ -0,0 +1,138 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// SafeAttributeAnalyzer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; +using System.Linq; + +namespace Neo.SmartContract.Analyzer +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class SafeAttributeAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "NC4036"; + + private static readonly LocalizableString Title = "Incorrect Safe attribute usage"; + private static readonly LocalizableString MessageFormat = "Method marked with [Safe] attribute should not modify state: {0}"; + private static readonly LocalizableString Description = "Methods marked with the [Safe] attribute should not modify blockchain state."; + private const string Category = "Usage"; + + private static readonly DiagnosticDescriptor Rule = new( + DiagnosticId, + Title, + MessageFormat, + Category, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration); + } + + private void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) + { + var methodDeclaration = (MethodDeclarationSyntax)context.Node; + + // Check if the method has the Safe attribute + if (!HasSafeAttribute(methodDeclaration)) + return; + + // Check if the method modifies state + if (ModifiesState(methodDeclaration, context.SemanticModel)) + { + var diagnostic = Diagnostic.Create(Rule, methodDeclaration.Identifier.GetLocation(), + "Methods marked as [Safe] should not modify blockchain state"); + context.ReportDiagnostic(diagnostic); + } + } + + private bool HasSafeAttribute(MethodDeclarationSyntax methodDeclaration) + { + return methodDeclaration.AttributeLists + .SelectMany(al => al.Attributes) + .Any(a => a.Name.ToString() == "Safe"); + } + + private bool ModifiesState(MethodDeclarationSyntax methodDeclaration, SemanticModel semanticModel) + { + if (methodDeclaration.Body == null) + return false; + + // Check for state-modifying operations + return methodDeclaration.DescendantNodes() + .OfType() + .Any(i => IsStateModifyingOperation(i, semanticModel)); + } + + private bool IsStateModifyingOperation(InvocationExpressionSyntax invocation, SemanticModel semanticModel) + { + if (invocation.Expression is MemberAccessExpressionSyntax memberAccess) + { + var symbol = semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + if (symbol == null) return false; + + // Check for Storage.Put/Delete + if ((symbol.Name == "Put" || symbol.Name == "Delete") && + symbol.ContainingType.Name == "Storage" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + return true; + } + + // Check for ContractManagement.Update/Deploy + if ((symbol.Name == "Update" || symbol.Name == "Deploy") && + symbol.ContainingType.Name == "ContractManagement" && + symbol.ContainingNamespace.ToString().Contains("Neo.SmartContract.Framework")) + { + return true; + } + + // Check for Runtime.Notify + if (symbol.Name == "Notify" && + symbol.ContainingType.Name == "Runtime" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + return true; + } + + // Check for Contract.Call with CallFlags that include WriteStates + if (symbol.Name == "Call" && + symbol.ContainingType.Name == "Contract" && + symbol.ContainingNamespace.ToString() == "Neo.SmartContract.Framework.Services") + { + // Check if the CallFlags parameter includes WriteStates + if (invocation.ArgumentList.Arguments.Count >= 3) + { + var flagsArg = invocation.ArgumentList.Arguments[2].Expression; + if (flagsArg is MemberAccessExpressionSyntax flagsMemberAccess) + { + string flagsName = flagsMemberAccess.Name.Identifier.Text; + if (flagsName.Contains("WriteStates") || flagsName == "All") + { + return true; + } + } + } + } + } + return false; + } + } +} diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract1.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract1.cs index 3515b6268..e1afd70a2 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract1.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract1.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract1 : SmartContract.Framework.SmartContract { private static string privateMethod() @@ -54,3 +62,5 @@ public static int testArgs4(int a, int b) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract2.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract2.cs index 45b9cecf0..8957f977b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract2.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract2.cs @@ -11,9 +11,16 @@ using System; using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract2 : SmartContract.Framework.SmartContract { public static byte UnitTest_002(object arg1, object arg2) @@ -23,3 +30,5 @@ public static byte UnitTest_002(object arg1, object arg2) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes.cs index cf091326c..e5269421e 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes.cs @@ -17,7 +17,14 @@ namespace Neo.Compiler.CSharp.TestContracts; [ContractPermission(Permission.Any, "c")] [ContractPermission("0x01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4", "a", "b")] [ContractTrust("0x0a0b00ff00ff00ff00ff00ff00ff00ff00ff00a4")] +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_ABIAttributes : SmartContract.Framework.SmartContract { public static int test() => 0; } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes2.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes2.cs index e6e274c63..eb7042475 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes2.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes2.cs @@ -24,7 +24,12 @@ namespace Neo.Compiler.CSharp.TestContracts; [ContractPermission(Permission.Any, Method.Any)] [ContractPermission("*", "b")] [ContractTrust("0x0a0b00ff00ff00ff00ff00ff00ff00ff00ff00a4")] +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] public class Contract_ABIAttributes2 : SmartContract.Framework.SmartContract { public static int test() => 0; } + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes3.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes3.cs index 12b35c6cc..26ef066e5 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes3.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABIAttributes3.cs @@ -16,7 +16,14 @@ namespace Neo.Compiler.CSharp.TestContracts; [ContractPermission("0x01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4", "a", "b", "c")] [ContractPermission("0x01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4", "*")] +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_ABIAttributes3 : SmartContract.Framework.SmartContract { public static int test() => 0; } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABISafe.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABISafe.cs index f1af33707..65dafc26a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABISafe.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ABISafe.cs @@ -9,10 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ABISafe : SmartContract.Framework.SmartContract { public static int UnitTest_001() @@ -32,3 +38,5 @@ public static int UnitTest_003() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Abort.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Abort.cs index 36d606299..5f2c185cc 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Abort.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Abort.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using System; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Abort : SmartContract.Framework.SmartContract { public int TestAbort() @@ -89,3 +95,5 @@ public int TestAbortInFinally(bool abortMsg) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs index 80fa16583..e347906b7 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Array.cs @@ -14,6 +14,7 @@ using System; using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { @@ -27,6 +28,11 @@ public State() } } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Array : SmartContract.Framework.SmartContract { // Does NOT work: @@ -196,3 +202,5 @@ public static (int[], List, int[][], int[][]) TestCollectionexpressions( } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assert.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assert.cs index 25ddd3761..5aa1f4c6a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assert.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assert.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using System; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Assert : SmartContract.Framework.SmartContract { public int TestAssertFalse() @@ -62,3 +68,5 @@ public int TestAssertInFinally() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assignment.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assignment.cs index c8ed2529b..1929efac7 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assignment.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Assignment.cs @@ -10,9 +10,15 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Assignment : SmartContract.Framework.SmartContract { public static void TestAssignment() @@ -35,3 +41,5 @@ public static void TestCoalesceAssignment() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_AttributeChanged.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_AttributeChanged.cs index a2fadd349..0b66c5ff5 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_AttributeChanged.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_AttributeChanged.cs @@ -10,15 +10,24 @@ // modifications are permitted. using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { public class SampleAttribute : System.Attribute { } [DisplayName("Contract_AttributeChanged")] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_AttributeChanged : SmartContract.Framework.SmartContract { [Sample] public static bool test() => true; } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_BigInteger.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_BigInteger.cs index 9e9c42d52..636af7209 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_BigInteger.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_BigInteger.cs @@ -10,11 +10,17 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; using System.Numerics; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_BigInteger : SmartContract.Framework.SmartContract { public static BigInteger TestPow(BigInteger x, int y) @@ -229,3 +235,5 @@ public static BigInteger TestModPow() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_BinaryExpression.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_BinaryExpression.cs index 604aa7f74..668147773 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_BinaryExpression.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_BinaryExpression.cs @@ -10,11 +10,17 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; using System.Numerics; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_BinaryExpression : SmartContract.Framework.SmartContract { public static void BinaryIs() @@ -34,3 +40,5 @@ public static void BinaryAs() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Boolean.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Boolean.cs index d45e3bbe7..ae6864d94 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Boolean.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Boolean.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Boolean : SmartContract.Framework.SmartContract { public static bool TestBooleanOr() @@ -19,3 +27,5 @@ public static bool TestBooleanOr() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs index 1719dfa59..79c216116 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs @@ -15,6 +15,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Break : SmartContract.Framework.SmartContract { public static void BreakInTryCatch(bool exception) @@ -82,3 +87,5 @@ public static void BreakInTryCatch(bool exception) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteArrayAssignment.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteArrayAssignment.cs index b16996f2a..7e9ab1065 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteArrayAssignment.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteArrayAssignment.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ByteArrayAssignment : SmartContract.Framework.SmartContract { public static byte[] TestAssignment() @@ -52,3 +60,5 @@ public static byte[] testAssignmentDynamic(byte x) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteString.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteString.cs index 869ec55a2..3b54053a0 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteString.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ByteString.cs @@ -10,9 +10,15 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ByteString : SmartContract.Framework.SmartContract { public static ByteString Literal00ToFF() => "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; @@ -20,3 +26,5 @@ public class Contract_ByteString : SmartContract.Framework.SmartContract public static ByteString LiteralWithOtherChar() => "你好\x00\x80\xff"; } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Char.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Char.cs index 6ac4d66c3..b4c4afe69 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Char.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Char.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_Char : SmartContract.Framework.SmartContract { public static bool TestCharIsDigit(char c) @@ -93,3 +101,5 @@ public static bool TestCharIsBetween(char c, char lower, char upper) return char.IsBetween(c, lower, upper); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_CheckedUnchecked.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_CheckedUnchecked.cs index 2e485c758..ecedfa9f4 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_CheckedUnchecked.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_CheckedUnchecked.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_CheckedUnchecked : SmartContract.Framework.SmartContract { public static int AddChecked(int a, int b) @@ -34,3 +42,5 @@ public static uint CastUnchecked(int a) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ClassInit.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ClassInit.cs index dc95bb172..467d39a65 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ClassInit.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ClassInit.cs @@ -14,6 +14,7 @@ using System; using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { @@ -33,6 +34,11 @@ public class ClassWithDifferentTypes public ClassWithDifferentTypes? cl; } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ClassInit : SmartContract.Framework.SmartContract { public static IntInit testInitInt() @@ -57,3 +63,5 @@ public static ClassWithDifferentTypes TestInitializationExpression() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ComplexAssign.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ComplexAssign.cs index 2edac07ca..d78ab37fa 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ComplexAssign.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ComplexAssign.cs @@ -10,11 +10,17 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using System; using System.ComponentModel; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ComplexAssign : SmartContract.Framework.SmartContract { public static (uint, int) UnitTest_Add_Assign_Checked() @@ -153,3 +159,5 @@ public static void UnitTest_Member_Element_Complex_Assign() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Concat.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Concat.cs index ff32cf8eb..0d5df26bb 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Concat.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Concat.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Concat : SmartContract.Framework.SmartContract { public static string TestStringAdd1(string a) @@ -34,3 +42,5 @@ public static string TestStringAdd4(string a, string b, string c, string d) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ConcatByteStringAddAssign.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ConcatByteStringAddAssign.cs index c0a14e7d8..423a202ae 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ConcatByteStringAddAssign.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ConcatByteStringAddAssign.cs @@ -10,9 +10,15 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ConcatByteStringAddAssign : SmartContract.Framework.SmartContract { public static ByteString ByteStringAddAssign(ByteString a, ByteString b, string c) @@ -25,3 +31,5 @@ public static ByteString ByteStringAddAssign(ByteString a, ByteString b, string } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Continue.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Continue.cs index ae54bb28c..a91514672 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Continue.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Continue.cs @@ -15,6 +15,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Continue : SmartContract.Framework.SmartContract { public static void ContinueInTryCatch(bool exception) @@ -89,3 +94,5 @@ public static void ContinueInTryCatch(bool exception) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ContractCall.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ContractCall.cs index 7a86e9ed8..ba14a6aa1 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_ContractCall.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_ContractCall.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts @@ -22,6 +23,11 @@ public class Contract_Call #pragma warning restore CS0626 // Method, operator, or accessor is marked external and has no attributes on it } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ContractCall : SmartContract.Framework.SmartContract { public static byte[] testContractCall() @@ -35,3 +41,5 @@ public static void testContractCallVoid() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Debug.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Debug.cs index 78b95270c..d0ce48e46 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Debug.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Debug.cs @@ -9,10 +9,17 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Debug : SmartContract.Framework.SmartContract { public static int TestElse() @@ -35,3 +42,5 @@ public static int TestIf() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Default.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Default.cs index 8d4dee1eb..7aef155ac 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Default.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Default.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Default : SmartContract.Framework.SmartContract { public static bool TestBooleanDefault() @@ -120,3 +127,5 @@ public class TestClass } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs index fb92a0687..87a31b388 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Delegate.cs @@ -11,10 +11,16 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Delegate : SmartContract.Framework.SmartContract { public static int sumFunc(int a, int b) @@ -42,3 +48,5 @@ public void TestDelegate() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs index b8ad58f04..98aeaf85f 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs @@ -17,6 +17,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_DirectInit : SmartContract.Framework.SmartContract { @@ -69,3 +74,5 @@ public static string testGetString() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Enum.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Enum.cs index 09c991769..790131367 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Enum.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Enum.cs @@ -12,9 +12,15 @@ using Neo.SmartContract.Framework.Attributes; using System.Collections; using System.Numerics; +using Neo.SmartContract.Framework; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Enum : SmartContract.Framework.SmartContract { public enum TestEnum @@ -79,3 +85,5 @@ public static string TestEnumGetNameWithType(object value) #pragma warning restore CS8603 } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Event.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Event.cs index 542e86329..9ad83cc6f 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Event.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Event.cs @@ -12,9 +12,16 @@ using System; using System.ComponentModel; using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Event : SmartContract.Framework.SmartContract { public static int MyStaticVar1; @@ -33,3 +40,5 @@ public static void test() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Extensions.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Extensions.cs index deb0e52ea..de1134afe 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Extensions.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Extensions.cs @@ -9,6 +9,9 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { public static class Ext @@ -19,6 +22,11 @@ public static int sum(this int a, int b) } } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Extensions : SmartContract.Framework.SmartContract { public static int TestSum(int a, int b) @@ -27,3 +35,5 @@ public static int TestSum(int a, int b) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs index 41c2dba9c..95e4a0a37 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Foreach.cs @@ -16,6 +16,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Foreach : SmartContract.Framework.SmartContract { [ByteArray("024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9")] @@ -237,3 +242,5 @@ public static void TestWhile() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_GoTo.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_GoTo.cs index e482a8956..45d84bfef 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_GoTo.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_GoTo.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_GoTo : SmartContract.Framework.SmartContract { public static int test() @@ -155,3 +161,5 @@ public static void testTryComplex(bool exception) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inc_Dec.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inc_Dec.cs index 7e9d1b4fc..b63c67cc2 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inc_Dec.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inc_Dec.cs @@ -11,9 +11,16 @@ using System; using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Inc_Dec : SmartContract.Framework.SmartContract { private static uint _property; @@ -283,3 +290,5 @@ public static void UnitTest_Not_DeadLoop() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_IndexOrRange.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_IndexOrRange.cs index cf1fbf834..36fef5ff0 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_IndexOrRange.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_IndexOrRange.cs @@ -9,11 +9,18 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_IndexOrRange : SmartContract.Framework.SmartContract { public static void TestMain() @@ -62,3 +69,5 @@ public static void TestMain() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs index 24e679e70..81501118c 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Initializer.cs @@ -11,10 +11,16 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Initializer : SmartContract.Framework.SmartContract { public class Data @@ -56,3 +62,5 @@ public void anonymousObjectCreation() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs index 8ac73f686..54a6c620b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs @@ -11,9 +11,15 @@ using System.Runtime.CompilerServices; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Inline : SmartContract.Framework.SmartContract { public static int TestInline(string method) @@ -105,3 +111,5 @@ private static int CallMethodThatReturnsInt(int a, int b) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Instance.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Instance.cs index 8c917dcc3..8f9a9446a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Instance.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Instance.cs @@ -11,9 +11,15 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Instance : SmartContract.Framework.SmartContract { public int init = 0; @@ -34,3 +40,5 @@ public int sum2(int a) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Integer.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Integer.cs index 6484a478e..b51228337 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Integer.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Integer.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_Integer : SmartContract.Framework.SmartContract { public static (byte quotient, byte remainder) DivRemByte(byte left, byte right) @@ -545,3 +552,5 @@ public static bool IsPow2BigInteger(BigInteger value) return value.IsPowerOfTwo; } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_IntegerParse.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_IntegerParse.cs index 80902574b..677dce8ad 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_IntegerParse.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_IntegerParse.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_IntegerParse : SmartContract.Framework.SmartContract { public static sbyte testSbyteparse(string s) @@ -56,3 +63,5 @@ public static int testIntparse(string s) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_InvokeCsNef.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_InvokeCsNef.cs index c893b435c..b48dd815d 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_InvokeCsNef.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_InvokeCsNef.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_InvokeCsNef : SmartContract.Framework.SmartContract { /// @@ -32,3 +40,5 @@ public static string returnString() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Lambda.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Lambda.cs index a91144bbe..e363e9f4b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Lambda.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Lambda.cs @@ -12,10 +12,16 @@ using System; using System.Collections.Generic; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Lambda : SmartContract.Framework.SmartContract { private const int z = 0; @@ -184,3 +190,5 @@ private static int InvokeFunc(Func f, int p1, int p2) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Linq.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Linq.cs index 6b37047be..578e0bc3a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Linq.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Linq.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Linq; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Linq : SmartContract.Framework.SmartContract { public class Person @@ -184,3 +190,5 @@ public static object WhereGreaterThanZero(int[] array) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs index 63cb59739..095368f06 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Logical.cs @@ -10,8 +10,14 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Logical : SmartContract.Framework.SmartContract { public static bool TestConditionalLogicalAnd(bool x, bool y) @@ -45,3 +51,5 @@ public static bool TestLogicalNegation(bool x) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Math.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Math.cs index 57e2a2c3f..1a8e1edfc 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Math.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Math.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Math : SmartContract.Framework.SmartContract { public static int max(int a, int b) @@ -121,3 +128,5 @@ public static ulong ClampULong(ulong value, ulong min, ulong max) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_MemberAccess.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_MemberAccess.cs index 472370a6c..e56d5d719 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_MemberAccess.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_MemberAccess.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_MemberAccess : SmartContract.Framework.SmartContract { public static void TestMain() @@ -72,3 +78,5 @@ public class MyClass } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Multiple.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Multiple.cs index 90ce58215..b9bc9e2b7 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Multiple.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Multiple.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_MultipleA : SmartContract.Framework.SmartContract { public static bool test() => true; @@ -21,3 +29,5 @@ public class Contract_MultipleB : SmartContract.Framework.SmartContract public static bool test() => false; } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs index 669f1593b..10cdb8131 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NULL.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_NULL : SmartContract.Framework.SmartContract { public static bool IsNull(object? value) @@ -163,3 +169,5 @@ public static void StaticNullableCoalesceAssignment() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NativeContracts.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NativeContracts.cs index 8eaf5bea1..a980ecaae 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NativeContracts.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NativeContracts.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_NativeContracts : SmartContract.Framework.SmartContract { public static uint OracleMinimumResponseFee() @@ -60,3 +66,5 @@ public static uint LedgerCurrentIndex() } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NullableType.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NullableType.cs index 59cb47887..f5d55d074 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_NullableType.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_NullableType.cs @@ -11,9 +11,15 @@ using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_NullableType : SmartContract.Framework.SmartContract { // BigInteger tests @@ -120,3 +126,5 @@ public class Contract_NullableType : SmartContract.Framework.SmartContract public static string TestStringConcat(string? a, string? b) => (a ?? "") + (b ?? ""); public static string TestStringConcatNonNullable(string a, string b) => a + b; } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment1.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment1.cs index e332473a8..e762a4865 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment1.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment1.cs @@ -11,9 +11,16 @@ using Neo.SmartContract.Framework.Services; using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_OnDeployment1 : SmartContract.Framework.SmartContract { [DisplayName("_deploy")] @@ -23,3 +30,5 @@ public static void MyDeployMethod(object data, bool update) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment2.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment2.cs index 67fa02c22..b6f188721 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment2.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_OnDeployment2.cs @@ -9,10 +9,17 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_OnDeployment2 : SmartContract.Framework.SmartContract { public static void _deploy(object data, bool update) @@ -21,3 +28,5 @@ public static void _deploy(object data, bool update) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Optimize.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Optimize.cs index 6b997a7a2..b8bd02317 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Optimize.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Optimize.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Optimize : SmartContract.Framework.SmartContract { private static string privateMethod() @@ -42,3 +50,5 @@ public static object testArgs2(byte[] a) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Out.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Out.cs index f2422adb6..658e93c73 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Out.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Out.cs @@ -11,9 +11,15 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_Out : SmartContract.Framework.SmartContract { // Basic out parameter usage @@ -114,3 +120,5 @@ private static int ProcessNestedOut(out int x) return x * 2; } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Overflow.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Overflow.cs index c83a843ba..9f03a43a9 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Overflow.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Overflow.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Overflow : SmartContract.Framework.SmartContract { public static int AddInt(int a, int b) => a + b; @@ -38,3 +46,5 @@ public class Contract_Overflow : SmartContract.Framework.SmartContract public static long NegateAddLongChecked(long a, long b) => checked(-(a + b)); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Params.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Params.cs index 4693c7870..0907f9aba 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Params.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Params.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public sealed class Contract_Params : SmartContract.Framework.SmartContract { private static int Sum(params int[] args) @@ -27,3 +35,5 @@ public static int Test() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Partial.1.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Partial.1.cs index a9edd97df..4edcc11a3 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Partial.1.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Partial.1.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public partial class Contract_Partial : SmartContract.Framework.SmartContract { public static int test1() @@ -19,3 +27,5 @@ public static int test1() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs index 2dbbc08a4..61ded91c1 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Pattern.cs @@ -12,10 +12,16 @@ using System; using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Pattern : SmartContract.Framework.SmartContract { public bool between(int value) @@ -110,3 +116,5 @@ public int TestTypePattern2(object t) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Polymorphism.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Polymorphism.cs index c049500b3..c4c0aebd8 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Polymorphism.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Polymorphism.cs @@ -11,9 +11,16 @@ using System; using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public abstract class A : SmartContract.Framework.SmartContract { public A() : base() { } @@ -91,3 +98,5 @@ public override string abstractTest() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_PostfixUnary.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_PostfixUnary.cs index 4ba43ff0c..1520b4788 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_PostfixUnary.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_PostfixUnary.cs @@ -11,6 +11,7 @@ using Microsoft.ApplicationInsights.DataContracts; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; using System; @@ -18,6 +19,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_PostfixUnary : SmartContract.Framework.SmartContract { public class Person @@ -83,3 +89,5 @@ public static void TestInvert() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Property.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Property.cs index 8563539bf..6b2792ccf 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Property.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Property.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Property : SmartContract.Framework.SmartContract { // Read-only property @@ -270,3 +277,5 @@ public void Reset() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_PropertyMethod.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_PropertyMethod.cs index 979a09680..47e2603f6 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_PropertyMethod.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_PropertyMethod.cs @@ -10,9 +10,15 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_PropertyMethod : SmartContract.Framework.SmartContract { public static (string, int) testProperty() @@ -75,3 +81,5 @@ public Person() #pragma warning restore CS8618 } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Record.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Record.cs index 30d4869ca..1d0cd047f 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Record.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Record.cs @@ -13,6 +13,8 @@ using Neo.SmartContract.Framework.Services; using System; using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { @@ -29,6 +31,11 @@ public StudentR(string n) } } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Record : SmartContract.Framework.SmartContract { public static object Test_CreateRecord(string n, int a) @@ -65,3 +72,5 @@ public static string Test_DeconstructRecord(string n, int a) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Recursion.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Recursion.cs index 56f7b1660..2cca72175 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Recursion.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Recursion.cs @@ -11,9 +11,15 @@ using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Recursion : SmartContract.Framework.SmartContract { /// @@ -70,3 +76,5 @@ public static List public static bool Odd(BigInteger n) => n == 0 ? false : Even(n < 0 ? n + 1 : n - 1); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Returns.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Returns.cs index fd79ec26d..1a06cc87d 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Returns.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Returns.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Returns : SmartContract.Framework.SmartContract { /// @@ -115,3 +121,5 @@ public static int TryReturn() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_CheckWitness.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_CheckWitness.cs index 542a4387f..929c2642b 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_CheckWitness.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_CheckWitness.cs @@ -10,16 +10,23 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_CheckWitness : SmartContract.Framework.SmartContract { public static void CheckWitnessAnalysis(UInt160 u) { - Runtime.CheckWitness(u); ExecutionEngine.Assert(Runtime.CheckWitness(u)); } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs index a84abd4ab..28d5ead87 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_Reentrancy.cs @@ -17,6 +17,11 @@ namespace Neo.Compiler.CSharp.TestContracts { #pragma warning disable CS8625 + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Reentrancy : SmartContract.Framework.SmartContract { public static void HasReentrancy() @@ -65,3 +70,5 @@ public static void NoReentrancyByAttribute() #pragma warning restore CS8625 } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_WriteInTry.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_WriteInTry.cs index 7e80b7d4f..3bf21f608 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_WriteInTry.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_SecurityAnalyzer/Contract_WriteInTry.cs @@ -11,10 +11,16 @@ using System; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_WriteInTry : SmartContract.Framework.SmartContract { public static void BaseTry() @@ -110,3 +116,5 @@ public static void UnsafeNestedTryWrite(bool recursive) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Stack.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Stack.cs index 34255f09d..5af672e4a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Stack.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Stack.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_Stack : SmartContract.Framework.SmartContract { public static BigInteger Test_Push_Integer(BigInteger value) @@ -34,3 +41,5 @@ public static (int, int, long) Test_External() return (minusOne, intValue, longValue); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticByteArray.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticByteArray.cs index 0c2fe3480..969645198 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticByteArray.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticByteArray.cs @@ -11,9 +11,16 @@ using System; using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticByteArray : SmartContract.Framework.SmartContract { [DisplayName("TestEvent")] @@ -29,3 +36,5 @@ public static byte[] TestStaticByteArray() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticClass.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticClass.cs index e77aff4cf..d733c3c8f 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticClass.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticClass.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticClass : SmartContract.Framework.SmartContract { class TestClass @@ -33,3 +41,5 @@ public static int TestStaticClass() return _testClass2.TestStaticClass(); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticConstruct.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticConstruct.cs index 4ddb21a19..211182bf0 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticConstruct.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticConstruct.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticConstruct : SmartContract.Framework.SmartContract { static int a; @@ -27,3 +35,5 @@ public static int TestStatic() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs index 13f943732..658f1aa9d 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using System.Numerics; namespace Neo.Compiler.CSharp.TestContracts @@ -22,6 +23,11 @@ namespace Neo.Compiler.CSharp.TestContracts /// attribute for types that cannot be directly assigned. /// public interfaces of can be static and non-static. /// + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticVar : SmartContract.Framework.SmartContract { // Direct initialization of a static integer. @@ -99,3 +105,5 @@ public static string testGetString() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs index d1fd5baa2..7934479e0 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticVarInit : SmartContract.Framework.SmartContract { //define and static var and init it with a runtime code. @@ -35,3 +41,5 @@ static UInt160 TestStaticInit() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Storage.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Storage.cs index efa37dd1d..e57f38964 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Storage.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Storage.cs @@ -18,6 +18,11 @@ namespace Neo.Compiler.CSharp.TestContracts { [ContractPermission("*", "*")] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Storage : SmartContract.Framework.SmartContract { #region A @@ -72,3 +77,5 @@ public static void WriteB() #endregion } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs index f63d52edd..d58ee77a4 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_String.cs @@ -11,11 +11,17 @@ using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_String : SmartContract.Framework.SmartContract { public static void TestMain() @@ -131,3 +137,5 @@ public static int TestLength(string s) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Switch.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Switch.cs index b12a59dfd..83a7e1530 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Switch.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Switch.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Switch : SmartContract.Framework.SmartContract { public static object SwitchLong(string method) @@ -127,3 +135,5 @@ public static object SwitchLongLong(string test) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Syscall_Out.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Syscall_Out.cs index 6a6167017..f9677642f 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Syscall_Out.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Syscall_Out.cs @@ -9,8 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + namespace Neo.Compiler.CSharp.TestContracts; +[ContractAuthor("core-dev", "dev@neo.org")] +[ContractVersion("0.0.1")] +[ContractDescription("Compiler Test Contract")] +[ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] +[ContractPermission(Permission.Any, Method.Any)] public class Contract_Syscall_Out : SmartContract.Framework.SmartContract { public static (bool, byte) TestByteTryParse(string s) @@ -67,3 +75,5 @@ public static (bool, bool) TestBoolTryParse(string s) return (success, result); } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs index c0b555ba0..4b9e9f255 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Throw.cs @@ -10,9 +10,16 @@ // modifications are permitted. using System; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Throw : SmartContract.Framework.SmartContract { public static void TestMain(string[] args) @@ -21,3 +28,5 @@ public static void TestMain(string[] args) } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs index 73d25a2cc..aa7598ff4 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs @@ -14,6 +14,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_TryCatch : SmartContract.Framework.SmartContract { [ByteArray("0a0b0c0d0E0F")] @@ -430,8 +435,10 @@ public static string catchExceptionType() { string result = "NoException"; try { throw new System.Exception(); } - catch (UncatchableException e) { result += e; } + catch (System.Exception e) { result += e; } return result; } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Tuple.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Tuple.cs index bd4857a53..e5dcec730 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Tuple.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Tuple.cs @@ -10,6 +10,8 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { @@ -32,6 +34,11 @@ struct StructB #pragma warning restore CS0649 // Field is never assigned to, and will always have its default value } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Tuple : SmartContract.Framework.SmartContract { public static (BigInteger, BigInteger, BigInteger, BigInteger) GetResult() @@ -51,3 +58,5 @@ public static object T1() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TypeConvert.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TypeConvert.cs index dfde1323f..66ad59791 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TypeConvert.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TypeConvert.cs @@ -10,10 +10,16 @@ // modifications are permitted. using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; using System.Numerics; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_TypeConvert : SmartContract.Framework.SmartContract { public static object testType() @@ -43,3 +49,5 @@ public static object testType() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types.cs index 3f54b405e..055ff42b6 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types.cs @@ -19,6 +19,10 @@ namespace Neo.Compiler.CSharp.TestContracts { [ContractPermission(Permission.Any, Method.Any)] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] public class Contract_Types : SmartContract.Framework.SmartContract { public enum EDummy : byte @@ -117,3 +121,4 @@ public static object Create(byte[] nef, string manifest) #pragma warning restore CS8625 } } + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_BigInteger.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_BigInteger.cs index e491f5994..d1c0ce922 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_BigInteger.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_BigInteger.cs @@ -11,9 +11,15 @@ using Neo.SmartContract.Framework.Attributes; using System.Numerics; +using Neo.SmartContract.Framework; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Types_BigInteger : SmartContract.Framework.SmartContract { [Integer("100000000000000000000000000")] @@ -36,3 +42,5 @@ public static BigInteger SumOverflow() public static BigInteger ConvertFromChar() { return (BigInteger)'A'; } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_ECPoint.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_ECPoint.cs index aef9fab21..acf910617 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_ECPoint.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Types_ECPoint.cs @@ -14,6 +14,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Types_ECPoint : SmartContract.Framework.SmartContract { [PublicKey("024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9")] @@ -37,3 +42,5 @@ public static object ecpoint2ByteArray() } } } + + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_UIntTypes.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_UIntTypes.cs index fb0ac2259..d008ed461 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_UIntTypes.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_UIntTypes.cs @@ -14,6 +14,11 @@ namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_UIntTypes : SmartContract.Framework.SmartContract { [Hash160("NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB")] @@ -25,3 +30,4 @@ public class Contract_UIntTypes : SmartContract.Framework.SmartContract public static bool validateAddress(UInt160 address) => address.IsValid && !address.IsZero; } } + diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_shift.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_shift.cs index ca9079336..8b2ce737c 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_shift.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_shift.cs @@ -11,9 +11,16 @@ using System; using System.ComponentModel; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.Compiler.CSharp.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Compiler Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.Compiler.CSharp.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_shift : SmartContract.Framework.SmartContract { public static int[] TestShift() @@ -35,3 +42,5 @@ public static System.Numerics.BigInteger[] TestShiftBigInt() } } } + + diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/CatchOnlySystemAnalyzerUnitTest.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/CatchOnlySystemAnalyzerUnitTest.cs index 543a2116c..906ce5232 100644 --- a/tests/Neo.SmartContract.Analyzer.UnitTests/CatchOnlySystemAnalyzerUnitTest.cs +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/CatchOnlySystemAnalyzerUnitTest.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; using Microsoft.CodeAnalysis.Testing; @@ -76,7 +75,7 @@ static void Main() [TestMethod] public async Task TestAnalyzer() { - var test = new CSharpAnalyzerTest + var test = new CSharpAnalyzerTest { TestCode = testCode }; @@ -84,14 +83,14 @@ public async Task TestAnalyzer() test.ExpectedDiagnostics.AddRange([expectedDiagnostic]); await test.RunAsync(); - test = new CSharpAnalyzerTest + test = new CSharpAnalyzerTest { TestCode = codeWithoutExceptionType }; // no ExpectedDiagnostics await test.RunAsync(); - test = new CSharpAnalyzerTest + test = new CSharpAnalyzerTest { TestCode = codeWithCorrectExceptionType }; @@ -102,7 +101,7 @@ public async Task TestAnalyzer() [TestMethod] public async Task TestCodeFix() { - var test = new CSharpCodeFixTest + var test = new CSharpCodeFixTest { TestCode = testCode, FixedCode = fixedCode diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/CheckWitnessUsageAnalyzerUnitTest.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/CheckWitnessUsageAnalyzerUnitTest.cs new file mode 100644 index 000000000..d384ac0cd --- /dev/null +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/CheckWitnessUsageAnalyzerUnitTest.cs @@ -0,0 +1,415 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// CheckWitnessUsageAnalyzerUnitTest.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +using VerifyCS = Neo.SmartContract.Analyzer.UnitTests.TestHelper; + +namespace Neo.SmartContract.Analyzer.UnitTests +{ + [TestClass] + public class CheckWitnessUsageAnalyzerUnitTest + { + [TestMethod] + public async Task CheckWitnessUsageAnalyzer_UnverifiedResult_ShouldReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Unverified CheckWitness result + Runtime.CheckWitness(owner); + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + + // Add all expected diagnostics + // Compiler errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 9, 9, 16).WithArguments("Runtime")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(9, 9, 9, 16).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(9, 17, 9, 29).WithArguments("System.Object")); + + // Our analyzer diagnostic + test.ExpectedDiagnostics.Add(new DiagnosticResult(CheckWitnessUsageAnalyzer.DiagnosticId, DiagnosticSeverity.Warning) + .WithSpan(9, 15, 9, 41) + .WithArguments("Use Assert(Runtime.CheckWitness(...)) or if (Runtime.CheckWitness(...))")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task CheckWitnessUsageAnalyzer_VerifiedWithAssert_ShouldNotReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Verified with Assert + Assert(Runtime.CheckWitness(owner)); + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + + // Add all expected diagnostics + // Compiler errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 9, 9, 15).WithArguments("Assert")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 16, 9, 23).WithArguments("Runtime")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(9, 22, 9, 29).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(9, 30, 9, 33).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(9, 34, 9, 39).WithArguments("System.String")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task CheckWitnessUsageAnalyzer_VerifiedWithIfCondition_ShouldNotReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Verified with if condition + if (Runtime.CheckWitness(owner)) + { + // Authorized code + } + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + + // Add all expected diagnostics + // Compiler errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 13, 9, 20).WithArguments("Runtime")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task CheckWitnessUsageAnalyzer_FixWithAssert() + { + const string originalCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Unverified CheckWitness result + Runtime.CheckWitness(owner); + } + } + """; + + const string fixedCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Unverified CheckWitness result + Assert(Runtime.CheckWitness(owner)); + } + } + """; + + var test = VerifyCS.CreateCodeFixTest(); + test.TestCode = originalCode; + test.FixedCode = fixedCode; + + // Add all expected diagnostics for the test state + // Compiler errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + + // Our analyzer diagnostic + test.ExpectedDiagnostics.Add(new DiagnosticResult(CheckWitnessUsageAnalyzer.DiagnosticId, DiagnosticSeverity.Warning) + .WithSpan(9, 15, 9, 41) + .WithArguments("Use Assert(Runtime.CheckWitness(...)) or if (Runtime.CheckWitness(...))")); + + // Clear fixed state diagnostics + test.FixedState.ExpectedDiagnostics.Clear(); + + // Add all expected diagnostics for the fixed state + // Compiler errors + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 9, 9, 15).WithArguments("Assert")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 16, 9, 23).WithArguments("Runtime")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task CheckWitnessUsageAnalyzer_FixWithIfCondition() + { + const string originalCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Unverified CheckWitness result + Runtime.CheckWitness(owner); + } + } + """; + + const string fixedCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main(UInt160 owner) + { + // Unverified CheckWitness result + if (Runtime.CheckWitness(owner)) + { + // Add your code here + } + else + { + throw new Exception("No authorization."); + } + } + } + """; + + var test = VerifyCS.CreateCodeFixTest(); + test.TestCode = originalCode; + test.FixedCode = fixedCode; + test.CodeActionIndex = 1; // Use the second code fix (if condition) + + // Add all expected diagnostics for the test state + // Compiler errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + + // Our analyzer diagnostic + test.ExpectedDiagnostics.Add(new DiagnosticResult(CheckWitnessUsageAnalyzer.DiagnosticId, DiagnosticSeverity.Warning) + .WithSpan(9, 15, 9, 41) + .WithArguments("Use Assert(Runtime.CheckWitness(...)) or if (Runtime.CheckWitness(...))")); + + // Clear fixed state diagnostics + test.FixedState.ExpectedDiagnostics.Clear(); + + // Add all expected diagnostics for the fixed state + // Compiler errors + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Boolean")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithArguments("System.Void")); + + // CS1705 errors + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS1705") + .WithArguments("Neo.SmartContract.Framework", "Neo.SmartContract.Framework, Version=3.7.4.0, Culture=neutral, PublicKeyToken=null", + "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime", + "System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")); + + // Specific errors with spans + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(4, 14, 4, 26).WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 19, 6, 23).WithArguments("System.Void")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0518").WithSpan(6, 29, 6, 36).WithArguments("System.Object")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(9, 13, 9, 20).WithArguments("Runtime")); + test.FixedState.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0103").WithSpan(15, 18, 15, 26).WithArguments("Exception")); + + // Note: We're testing the "Use in if condition" code fix here by specifying CodeActionIndex = 1 + // This selects the second code fix provider action + + await test.RunAsync(); + } + } +} diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/ContractAttributeAnalyzerUnitTest.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/ContractAttributeAnalyzerUnitTest.cs new file mode 100644 index 000000000..ada4d4a1a --- /dev/null +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/ContractAttributeAnalyzerUnitTest.cs @@ -0,0 +1,185 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// ContractAttributeAnalyzerUnitTest.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +using VerifyCS = Neo.SmartContract.Analyzer.UnitTests.TestHelper; + +namespace Neo.SmartContract.Analyzer.UnitTests +{ + [TestClass] + public class ContractAttributeAnalyzerUnitTest + { + [TestMethod] + public async Task ContractAttributeAnalyzer_MissingAttributes_ShouldReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(ContractAttributeAnalyzer.DiagnosticIdMissingAttributes, DiagnosticSeverity.Warning) + .WithSpan(3, 14, 3, 26) + .WithArguments("DisplayName, ContractDescription, ContractVersion, ContractPermission")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task ContractAttributeAnalyzer_AllRequiredAttributes_ShouldNotReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Attributes; + + [DisplayName("Test Contract")] + [ContractDescription("This is a test contract")] + [ContractVersion("1.0.0")] + [ContractPermission(Permission.Any, Method.Any)] + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + // No diagnostics expected + + await test.RunAsync(); + } + + [TestMethod] + public async Task ContractAttributeAnalyzer_InvalidAttribute_ShouldReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Attributes; + + [DisplayName] + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(ContractAttributeAnalyzer.DiagnosticIdInvalidAttribute, DiagnosticSeverity.Warning) + .WithSpan(4, 2, 4, 14) + .WithArguments("DisplayName attribute requires a string parameter")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task ContractAttributeAnalyzer_FixMissingAttributes() + { + const string originalCode = """ + using Neo.SmartContract.Framework; + + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + const string fixedCode = """ + using Neo.SmartContract.Framework; + + [DisplayName("TestContract")] + [ContractDescription("Description of TestContract")] + [ContractVersion("1.0.0")] + [ContractPermission(Permission.Any, Method.Any)] + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + var test = VerifyCS.CreateCodeFixTest(); + test.TestCode = originalCode; + test.FixedCode = fixedCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(ContractAttributeAnalyzer.DiagnosticIdMissingAttributes, DiagnosticSeverity.Warning) + .WithSpan(3, 14, 3, 26) + .WithArguments("DisplayName, ContractDescription, ContractVersion, ContractPermission")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task ContractAttributeAnalyzer_FixInvalidAttribute() + { + const string originalCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Attributes; + + [DisplayName] + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + const string fixedCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Attributes; + + [DisplayName("MyContract")] + public class TestContract : SmartContract + { + public static void Main() + { + // Some code + } + } + """; + + var test = VerifyCS.CreateCodeFixTest(); + test.TestCode = originalCode; + test.FixedCode = fixedCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(ContractAttributeAnalyzer.DiagnosticIdInvalidAttribute, DiagnosticSeverity.Warning) + .WithSpan(4, 2, 4, 14) + .WithArguments("DisplayName attribute requires a string parameter")); + + await test.RunAsync(); + } + } +} diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerTests.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerTests.cs new file mode 100644 index 000000000..86a4cf340 --- /dev/null +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerTests.cs @@ -0,0 +1,91 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; + +namespace Neo.SmartContract.Analyzer.UnitTests +{ + [TestClass] + public class EventRegistrationAnalyzerTests + { + [TestMethod] + public async Task NonStaticEventDelegateIsAllowed() + { + // Arrange + var source = @" +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + +namespace TestContract +{ + public class Contract : SmartContract.Framework.SmartContract + { + // Non-static event delegate + public delegate void Transfer(string from, string to, int amount); + + public static void Main() + { + // Trigger the event + OnTransfer(""sender"", ""receiver"", 100); + } + + public static void OnTransfer(string from, string to, int amount) + { + Transfer(from, to, amount); + } + } +}"; + + // Act + var compilation = await TestHelper.CreateCompilationAsync(source); + var analyzer = new EventRegistrationAnalyzer(); + var diagnostics = await compilation.WithAnalyzers(ImmutableArray.Create(analyzer)).GetAnalyzerDiagnosticsAsync(); + + // Assert + // There should be no diagnostics for the non-static event delegate + Assert.AreEqual(0, diagnostics.Count(d => d.Id == EventRegistrationAnalyzer.DiagnosticIdImproperEventDefinition)); + } + + [TestMethod] + public async Task NonStaticEventFieldIsAllowed() + { + // Arrange + var source = @" +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; + +namespace TestContract +{ + public delegate void Transfer(string from, string to, int amount); + + public class Contract : SmartContract.Framework.SmartContract + { + // Non-static event field + public Transfer TransferEvent; + + public static void Main() + { + // Trigger the event + OnTransfer(""sender"", ""receiver"", 100); + } + + public static void OnTransfer(string from, string to, int amount) + { + TransferEvent(from, to, amount); + } + } +}"; + + // Act + var compilation = await TestHelper.CreateCompilationAsync(source); + var analyzer = new EventRegistrationAnalyzer(); + var diagnostics = await compilation.WithAnalyzers(ImmutableArray.Create(analyzer)).GetAnalyzerDiagnosticsAsync(); + + // Assert + // There should be no diagnostics for the non-static event field + Assert.AreEqual(0, diagnostics.Count(d => d.Id == EventRegistrationAnalyzer.DiagnosticIdImproperEventDefinition)); + } + } +} diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerUnitTest.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerUnitTest.cs new file mode 100644 index 000000000..5397ef89a --- /dev/null +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/EventRegistrationAnalyzerUnitTest.cs @@ -0,0 +1,155 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// EventRegistrationAnalyzerUnitTest.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.CodeAnalysis.CSharp.Testing; + +using VerifyCS = Neo.SmartContract.Analyzer.UnitTests.TestHelper; + +namespace Neo.SmartContract.Analyzer.UnitTests +{ + [TestClass] + public class EventRegistrationAnalyzerUnitTest + { + [TestMethod] + public async Task EventRegistrationAnalyzer_UnregisteredEvent_ShouldReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main() + { + // Using an unregistered event + Runtime.Notify(MyEvent, "data"); + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(EventRegistrationAnalyzer.DiagnosticIdUnregisteredEvent, DiagnosticSeverity.Error) + .WithSpan(9, 31, 9, 38) + .WithArguments("MyEvent")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task EventRegistrationAnalyzer_RegisteredEvent_ShouldNotReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + // Properly registered event + public static event Action MyEvent; + + public static void Main() + { + // Using a registered event + Runtime.Notify(MyEvent, "data"); + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + // No diagnostics expected + + await test.RunAsync(); + } + + [TestMethod] + public async Task EventRegistrationAnalyzer_NonStaticEvent_ShouldNotReportDiagnostic() + { + const string sourceCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + using System; + + public class TestContract : SmartContract + { + // Non-static event (now allowed) + public delegate void MyEventDelegate(string data); + public MyEventDelegate MyEvent; + + public static void Main() + { + // Using the event + Runtime.Notify(MyEvent, "data"); + } + } + """; + + var test = VerifyCS.CreateAnalyzerTest(); + test.TestCode = sourceCode; + // Only expect the unregistered event diagnostic, not the non-static warning + test.ExpectedDiagnostics.Add(new DiagnosticResult(EventRegistrationAnalyzer.DiagnosticIdUnregisteredEvent, DiagnosticSeverity.Error) + .WithSpan(13, 31, 13, 38) + .WithArguments("MyEvent")); + + await test.RunAsync(); + } + + [TestMethod] + public async Task EventRegistrationAnalyzer_FixUnregisteredEvent() + { + const string originalCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public static void Main() + { + // Using an unregistered event + Runtime.Notify(MyEvent, "data"); + } + } + """; + + const string fixedCode = """ + using Neo.SmartContract.Framework; + using Neo.SmartContract.Framework.Services; + + public class TestContract : SmartContract + { + public delegate void MyEvent(string name); + + public static void Main() + { + // Using an unregistered event + Runtime.Notify(MyEvent, "data"); + } + } + """; + + var test = VerifyCS.CreateCodeFixTest(); + test.TestCode = originalCode; + test.FixedCode = fixedCode; + test.ExpectedDiagnostics.Add(new DiagnosticResult(EventRegistrationAnalyzer.DiagnosticIdUnregisteredEvent, DiagnosticSeverity.Error) + .WithSpan(9, 31, 9, 38) + .WithArguments("MyEvent")); + + await test.RunAsync(); + } + + + } +} diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/Neo.SmartContract.Analyzer.UnitTests.csproj b/tests/Neo.SmartContract.Analyzer.UnitTests/Neo.SmartContract.Analyzer.UnitTests.csproj index 3823a9862..ee0b2b1ab 100644 --- a/tests/Neo.SmartContract.Analyzer.UnitTests/Neo.SmartContract.Analyzer.UnitTests.csproj +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/Neo.SmartContract.Analyzer.UnitTests.csproj @@ -6,10 +6,22 @@ Neo.SmartContract.Analyzer.UnitTests false true + net9.0 + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/tests/Neo.SmartContract.Analyzer.UnitTests/TestHelper.cs b/tests/Neo.SmartContract.Analyzer.UnitTests/TestHelper.cs new file mode 100644 index 000000000..2f0139a9f --- /dev/null +++ b/tests/Neo.SmartContract.Analyzer.UnitTests/TestHelper.cs @@ -0,0 +1,265 @@ +// Copyright (C) 2015-2025 The Neo Project. +// +// TestHelper.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace Neo.SmartContract.Analyzer.UnitTests +{ + public static class TestHelper + { + private static readonly string[] NeoAssemblies = new[] + { + "Neo.SmartContract.Framework.dll" + }; + + public static Task CreateCompilationAsync(string source) + { + return CreateCompilationAsync(source, new string[] { }); + } + + + + public static async Task CreateCompilationAsync(string source, string[] additionalReferences) + { + var references = new List(); + + // Add basic .NET references + var trustedAssemblies = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator); + foreach (var path in trustedAssemblies) + { + try + { + references.Add(MetadataReference.CreateFromFile(path)); + } + catch + { + // Ignore any assemblies that can't be loaded + } + } + + // Add Neo.SmartContract.Framework reference + foreach (var assembly in NeoAssemblies) + { + var neoAssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assembly); + if (File.Exists(neoAssemblyPath)) + { + references.Add(MetadataReference.CreateFromFile(neoAssemblyPath)); + } + else + { + // Try to find the assembly in the build output + var projectDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.Parent.FullName; + var frameworkPath = Path.Combine(projectDir, "src", "Neo.SmartContract.Framework", "bin", "Debug", "net9.0", assembly); + + if (File.Exists(frameworkPath)) + { + references.Add(MetadataReference.CreateFromFile(frameworkPath)); + } + else + { + throw new FileNotFoundException($"Could not find {assembly}. Make sure it's built and available."); + } + } + } + + // Add additional references + foreach (var reference in additionalReferences) + { + references.Add(MetadataReference.CreateFromFile(reference)); + } + + var compilation = CSharpCompilation.Create( + "TestCompilation", + new[] { CSharpSyntaxTree.ParseText(source) }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + return compilation; + } + + public static CSharpCodeFixTest CreateCodeFixTest() + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new() + { + var test = new CustomCodeFixTest(); + test.SolutionTransforms.Add((solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler().Select(id => new KeyValuePair(id, ReportDiagnostic.Suppress)))); + + return solution.WithProjectCompilationOptions(projectId, compilationOptions); + }); + return test; + } + + public static CSharpAnalyzerTest CreateAnalyzerTest() + where TAnalyzer : DiagnosticAnalyzer, new() + { + var test = new CustomAnalyzerTest(); + test.SolutionTransforms.Add((solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler().Select(id => new KeyValuePair(id, ReportDiagnostic.Suppress)))); + + return solution.WithProjectCompilationOptions(projectId, compilationOptions); + }); + return test; + } + + private static IEnumerable GetNullableWarningsFromCompiler() + { + // These are the compiler diagnostics we want to suppress + return new[] + { + // CS errors + "CS0518", "CS0246", "CS0103", "CS1705", + }; + } + + private class CustomCodeFixTest : CSharpCodeFixTest + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new() + { + public CustomCodeFixTest() + { + TestState.AdditionalReferences.Add( + MetadataReference.CreateFromFile(typeof(object).Assembly.Location)); + + // Add Neo.SmartContract.Framework reference + foreach (var assembly in NeoAssemblies) + { + var neoAssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assembly); + if (File.Exists(neoAssemblyPath)) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(neoAssemblyPath)); + } + else + { + // Try to find the assembly in the build output + var projectDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.Parent.FullName; + var frameworkPath = Path.Combine(projectDir, "src", "Neo.SmartContract.Framework", "bin", "Debug", "net9.0", assembly); + + if (File.Exists(frameworkPath)) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(frameworkPath)); + } + } + } + + // Add System.Numerics for BigInteger + var trustedAssemblies = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator); + var systemNumerics = trustedAssemblies.FirstOrDefault(a => a.EndsWith("System.Numerics.dll")); + if (systemNumerics != null) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(systemNumerics)); + } + + // Configure to ignore compiler diagnostics + TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*.cs]\ndotnet_diagnostic.CS*.severity = none\n")); + + // Suppress compiler diagnostics + TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck; + } + + protected override CompilationOptions CreateCompilationOptions() + { + var compilationOptions = base.CreateCompilationOptions(); + return compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler().Select(id => new KeyValuePair(id, ReportDiagnostic.Suppress)))); + } + + private static IEnumerable GetNullableWarningsFromCompiler() + { + // These are the compiler diagnostics we want to suppress + return new[] + { + // CS errors + "CS0518", "CS0246", "CS0103", "CS1705", + }; + } + } + + private class CustomAnalyzerTest : CSharpAnalyzerTest + where TAnalyzer : DiagnosticAnalyzer, new() + { + public CustomAnalyzerTest() + { + TestState.AdditionalReferences.Add( + MetadataReference.CreateFromFile(typeof(object).Assembly.Location)); + + // Add Neo.SmartContract.Framework reference + foreach (var assembly in NeoAssemblies) + { + var neoAssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assembly); + if (File.Exists(neoAssemblyPath)) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(neoAssemblyPath)); + } + else + { + // Try to find the assembly in the build output + var projectDir = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.Parent.FullName; + var frameworkPath = Path.Combine(projectDir, "src", "Neo.SmartContract.Framework", "bin", "Debug", "net9.0", assembly); + + if (File.Exists(frameworkPath)) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(frameworkPath)); + } + } + } + + // Add System.Numerics for BigInteger + var trustedAssemblies = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator); + var systemNumerics = trustedAssemblies.FirstOrDefault(a => a.EndsWith("System.Numerics.dll")); + if (systemNumerics != null) + { + TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(systemNumerics)); + } + + // Configure to ignore compiler diagnostics + TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "root = true\n\n[*.cs]\ndotnet_diagnostic.CS*.severity = none\n")); + + // Suppress compiler diagnostics + TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck; + } + + protected override CompilationOptions CreateCompilationOptions() + { + var compilationOptions = base.CreateCompilationOptions(); + return compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler().Select(id => new KeyValuePair(id, ReportDiagnostic.Suppress)))); + } + + private static IEnumerable GetNullableWarningsFromCompiler() + { + // These are the compiler diagnostics we want to suppress + return new[] + { + // CS errors + "CS0518", "CS0246", "CS0103", "CS1705", + }; + } + } + } +} diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Attribute.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Attribute.cs index 951130131..8f7198356 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Attribute.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Attribute.cs @@ -32,6 +32,11 @@ public override void Enter() public override void Exit() { } } + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Attribute : SmartContract { [OwnerOnly("AAAAAAAAAAAAAAAAAAAAAAAAAAA=")] @@ -63,3 +68,4 @@ public void reentrantTest(int value) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Blockchain.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Blockchain.cs index 9ca96899c..88c46443a 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Blockchain.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Blockchain.cs @@ -13,9 +13,15 @@ using Neo.SmartContract.Framework.Services; using System; using System.Numerics; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Blockchain : SmartContract { public static uint GetHeight() @@ -129,3 +135,4 @@ public static BigInteger GetTxVMState(UInt256 hash) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Contract.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Contract.cs index c3f8e5933..0093cfc60 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Contract.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Contract.cs @@ -16,6 +16,10 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { [ContractPermission(Permission.Any, Method.Any)] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] public class Contract_Contract : SmartContract { public static object Call(UInt160 scriptHash, string method, CallFlags flag, object[] args) @@ -41,3 +45,4 @@ public static UInt160 CreateStandardAccount(ECPoint pubKey) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Create.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Create.cs index 65f494319..7e8b8cd00 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Create.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Create.cs @@ -16,6 +16,10 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { [ContractPermission(Permission.Any, Method.Any)] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] public class Contract_Create : SmartContract { public static string OldContract() @@ -53,3 +57,4 @@ public static int GetCallFlags() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs index 76aceb833..ac5c6c784 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Crypto.cs @@ -11,9 +11,15 @@ using Neo.SmartContract.Framework.Native; using System.ComponentModel; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Crypto : SmartContract { [DisplayName("SHA256")] @@ -84,3 +90,4 @@ public static object Bls12381Pairing(object g1, object g2) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExecutionEngine.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExecutionEngine.cs index 74fc1238d..966c3874b 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExecutionEngine.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExecutionEngine.cs @@ -9,10 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ExecutionEngine : SmartContract { public static byte[] CallingScriptHash() @@ -43,3 +49,4 @@ public static object Transaction() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExtraAttribute.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExtraAttribute.cs index e61e0aa3c..1b51ae9ce 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExtraAttribute.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ExtraAttribute.cs @@ -15,6 +15,11 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { [ManifestExtra("Author", "Neo")] [ManifestExtra("E-mail", "dev@neo.org")] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ExtraAttribute : SmartContract { public static object Main2(string method, object[] args) @@ -23,3 +28,4 @@ public static object Main2(string method, object[] args) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Helper.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Helper.cs index 0bdcacbae..f89458399 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Helper.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Helper.cs @@ -14,6 +14,11 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Helper : SmartContract { [ByteArray("0a0b0c0d0E0F")] @@ -133,3 +138,4 @@ public static byte[] testToScriptHash() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_IOracle.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_IOracle.cs index e707342e2..bcb1e7fee 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_IOracle.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_IOracle.cs @@ -9,12 +9,18 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Interfaces; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_IOracle : SmartContract, IOracle { public void OnOracleResponse(string url, object userData, OracleResponseCode code, string result) @@ -26,3 +32,4 @@ public void OnOracleResponse(string url, object userData, OracleResponseCode cod } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Json.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Json.cs index c25afae8a..2c9a60c12 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Json.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Json.cs @@ -9,10 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Json : SmartContract { public static string Serialize(object obj) @@ -26,3 +32,4 @@ public static object Deserialize(string json) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_List.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_List.cs index a1eaf1e77..f0cc60b97 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_List.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_List.cs @@ -9,10 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_List : SmartContract { public static int TestCount(int count) @@ -75,3 +81,4 @@ public static int[] TestArrayConvert(int count) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs index 2c3c2c165..4199751f6 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_ManifestAttribute.cs @@ -18,6 +18,8 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses [ContractVersion("v3.6.3")] [ContractDescription("This is a test contract.")] [ManifestExtra("ExtraKey", "ExtraValue")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_ManifestAttribute : SmartContract { [NoReentrant] @@ -31,3 +33,4 @@ public void reentrantTest(int value) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Map.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Map.cs index 81d8eae86..45d99b798 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Map.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Map.cs @@ -9,10 +9,16 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Map : SmartContract { public static int TestCount(int count) @@ -102,3 +108,4 @@ public static object testuint160Key() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Native.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Native.cs index 461316b1e..bb5cc1840 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Native.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Native.cs @@ -12,9 +12,15 @@ using Neo.SmartContract.Framework.Native; using System.ComponentModel; using System.Numerics; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Native : SmartContract { [DisplayName("NEO_Decimals")] @@ -86,3 +92,4 @@ public static bool Policy_IsBlocked(UInt160 account) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Nullable.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Nullable.cs index b1d488def..a4e679057 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Nullable.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Nullable.cs @@ -12,9 +12,15 @@ using System; using System.Numerics; using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.TestContracts { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Nullable : SmartContract { public static bool BigIntegerNullableEqual(BigInteger a, BigInteger? b) @@ -240,3 +246,4 @@ public static bool BigIntegerNullableToString(BigInteger? a) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Pointers.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Pointers.cs index 8a929e332..3c7c03195 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Pointers.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Pointers.cs @@ -11,9 +11,15 @@ using System; using System.Numerics; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Pointers : SmartContract { public static object CreateFuncPointer() @@ -50,3 +56,4 @@ public static BigInteger CallFuncPointerWithArg() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Regex.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Regex.cs index 22615d53c..bb7d27fc8 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Regex.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Regex.cs @@ -9,8 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; + namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Regex : SmartContract { public static bool TestStartWith() @@ -54,3 +61,4 @@ public static bool TestUpperAlphabetOnly() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Runtime.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Runtime.cs index 634850313..01fd2b1a2 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Runtime.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Runtime.cs @@ -10,10 +10,16 @@ // modifications are permitted. using System.Numerics; +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Runtime : SmartContract { public static uint GetInvocationCounter() @@ -160,3 +166,4 @@ public static int DynamicSum(int a, int b) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SequencePointInserter.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SequencePointInserter.cs index 0b1a9b94d..1847f66c2 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SequencePointInserter.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SequencePointInserter.cs @@ -9,8 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; + namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_SequencePointInserter : SmartContract { public static int test(int a) @@ -20,3 +27,4 @@ public static int test(int a) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_StaticStorageMap.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_StaticStorageMap.cs index 81fdb02bb..26571c42c 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_StaticStorageMap.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_StaticStorageMap.cs @@ -11,9 +11,15 @@ using Neo.SmartContract.Framework.Services; using System.Numerics; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StaticStorageMap : SmartContract { private static StorageMap Data = new(Storage.CurrentContext, "data"); @@ -66,3 +72,4 @@ public static BigInteger teststoragemap_Getbyteprefix(byte x) #pragma warning restore CS8604 } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_StdLib.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_StdLib.cs index 6c19014f6..8f00319f4 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_StdLib.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_StdLib.cs @@ -11,9 +11,15 @@ using Neo.SmartContract.Framework.Native; using System.Numerics; +using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_StdLib : SmartContract { public static string base58CheckEncode(ByteString input) @@ -87,3 +93,4 @@ public static string[] stringSplit2(string str, string separator, bool removeEmp } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Storage.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Storage.cs index e8b8c7a43..0c4fd38ad 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Storage.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Storage.cs @@ -9,12 +9,18 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Services; namespace Neo.SmartContract.Framework.UnitTests.TestClasses { #pragma warning disable CS8604 + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Storage : SmartContract { // There is no main here, it can be auto generation. @@ -233,3 +239,4 @@ public static byte[] TestIndexGet(byte[] key) } #pragma warning restore CS8604 } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Stored.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Stored.cs index 422e6657f..4bb3a1e4a 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Stored.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Stored.cs @@ -14,6 +14,11 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Stored : SmartContract { // Test non-static @@ -102,3 +107,4 @@ public BigInteger TestMultiGet() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_String.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_String.cs index cbbd277c1..96a98bf2a 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_String.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_String.cs @@ -9,8 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; + namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_String : SmartContract { public static int TestStringAdd(string s1, string s2) @@ -34,3 +41,4 @@ public static string TestStringAddInt(string s, int i) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard26.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard26.cs index 6d8b1c6fc..2a2404407 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard26.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard26.cs @@ -22,6 +22,7 @@ namespace Neo.SmartContract.Framework.TestContracts [ContractVersion("")] [ContractPermission(Permission.Any, Method.Any)] [SupportedStandards(NepStandard.Nep26)] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] public class Contract_SupportedStandard26 : SmartContract, INEP26 { public void OnNEP11Payment(UInt160 from, BigInteger amount, string tokenId, object? data = null) @@ -29,3 +30,4 @@ public void OnNEP11Payment(UInt160 from, BigInteger amount, string tokenId, obje } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard27.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard27.cs index 64f01a5ab..23b2a4237 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard27.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandard27.cs @@ -22,6 +22,7 @@ namespace Neo.SmartContract.Framework.TestContracts [ContractVersion("")] [ContractPermission(Permission.Any, Method.Any)] [SupportedStandards(NepStandard.Nep27)] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] public class Contract_SupportedStandard27 : SmartContract, INEP27 { public void OnNEP17Payment(UInt160 from, BigInteger amount, object? data = null) @@ -29,3 +30,4 @@ public void OnNEP17Payment(UInt160 from, BigInteger amount, object? data = null) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandards.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandards.cs index 177fca91c..356c94a3e 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandards.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_SupportedStandards.cs @@ -16,6 +16,11 @@ namespace Neo.SmartContract.Framework.UnitTests.TestClasses { // Both NEP-10 and NEP-5 are obsolete, but this is just a test contract [SupportedStandards("NEP-10", "NEP-5")] + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_SupportedStandards : SmartContract { public static bool TestStandard() @@ -24,3 +29,4 @@ public static bool TestStandard() } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_UInt.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_UInt.cs index 5a2f30a44..2a3236749 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_UInt.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_UInt.cs @@ -9,8 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; + namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_UInt : SmartContract { public static bool IsValidAndNotZeroUInt256(UInt256 value) => value.IsValidAndNotZero; @@ -31,3 +38,4 @@ public static string ToAddress(UInt160 value) } } } + diff --git a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Update.cs b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Update.cs index 441eda475..086b64ce1 100644 --- a/tests/Neo.SmartContract.Framework.TestContracts/Contract_Update.cs +++ b/tests/Neo.SmartContract.Framework.TestContracts/Contract_Update.cs @@ -9,8 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.SmartContract.Framework.Attributes; + namespace Neo.SmartContract.Framework.UnitTests.TestClasses { + [ContractAuthor("core-dev", "dev@neo.org")] + [ContractVersion("0.0.1")] + [ContractDescription("Neo Framework Test Contract")] + [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/tests/Neo.SmartContract.Framework.TestContracts")] + [ContractPermission(Permission.Any, Method.Any)] public class Contract_Update : SmartContract { public static string ImUpdated() @@ -19,3 +26,4 @@ public static string ImUpdated() } } } +