Exemplo n.º 1
0
            public void AnalyzeAttribute(SyntaxNodeAnalysisContext context)
            {
                AttributeSyntax syntax           = (AttributeSyntax)context.Node;
                ISymbol         attributedSymbol = context.ContainingSymbol !;

                AttributeData?attr = syntax.FindAttributeData(attributedSymbol);

                if (attr?.AttributeClass?.ToDisplayString() == TypeNames.CustomMarshallerAttribute &&
                    attr.AttributeConstructor is not null)
                {
                    DiagnosticReporter managedTypeReporter = DiagnosticReporter.CreateForLocation(syntax.FindArgumentWithNameOrArity("managedType", 0).FindTypeExpressionOrNullLocation(), context.ReportDiagnostic);
                    INamedTypeSymbol   entryType           = (INamedTypeSymbol)attributedSymbol;

                    INamedTypeSymbol?managedTypeInAttribute = (INamedTypeSymbol?)attr.ConstructorArguments[0].Value;
                    if (managedTypeInAttribute is null)
                    {
                        managedTypeReporter.CreateAndReportDiagnostic(ManagedTypeMustBeNonNullRule, entryType.ToDisplayString());
                    }

                    if (!ManualTypeMarshallingHelper.TryResolveManagedType(
                            entryType,
                            managedTypeInAttribute,
                            ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryType),
                            (entryType, managedType) => managedTypeReporter.CreateAndReportDiagnostic(ManagedTypeMustBeClosedOrMatchArityRule, managedType, entryType), out ITypeSymbol managedType))
                    {
                        return;
                    }
                    DiagnosticReporter marshallerTypeReporter    = DiagnosticReporter.CreateForLocation(syntax.FindArgumentWithNameOrArity("marshallerType", 2).FindTypeExpressionOrNullLocation(), context.ReportDiagnostic);
                    ITypeSymbol?       marshallerTypeInAttribute = (ITypeSymbol?)attr.ConstructorArguments[2].Value;
                    if (marshallerTypeInAttribute is null)
                    {
                        marshallerTypeReporter.CreateAndReportDiagnostic(MarshallerTypeMustBeNonNullRule);
                    }
                    if (!ManualTypeMarshallingHelper.TryResolveMarshallerType(
                            entryType,
                            marshallerTypeInAttribute,
                            (entryType, marshallerType) => marshallerTypeReporter.CreateAndReportDiagnostic(MarshallerTypeMustBeClosedOrMatchArityRule, marshallerType, entryType),
                            out ITypeSymbol marshallerType))
                    {
                        return;
                    }

                    AnalyzeMarshallerType(
                        marshallerTypeReporter,
                        (INamedTypeSymbol)managedType,
                        (MarshalMode)attr.ConstructorArguments[1].Value,
                        (INamedTypeSymbol?)marshallerType,
                        ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryType));
                }
            }
 private static (INamedTypeSymbol EntryPointType, INamedTypeSymbol ManagedType)? FindContainingEntryPointTypeAndManagedType(INamedTypeSymbol marshallerType)
 {
     for (INamedTypeSymbol containingType = marshallerType; containingType is not null; containingType = containingType.ContainingType)
     {
         AttributeData?attrData = containingType.GetAttributes().FirstOrDefault(
             attr => attr.AttributeClass?.ToDisplayString() == TypeNames.CustomMarshallerAttribute &&
             attr.AttributeConstructor is not null &&
             !attr.ConstructorArguments[0].IsNull &&
             attr.ConstructorArguments[2].Value is INamedTypeSymbol marshallerTypeInAttribute &&
             ManualTypeMarshallingHelper.TryResolveMarshallerType(containingType, marshallerTypeInAttribute, (_, _) => { }, out ITypeSymbol constructedMarshallerType) &&
             SymbolEqualityComparer.Default.Equals(constructedMarshallerType, marshallerType));
         if (attrData is not null)
         {
             return(containingType, (INamedTypeSymbol)attrData.ConstructorArguments[0].Value);
         }
     }
     return(null);
 }
        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));
                }
            }
        }
