/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTests.cs
360 строк
17 KB
Tomáš Matoušek
Add ChecksumAlgorithm to project snapshot (#62840)
10 окт 2022, 20:50
Не верифицирован
10 окт 2022, 20:50
157d34a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.FlowAnalysis; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; using static Microsoft.CodeAnalysis.Operations.OperationExtensions; namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics { public class OperationTests : TestBase { private static void TestCore(Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression) { // Empty arguments and default argument names/refkinds ImmutableArray<IOperation> arguments = ImmutableArray<IOperation>.Empty; ImmutableArray<string> argumentNames = default; ImmutableArray<RefKind> argumentRefKinds = default; HasDynamicArgumentsExpression dynamicExpression = createDynamicExpression(arguments, argumentNames, argumentRefKinds); Assert.Throws<InvalidOperationException>(() => dynamicExpression.GetArgumentName(0)); Assert.Throws<InvalidOperationException>(() => dynamicExpression.GetArgumentRefKind(0)); // Non-empty arguments and default argument names/refkinds arguments = ImmutableArray.Create((IOperation)null); argumentNames = default; argumentRefKinds = default; dynamicExpression = createDynamicExpression(arguments, argumentNames, argumentRefKinds); Assert.Null(dynamicExpression.GetArgumentName(0)); Assert.Null(dynamicExpression.GetArgumentRefKind(0)); // Non-empty arguments and empty argument names/refkinds arguments = ImmutableArray.Create((IOperation)null); argumentNames = ImmutableArray<string>.Empty; argumentRefKinds = ImmutableArray<RefKind>.Empty; dynamicExpression = createDynamicExpression(arguments, argumentNames, argumentRefKinds); Assert.Null(dynamicExpression.GetArgumentName(0)); Assert.Equal(RefKind.None, dynamicExpression.GetArgumentRefKind(0)); // Non-empty arguments and non-empty argument names/refkinds string name = "first"; RefKind refKind = RefKind.Ref; arguments = ImmutableArray.Create((IOperation)null); argumentNames = ImmutableArray.Create(name); argumentRefKinds = ImmutableArray.Create(refKind); dynamicExpression = createDynamicExpression(arguments, argumentNames, argumentRefKinds); Assert.Equal(name, dynamicExpression.GetArgumentName(0)); Assert.Equal(refKind, dynamicExpression.GetArgumentRefKind(0)); // Index out of range: Negative index Assert.Throws<ArgumentOutOfRangeException>(() => dynamicExpression.GetArgumentName(-1)); Assert.Throws<ArgumentOutOfRangeException>(() => dynamicExpression.GetArgumentRefKind(-1)); // Index out of range: Index > Length Assert.Throws<ArgumentOutOfRangeException>(() => dynamicExpression.GetArgumentName(100)); Assert.Throws<ArgumentOutOfRangeException>(() => dynamicExpression.GetArgumentRefKind(100)); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void IDynamicInvocationExpression_PublicExtensionMethodTests() { // Test null argument IDynamicInvocationOperation nullDynamicExpression = null; Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentName(0)); Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0)); Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression = (arguments, argumentNames, argumentRefKinds) => new DynamicInvocationOperation(operation: null, arguments, argumentNames, argumentRefKinds, semanticModel: null, syntax: null, type: null, isImplicit: false); TestCore(createDynamicExpression); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void IDynamicIndexerAccessExpression_PublicExtensionMethodTests() { // Test null argument IDynamicIndexerAccessOperation nullDynamicExpression = null; Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentName(0)); Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0)); Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression = (arguments, argumentNames, argumentRefKinds) => new DynamicIndexerAccessOperation(operation: null, arguments, argumentNames, argumentRefKinds, semanticModel: null, syntax: null, type: null, isImplicit: false); TestCore(createDynamicExpression); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void IDynamicObjectCreationExpression_PublicExtensionMethodTests() { // Test null argument IDynamicObjectCreationOperation nullDynamicExpression = null; Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentName(0)); Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0)); Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression = (arguments, argumentNames, argumentRefKinds) => new DynamicObjectCreationOperation(initializer: null, arguments, argumentNames, argumentRefKinds, semanticModel: null, syntax: null, type: null, isImplicit: false); TestCore(createDynamicExpression); } [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] [Fact] public void TestGetFlowGraphNullArgument() { Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IBlockOperation)null)); Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IFieldInitializerOperation)null)); Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IPropertyInitializerOperation)null)); Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IParameterInitializerOperation)null)); Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IConstructorBodyOperation)null)); Assert.Throws<ArgumentNullException>(() => ControlFlowGraph.Create((IMethodBodyOperation)null)); } [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] [Fact] public void TestGetFlowGraphInvalidArgumentWithNonNullParent() { IOperation parent = new BlockOperation(ImmutableArray<IOperation>.Empty, ImmutableArray<ILocalSymbol>.Empty, semanticModel: null, syntax: null, isImplicit: false); TestGetFlowGraphInvalidArgumentCore(argumentExceptionMessage: CodeAnalysisResources.NotARootOperation, parent); } [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] [Fact] public void TestGetFlowGraphInvalidArgumentWithNullSemanticModel() { TestGetFlowGraphInvalidArgumentCore(argumentExceptionMessage: CodeAnalysisResources.OperationHasNullSemanticModel, parent: null); } private void TestGetFlowGraphInvalidArgumentCore(string argumentExceptionMessage, IOperation parent) { bool exceptionThrown = false; try { IBlockOperation block = new BlockOperation( ImmutableArray<IOperation>.Empty, ImmutableArray<ILocalSymbol>.Empty, semanticModel: null, syntax: null, isImplicit: false); block = Operation.SetParentOperation(block, parent); _ = ControlFlowGraph.Create(block); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "body").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { IFieldInitializerOperation initializer = new FieldInitializerOperation( ImmutableArray<IFieldSymbol>.Empty, ImmutableArray<ILocalSymbol>.Empty, value: null, semanticModel: null, syntax: null, isImplicit: false); initializer = Operation.SetParentOperation(initializer, parent); _ = ControlFlowGraph.Create(initializer); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "initializer").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { IPropertyInitializerOperation initializer = new PropertyInitializerOperation( ImmutableArray<IPropertySymbol>.Empty, ImmutableArray<ILocalSymbol>.Empty, value: null, semanticModel: null, syntax: null, isImplicit: false); initializer = Operation.SetParentOperation(initializer, parent); _ = ControlFlowGraph.Create(initializer); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "initializer").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { IParameterInitializerOperation initializer = new ParameterInitializerOperation( parameter: null, locals: ImmutableArray<ILocalSymbol>.Empty, value: null, semanticModel: null, syntax: null, isImplicit: false); initializer = Operation.SetParentOperation(initializer, parent); _ = ControlFlowGraph.Create(initializer); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "initializer").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { IConstructorBodyOperation constructorBody = new ConstructorBodyOperation( ImmutableArray<ILocalSymbol>.Empty, initializer: null, blockBody: null, expressionBody: null, semanticModel: null, syntax: null, isImplicit: false); constructorBody = Operation.SetParentOperation(constructorBody, parent); _ = ControlFlowGraph.Create(constructorBody); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "constructorBody").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { IMethodBodyOperation methodBody = new MethodBodyOperation( blockBody: null, expressionBody: null, semanticModel: null, syntax: null, isImplicit: false); methodBody = Operation.SetParentOperation(methodBody, parent); _ = ControlFlowGraph.Create(methodBody); } catch (ArgumentException ex) { Assert.Equal(new ArgumentException(argumentExceptionMessage, "methodBody").Message, ex.Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; } [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] [Fact] public void TestControlFlowGraphCreateFromSyntax() { var source = @" class C { void M(int x) { x = 0; } }"; var tree = CSharpTestSource.Parse(source); var compilation = CSharpCompilation.Create("c", new[] { tree }); var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true); var methodBodySyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BaseMethodDeclarationSyntax>().Last(); // Verify ArgumentNullException bool exceptionThrown = false; try { _ = ControlFlowGraph.Create(node: null, model); } catch (ArgumentNullException ex) { Assert.Equal(ex.Message, new ArgumentNullException("node").Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; try { _ = ControlFlowGraph.Create(methodBodySyntax, semanticModel: null); } catch (ArgumentNullException ex) { Assert.Equal(ex.Message, new ArgumentNullException("semanticModel").Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; // Verify argument exception on providing a syntax node in executable code which does not produce root operation. try { var literal = tree.GetRoot().DescendantNodes().OfType<LiteralExpressionSyntax>().Single(); _ = ControlFlowGraph.Create(literal, model); } catch (ArgumentException ex) { Assert.Equal(ex.Message, new ArgumentException(CodeAnalysisResources.NotARootOperation, "operation").Message); exceptionThrown = true; } Assert.True(exceptionThrown); exceptionThrown = false; // Verify null return for non-executable code syntax node, which does not produce an operation. var classDecl = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Single(); Assert.Null(ControlFlowGraph.Create(classDecl, model)); // Verify identical CFG from method body syntax and operation. var cfgFromSyntax = ControlFlowGraph.Create(methodBodySyntax, model); var cfgSymbol = model.GetDeclaredSymbol(methodBodySyntax); Assert.NotNull(cfgFromSyntax); Assert.NotNull(cfgSymbol); var operation = (IMethodBodyOperation)model.GetOperation(methodBodySyntax); var cfgFromOperation = ControlFlowGraph.Create(operation); Assert.NotNull(cfgFromOperation); var expectedCfg = @" Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Block[B1] - Block Predecessors: [B0] Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsInvalid) (Syntax: 'x = 0;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32[missing], IsInvalid) (Syntax: 'x = 0') Left: IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32[missing]) (Syntax: 'x') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32[missing], Constant: 0, IsInvalid) (Syntax: '0') Next (Regular) Block[B2] Block[B2] - Exit Predecessors: [B1] Statements (0) "; ControlFlowGraphVerifier.VerifyGraph(compilation, expectedCfg, cfgFromSyntax, cfgSymbol); ControlFlowGraphVerifier.VerifyGraph(compilation, expectedCfg, cfgFromOperation, cfgSymbol); } } }