예제 #1
0
        private static void AddMissingMembersToStatefulMarshaller(DocumentEditor editor, SyntaxNode declaringSyntax, INamedTypeSymbol marshallerType, ITypeSymbol managedType, HashSet <string> missingMemberNames, bool isLinearCollectionMarshaller)
        {
            SyntaxGenerator gen = editor.Generator;

            // Get the methods of the shape so we can use them to determine what types to use in signatures that are not obvious.
            var(_, methods) = StatefulMarshallerShapeHelper.GetShapeForType(marshallerType, managedType, isLinearCollectionMarshaller, editor.SemanticModel.Compilation);
            INamedTypeSymbol spanOfT         = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_Span_Metadata) !;
            INamedTypeSymbol readOnlySpanOfT = editor.SemanticModel.Compilation.GetBestTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata) !;

            var(typeParameters, _) = marshallerType.GetAllTypeArgumentsIncludingInContainingTypes();

            // Use a lazy factory for the type syntaxes to avoid re-checking the various methods and reconstructing the syntax.
            Lazy <SyntaxNode>  unmanagedTypeSyntax      = new(CreateUnmanagedTypeSyntax, isThreadSafe : false);
            Lazy <ITypeSymbol> managedElementTypeSymbol = new(CreateManagedElementTypeSymbol, isThreadSafe : false);

            List <SyntaxNode> newMembers = new();

            if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromManaged))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.Value.Stateful.FromManaged,
                        parameters: new[] { gen.ParameterDeclaration("managed", gen.TypeExpression(managedType)) },
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToUnmanaged))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.Value.Stateful.ToUnmanaged,
                        returnType: unmanagedTypeSyntax.Value,
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.FromUnmanaged))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.Value.Stateful.FromUnmanaged,
                        parameters: new[] { gen.ParameterDeclaration("unmanaged", unmanagedTypeSyntax.Value) },
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.Value.Stateful.ToManaged))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.Value.Stateful.ToManaged,
                        returnType: gen.TypeExpression(managedType),
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.BufferSize))
            {
                newMembers.Add(
                    gen.WithAccessorDeclarations(
                        gen.PropertyDeclaration(ShapeMemberNames.BufferSize,
                                                gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_Int32)),
                                                Accessibility.Public,
                                                DeclarationModifiers.Static),
                        gen.GetAccessorDeclaration(statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) })));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesSource,
                        returnType: gen.TypeExpression(readOnlySpanOfT.Construct(managedElementTypeSymbol.Value)),
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesDestination,
                        returnType: gen.TypeExpression(spanOfT.Construct(typeParameters[typeParameters.Length - 1])),
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.LinearCollection.Stateful.GetUnmanagedValuesSource,
                        parameters: new[]
                {
                    gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32))
                },
                        returnType: gen.TypeExpression(readOnlySpanOfT.Construct(typeParameters[typeParameters.Length - 1])),
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.LinearCollection.Stateful.GetManagedValuesDestination,
                        parameters: new[]
                {
                    gen.ParameterDeclaration("numElements", gen.TypeExpression(SpecialType.System_Int32))
                },
                        returnType: gen.TypeExpression(spanOfT.Construct(managedElementTypeSymbol.Value)),
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            if (missingMemberNames.Contains(ShapeMemberNames.Free))
            {
                newMembers.Add(
                    gen.MethodDeclaration(
                        ShapeMemberNames.Value.Stateful.Free,
                        accessibility: Accessibility.Public,
                        statements: new[] { DefaultMethodStatement(gen, editor.SemanticModel.Compilation) }));
            }

            editor.ReplaceNode(declaringSyntax, (declaringSyntax, gen) => gen.AddMembers(declaringSyntax, newMembers));

            SyntaxNode CreateUnmanagedTypeSyntax()
            {
                ITypeSymbol?unmanagedType = null;

                if (methods.ToUnmanaged is not null)
                {
                    unmanagedType = methods.ToUnmanaged.ReturnType;
                }
                else if (methods.FromUnmanaged is not null)
                {
                    unmanagedType = methods.FromUnmanaged.Parameters[0].Type;
                }
                else if (methods.UnmanagedValuesSource is not null)
                {
                    unmanagedType = methods.UnmanagedValuesSource.Parameters[0].Type;
                }
                else if (methods.UnmanagedValuesDestination is not null)
                {
                    unmanagedType = methods.UnmanagedValuesDestination.Parameters[0].Type;
                }

                if (unmanagedType is not null)
                {
                    return(gen.TypeExpression(unmanagedType));
                }
                return(gen.TypeExpression(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr)));
            }

            ITypeSymbol CreateManagedElementTypeSymbol()
            {
                if (methods.ManagedValuesSource is not null)
                {
                    return(((INamedTypeSymbol)methods.ManagedValuesSource.ReturnType).TypeArguments[0]);
                }
                if (methods.ManagedValuesDestination is not null)
                {
                    return(((INamedTypeSymbol)methods.ManagedValuesDestination.ReturnType).TypeArguments[0]);
                }

                return(editor.SemanticModel.Compilation.GetSpecialType(SpecialType.System_IntPtr));
            }
        }
        private static void SuppressMarkMethodsAsStaticDiagnosticIfNeeded(SuppressionAnalysisContext context, Diagnostic diagnostic)
        {
            SemanticModel model           = context.GetSemanticModel(diagnostic.Location.SourceTree);
            ISymbol       diagnosedSymbol = model.GetDeclaredSymbol(diagnostic.Location.SourceTree.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan), context.CancellationToken);

            if (diagnosedSymbol.Kind != SymbolKind.Method)
            {
                return;
            }

            if (FindContainingEntryPointTypeAndManagedType(diagnosedSymbol.ContainingType) is (INamedTypeSymbol entryPointMarshallerType, INamedTypeSymbol managedType))
            {
                bool isLinearCollectionMarshaller = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointMarshallerType);
                (MarshallerShape _, StatefulMarshallerShapeHelper.MarshallerMethods methods) = StatefulMarshallerShapeHelper.GetShapeForType(diagnosedSymbol.ContainingType, managedType, isLinearCollectionMarshaller, context.Compilation);
                if (methods.IsShapeMethod((IMethodSymbol)diagnosedSymbol))
                {
                    // If we are a method of the shape on the stateful marshaller shape, then we need to be our current shape.
                    // So, suppress the diagnostic to make this method static, as that would break the shape.
                    context.ReportSuppression(Suppression.Create(MarkMethodsAsStaticSuppression, diagnostic));
                }
            }
        }