Exemplo n.º 4
0
        private static async Task <Solution> AddMissingMembers(Document doc, SyntaxNode node, HashSet <string> missingMemberNames, CancellationToken ct)
        {
            var model = await doc.GetSemanticModelAsync(ct).ConfigureAwait(false);

            var entryPointTypeSymbol = (INamedTypeSymbol)model.GetEnclosingSymbol(node.SpanStart, ct);

            // TODO: Convert to use the IOperation tree once IAttributeOperation is available
            var managedTypeSymbolInAttribute = GetManagedTypeInAttributeSyntax(node.GetLocation(), entryPointTypeSymbol);

            bool isLinearCollectionMarshaller = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointTypeSymbol);

            // Explicitly ignore the generic arity mismatch diagnostics as we will only reach here if there are no mismatches.
            // The analyzer will not for missing members if the managed type cannot be resolved.
            ManualTypeMarshallingHelper.TryResolveManagedType(entryPointTypeSymbol, ManualTypeMarshallingHelper.ReplaceGenericPlaceholderInType(managedTypeSymbolInAttribute, entryPointTypeSymbol, model.Compilation), isLinearCollectionMarshaller, IgnoreArityMismatch, out ITypeSymbol managedType);

            SymbolEditor editor = SymbolEditor.Create(doc.Project.Solution);

            INamedTypeSymbol marshallerType = (INamedTypeSymbol)model.GetSymbolInfo(node, ct).Symbol;

            await editor.EditOneDeclarationAsync(marshallerType, (editor, decl) => AddMissingMembers(editor, decl, marshallerType, managedType, missingMemberNames, isLinearCollectionMarshaller), ct).ConfigureAwait(false);

            return(editor.ChangedSolution);
        }
            private void AnalyzeManagedTypeMarshallingInfo(
                ITypeSymbol managedType,
                DiagnosticReporter diagnosticFactory,
                INamedTypeSymbol?entryType)
            {
                if (entryType is null)
                {
                    diagnosticFactory.CreateAndReportDiagnostic(
                        MarshallerEntryPointTypeMustBeNonNullRule,
                        managedType.ToDisplayString());
                    return;
                }

                if (!ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryType))
                {
                    diagnosticFactory.CreateAndReportDiagnostic(
                        MarshallerEntryPointTypeMustHaveCustomMarshallerAttributeWithMatchingManagedTypeRule,
                        entryType.ToDisplayString(),
                        managedType.ToDisplayString());
                    return;
                }

                bool isLinearCollectionMarshaller = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryType);

                if (entryType.IsUnboundGenericType)
                {
                    if (managedType is not INamedTypeSymbol namedManagedType)
                    {
                        diagnosticFactory.CreateAndReportDiagnostic(
                            GenericEntryPointMarshallerTypeMustBeClosedOrMatchArityRule,
                            entryType.ToDisplayString(),
                            managedType.ToDisplayString());
                        return;
                    }
                    if (!ManualTypeMarshallingHelper.TryResolveEntryPointType(
                            namedManagedType,
                            entryType,
                            isLinearCollectionMarshaller,
                            (managedType, entryType) => diagnosticFactory.CreateAndReportDiagnostic(
                                GenericEntryPointMarshallerTypeMustBeClosedOrMatchArityRule,
                                entryType.ToDisplayString(),
                                managedType.ToDisplayString()),
                            out ITypeSymbol resolvedEntryType))
                    {
                        return;
                    }
                    entryType = (INamedTypeSymbol)resolvedEntryType;
                }

                if (!ManualTypeMarshallingHelper.TryGetMarshallersFromEntryTypeIgnoringElements(
                        entryType,
                        managedType,
                        _compilation,
                        (entryType, managedType) =>
                        diagnosticFactory.CreateAndReportDiagnostic(
                            GenericEntryPointMarshallerTypeMustBeClosedOrMatchArityRule,
                            entryType.ToDisplayString(),
                            managedType.ToDisplayString()), out _))
                {
                    diagnosticFactory.CreateAndReportDiagnostic(
                        MarshallerEntryPointTypeMustHaveCustomMarshallerAttributeWithMatchingManagedTypeRule,
                        entryType.ToDisplayString(),
                        managedType.ToDisplayString());
                }
            }
            private void AnalyzeNativeMarshalerType(SymbolAnalysisContext context, ITypeSymbol type, AttributeData nativeMarshalerAttributeData, bool isNativeMarshallingAttribute)
            {
                if (nativeMarshalerAttributeData.ConstructorArguments.Length == 0)
                {
                    // This is a MarshalUsing with just count information.
                    return;
                }

                if (nativeMarshalerAttributeData.ConstructorArguments[0].IsNull)
                {
                    context.ReportDiagnostic(
                        nativeMarshalerAttributeData.CreateDiagnostic(
                            NativeTypeMustBeNonNullRule,
                            type.ToDisplayString()));
                    return;
                }

                ITypeSymbol nativeType = (ITypeSymbol)nativeMarshalerAttributeData.ConstructorArguments[0].Value !;
                ISymbol     nativeTypeDiagnosticsTargetSymbol = nativeType;

                if (nativeType is not INamedTypeSymbol marshalerType)
                {
                    context.ReportDiagnostic(
                        GetDiagnosticLocations(context, nativeType, nativeMarshalerAttributeData).CreateDiagnostic(
                            NativeTypeMustHaveRequiredShapeRule,
                            nativeType.ToDisplayString(),
                            type.ToDisplayString()));
                    return;
                }

                DiagnosticDescriptor requiredShapeRule = NativeTypeMustHaveRequiredShapeRule;

                ManualTypeMarshallingHelper.NativeTypeMarshallingVariant variant = ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.Standard;
                if (marshalerType.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(_genericContiguousCollectionMarshallerAttribute, a.AttributeClass)))
                {
                    variant           = ManualTypeMarshallingHelper.NativeTypeMarshallingVariant.ContiguousCollection;
                    requiredShapeRule = CollectionNativeTypeMustHaveRequiredShapeRule;
                    if (!ManualTypeMarshallingHelper.TryGetManagedValuesProperty(marshalerType, out _) ||
                        !ManualTypeMarshallingHelper.HasNativeValueStorageProperty(marshalerType, _spanOfByte))
                    {
                        context.ReportDiagnostic(
                            GetDiagnosticLocations(context, marshalerType, nativeMarshalerAttributeData).CreateDiagnostic(
                                requiredShapeRule,
                                nativeType.ToDisplayString(),
                                type.ToDisplayString()));
                        return;
                    }
                }

                if (!nativeType.IsValueType)
                {
                    context.ReportDiagnostic(
                        GetDiagnosticLocations(context, nativeType, nativeMarshalerAttributeData).CreateDiagnostic(
                            requiredShapeRule,
                            nativeType.ToDisplayString(),
                            type.ToDisplayString()));
                    return;
                }

                if (marshalerType.IsUnboundGenericType)
                {
                    if (!isNativeMarshallingAttribute)
                    {
                        context.ReportDiagnostic(
                            nativeMarshalerAttributeData.CreateDiagnostic(
                                NativeGenericTypeMustBeClosedOrMatchArityRule,
                                nativeType.ToDisplayString(),
                                type.ToDisplayString()));
                        return;
                    }
                    if (type is not INamedTypeSymbol namedType || marshalerType.TypeArguments.Length != namedType.TypeArguments.Length)
                    {
                        context.ReportDiagnostic(
                            nativeMarshalerAttributeData.CreateDiagnostic(
                                NativeGenericTypeMustBeClosedOrMatchArityRule,
                                nativeType.ToDisplayString(),
                                type.ToDisplayString()));
                        return;
                    }
                    // Construct the marshaler type around the same type arguments as the managed type.
                    nativeType = marshalerType = marshalerType.ConstructedFrom.Construct(namedType.TypeArguments, namedType.TypeArgumentNullableAnnotations);
                }

                bool hasConstructor = false;
                bool hasCallerAllocSpanConstructor = false;

                foreach (IMethodSymbol ctor in marshalerType.Constructors)
                {
                    if (ctor.IsStatic)
                    {
                        continue;
                    }

                    hasConstructor = hasConstructor || ManualTypeMarshallingHelper.IsManagedToNativeConstructor(ctor, type, variant);

                    if (!hasCallerAllocSpanConstructor && ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfByte, variant))
                    {
                        hasCallerAllocSpanConstructor = true;
                        IFieldSymbol bufferSizeField = nativeType.GetMembers(ManualTypeMarshallingHelper.BufferSizeFieldName).OfType <IFieldSymbol>().FirstOrDefault();
                        if (bufferSizeField is null or {
                            DeclaredAccessibility: not Accessibility.Public
                        } or {
                            IsConst: false
                        } or {
                            Type: not {
                                SpecialType: SpecialType.System_Int32
                            }
                        })
Exemplo n.º 7
0
        private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol
                                                    marshallerType, List <string> missingMemberNames, Compilation compilation, SyntaxGenerator gen)
        {
            INamedTypeSymbol @byte              = compilation.GetSpecialType(SpecialType.System_Byte);
            INamedTypeSymbol @object            = compilation.GetSpecialType(SpecialType.System_Object);
            INamedTypeSymbol spanOfT            = compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata) !;
            INamedTypeSymbol spanOfByte         = spanOfT.Construct(@byte) !;
            INamedTypeSymbol readOnlySpanOfT    = compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata) !;
            INamedTypeSymbol readOnlySpanOfByte = readOnlySpanOfT.Construct(@byte) !;
            INamedTypeSymbol int32              = compilation.GetSpecialType(SpecialType.System_Int32);

            SyntaxNode updatedDeclaration = node;


            (_, ITypeSymbol managedType, _) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(marshallerType);

            IMethodSymbol?fromNativeValueMethod             = ManualTypeMarshallingHelper.FindFromNativeValueMethod(marshallerType);
            IMethodSymbol?toNativeValueMethod               = ManualTypeMarshallingHelper.FindToNativeValueMethod(marshallerType);
            IMethodSymbol?getManagedValuesSourceMethod      = ManualTypeMarshallingHelper.FindGetManagedValuesSourceMethod(marshallerType, readOnlySpanOfT);
            IMethodSymbol?getManagedValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetManagedValuesDestinationMethod(marshallerType, spanOfT);

            SyntaxNode[] throwNotImplementedStatements = new[]
            {
                gen.ThrowStatement(gen.ObjectCreationExpression(gen.DottedName("System.NotImplementedException")))
            };

            foreach (string missingMemberName in missingMemberNames)
            {
                switch (missingMemberName)
                {
                case CustomTypeMarshallerAnalyzer.MissingMemberNames.ValueManagedToNativeConstructor:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration(
                                                            gen.GetName(node),
                                                            new[]
                    {
                        gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case CustomTypeMarshallerAnalyzer.MissingMemberNames.ValueCallerAllocatedBufferConstructor:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration(
                                                            gen.GetName(node),
                                                            new[]
                    {
                        gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)),
                        gen.ParameterDeclaration("buffer", type: gen.TypeExpression(spanOfByte))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionManagedToNativeConstructor:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration(
                                                            gen.GetName(node),
                                                            new[]
                    {
                        gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)),
                        gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionCallerAllocatedBufferConstructor:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration(
                                                            gen.GetName(node),
                                                            new[]
                    {
                        gen.ParameterDeclaration("managed", type: gen.TypeExpression(managedType)),
                        gen.ParameterDeclaration("buffer", type: gen.TypeExpression(spanOfByte)),
                        gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case CustomTypeMarshallerAnalyzer.MissingMemberNames.CollectionNativeElementSizeConstructor:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.ConstructorDeclaration(
                                                            gen.GetName(node),
                                                            new[]
                    {
                        gen.ParameterDeclaration("nativeElementSize", type: gen.TypeExpression(int32))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.Value.ToManaged:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.Value.ToManaged,
                                                            returnType: gen.TypeExpression(managedType),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.Value.FreeNative:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(ShapeMemberNames.Value.FreeNative,
                                                                                                  accessibility: Accessibility.Public,
                                                                                                  statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.Value.FromNativeValue:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.Value.FromNativeValue,
                                                            parameters: new[]
                    {
                        gen.ParameterDeclaration("value",
                                                 type: gen.TypeExpression(toNativeValueMethod?.ReturnType ?? @byte))
                    },
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.Value.ToNativeValue:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.Value.ToNativeValue,
                                                            returnType: gen.TypeExpression(fromNativeValueMethod?.Parameters[0].Type ?? @byte),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.LinearCollection.GetManagedValuesSource:
                    INamedTypeSymbol?getManagedValuesDestinationReturnType = (INamedTypeSymbol?)getManagedValuesDestinationMethod?.ReturnType;
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.LinearCollection.GetManagedValuesSource,
                                                            returnType: gen.TypeExpression(
                                                                readOnlySpanOfT.Construct(
                                                                    getManagedValuesDestinationReturnType?.TypeArguments[0] ?? @object)),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.LinearCollection.GetNativeValuesDestination:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.LinearCollection.GetNativeValuesDestination,
                                                            returnType: gen.TypeExpression(spanOfByte),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.LinearCollection.GetNativeValuesSource:
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.LinearCollection.GetNativeValuesSource,
                                                            parameters: new[]
                    {
                        gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32))
                    },
                                                            returnType: gen.TypeExpression(readOnlySpanOfByte),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                case ShapeMemberNames.LinearCollection.GetManagedValuesDestination:
                    INamedTypeSymbol?getManagedValuesSourceReturnType = (INamedTypeSymbol?)getManagedValuesSourceMethod?.ReturnType;
                    updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(
                                                            ShapeMemberNames.LinearCollection.GetNativeValuesDestination,
                                                            parameters: new[]
                    {
                        gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32))
                    },
                                                            returnType: gen.TypeExpression(
                                                                spanOfT.Construct(
                                                                    getManagedValuesSourceReturnType?.TypeArguments[0] ?? @object)),
                                                            accessibility: Accessibility.Public,
                                                            statements: throwNotImplementedStatements));
                    break;

                default:
                    break;
                }
            }

            return(updatedDeclaration);
        }