Exemple #1
0
        public async Task ValidateSnippetsFallbackForwarder(string source, TestTargetFramework targetFramework, bool expectFallbackForwarder)
        {
            Compilation comp = await TestUtils.CreateCompilation(source, targetFramework);

            TestUtils.AssertPreSourceGeneratorCompilation(comp);

            var newComp = TestUtils.RunGenerators(
                comp,
                out var generatorDiags,
                new Microsoft.Interop.LibraryImportGenerator());

            Assert.Empty(generatorDiags);

            TestUtils.AssertPostSourceGeneratorCompilation(newComp);

            // Verify that the forwarder generates the method as a DllImport.
            SyntaxTree    generatedCode = newComp.SyntaxTrees.Last();
            SemanticModel model         = newComp.GetSemanticModel(generatedCode);
            var           methods       = generatedCode.GetRoot()
                                          .DescendantNodes().OfType <MethodDeclarationSyntax>()
                                          .ToList();
            MethodDeclarationSyntax generatedMethod = Assert.Single(methods);

            IMethodSymbol method = model.GetDeclaredSymbol(generatedMethod) !;

            // If we expect fallback forwarder, then the DllImportData will not be null.
            Assert.Equal(expectFallbackForwarder, method.GetDllImportData() is not null);
        }
 private static bool IsHResultOrErrorCodeReturningMethod(IMethodSymbol method)
 {
     // Tune this method to match the FxCop behavior once https://github.com/dotnet/roslyn/issues/7282 is addressed.
     return(method.GetDllImportData() != null &&
            (method.ReturnType.SpecialType == SpecialType.System_Int32 ||
             method.ReturnType.SpecialType == SpecialType.System_UInt32));
 }
Exemple #3
0
        public async Task ValidateSnippetsWithForwarder(string source)
        {
            Compilation comp = await TestUtils.CreateCompilation(source);

            TestUtils.AssertPreSourceGeneratorCompilation(comp);

            var newComp = TestUtils.RunGenerators(
                comp,
                new DllImportGeneratorOptionsProvider(useMarshalType: false, generateForwarders: true),
                out var generatorDiags,
                new Microsoft.Interop.DllImportGenerator());

            Assert.Empty(generatorDiags);

            var newCompDiags = newComp.GetDiagnostics();

            Assert.Empty(newCompDiags);

            // Verify that the forwarder generates the method as a DllImport.
            SyntaxTree    generatedCode = newComp.SyntaxTrees.Last();
            SemanticModel model         = newComp.GetSemanticModel(generatedCode);
            var           methods       = generatedCode.GetRoot()
                                          .DescendantNodes().OfType <MethodDeclarationSyntax>()
                                          .ToList();
            MethodDeclarationSyntax generatedMethod = Assert.Single(methods);

            IMethodSymbol method = model.GetDeclaredSymbol(generatedMethod) !;

            Assert.NotNull(method.GetDllImportData());
        }
        private async Task <Document> ConvertToGeneratedDllImport(
            Document doc,
            MethodDeclarationSyntax methodSyntax,
            IMethodSymbol methodSymbol,
            AttributeData dllImportAttr,
            INamedTypeSymbol generatedDllImportAttrType,
            char?entryPointSuffix,
            CancellationToken cancellationToken)
        {
            DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false);

            SyntaxGenerator generator = editor.Generator;

            var dllImportSyntax = (AttributeSyntax)dllImportAttr !.ApplicationSyntaxReference !.GetSyntax(cancellationToken);

            // Create GeneratedDllImport attribute based on the DllImport attribute
            SyntaxNode generatedDllImportSyntax = GetGeneratedDllImportAttribute(
                editor,
                generator,
                dllImportSyntax,
                methodSymbol.GetDllImportData() !,
                generatedDllImportAttrType,
                methodSymbol.Name,
                entryPointSuffix,
                out SyntaxNode? unmanagedCallConvAttributeMaybe);

            // Add annotation about potential behavioural and compatibility changes
            generatedDllImportSyntax = generatedDllImportSyntax.WithAdditionalAnnotations(
                WarningAnnotation.Create(string.Format(Resources.ConvertToGeneratedDllImportWarning, "[TODO] Documentation link")));

            // Replace DllImport with GeneratedDllImport
            SyntaxNode generatedDeclaration = generator.ReplaceNode(methodSyntax, dllImportSyntax, generatedDllImportSyntax);

            if (!methodSymbol.MethodImplementationFlags.HasFlag(System.Reflection.MethodImplAttributes.PreserveSig))
            {
                generatedDeclaration = await RemoveNoPreserveSigTransform(editor, generatedDeclaration, methodSymbol, cancellationToken).ConfigureAwait(false);
            }

            if (unmanagedCallConvAttributeMaybe is not null)
            {
                generatedDeclaration = generator.AddAttributes(generatedDeclaration, unmanagedCallConvAttributeMaybe);
            }

            // Replace extern keyword with partial keyword
            generatedDeclaration = generator.WithModifiers(
                generatedDeclaration,
                generator.GetModifiers(methodSyntax)
                .WithIsExtern(false)
                .WithPartial(true));

            // Replace the original method with the updated one
            editor.ReplaceNode(methodSyntax, generatedDeclaration);

            return(editor.GetChangedDocument());
        }
Exemple #5
0
        public static CallingConvention GetCallingConvention(this IMethodSymbol iMethodSymbol)
        {
            var dllImportData = iMethodSymbol.GetDllImportData();

            if (dllImportData != null)
            {
                return(dllImportData.CallingConvention);
            }

            return(CallingConvention.Cdecl);
        }
Exemple #6
0
        public static bool IsDllExport(this IMethodSymbol iMethodSymbol)
        {
#if SUPPORT_CUSTOM_EXTERN
            var dllImportData = iMethodSymbol.GetDllImportData();
            if (dllImportData != null && !string.IsNullOrWhiteSpace(dllImportData.ModuleName))
            {
                return(true);
            }
#endif
            return(false);
        }
Exemple #7
0
 private void AnalyzeMethod(Action <Diagnostic> reportDiagnostic, IMethodSymbol symbol)
 {
     // Analyze delegate parameters and return values of P/Invokes.
     if (symbol.GetDllImportData() is not null)
     {
         foreach (var param in symbol.Parameters)
         {
             if (param.Type.TypeKind == TypeKind.Delegate)
             {
                 AnalyzeDelegateMethodSignature((INamedTypeSymbol)param.Type, param);
             }
             else if (param.Type is IArrayTypeSymbol {
                 ElementType.TypeKind: TypeKind.Delegate
             })
Exemple #8
0
        public static bool IsExternDeclaration(this IMethodSymbol iMethodSymbol)
        {
#if SUPPORT_CUSTOM_EXTERN
            var methodSymbol = iMethodSymbol as MethodSymbol;
            if (methodSymbol != null)
            {
                var methodImplAttributes = methodSymbol.ImplementationAttributes & MethodImplAttributes.ManagedMask;
                if (methodImplAttributes.HasFlag(MethodImplAttributes.Unmanaged) &&
                    !methodImplAttributes.HasFlag(MethodImplAttributes.InternalCall))
                {
                    return(true);
                }
            }

            var dllImportData = iMethodSymbol.GetDllImportData();
            if (dllImportData != null && dllImportData.ModuleName == " ")
            {
                return(true);
            }
#endif
            return(false);
        }
Exemple #9
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(
                compilationStartAnalysisContext =>
            {
                Compilation compilation = compilationStartAnalysisContext.Compilation;

                ImmutableHashSet <INamedTypeSymbol> nativeResourceTypes = ImmutableHashSet.Create(
                    WellKnownTypes.IntPtr(compilation),
                    WellKnownTypes.UIntPtr(compilation),
                    WellKnownTypes.HandleRef(compilation)
                    );
                var disposableType = WellKnownTypes.IDisposable(compilation);

                compilationStartAnalysisContext.RegisterOperationAction(
                    operationAnalysisContext =>
                {
                    var assignment = (IAssignmentOperation)operationAnalysisContext.Operation;

                    IOperation target = assignment.Target;
                    if (target == null)
                    {
                        // This can happen if the left-hand side is an undefined symbol.
                        return;
                    }

                    if (target.Kind != OperationKind.FieldReference)
                    {
                        return;
                    }

                    var fieldReference = (IFieldReferenceOperation)target;
                    var field          = fieldReference.Member as IFieldSymbol;
                    if (field == null || field.Kind != SymbolKind.Field || field.IsStatic)
                    {
                        return;
                    }

                    if (!nativeResourceTypes.Contains(field.Type))
                    {
                        return;
                    }

                    INamedTypeSymbol containingType = field.ContainingType;
                    if (containingType == null || containingType.IsValueType)
                    {
                        return;
                    }

                    if (!containingType.AllInterfaces.Contains(disposableType))
                    {
                        return;
                    }

                    if (containingType.HasFinalizer())
                    {
                        return;
                    }

                    if (assignment.Value == null || assignment.Value.Kind != OperationKind.Invocation)
                    {
                        return;
                    }

                    var invocation = (IInvocationOperation)assignment.Value;
                    if (invocation == null)
                    {
                        return;
                    }

                    IMethodSymbol method = invocation.TargetMethod;

                    // TODO: What about COM?
                    if (method.GetDllImportData() == null)
                    {
                        return;
                    }

                    operationAnalysisContext.ReportDiagnostic(containingType.CreateDiagnostic(Rule));
                },
                    OperationKind.SimpleAssignment);
            });
        }
 public DllImportData GetDllImportData()
 {
     return(_symbol.GetDllImportData());
 }
 public DllImportData GetDllImportData()
 => _symbol.GetDllImportData();
Exemple #12
0
        private async Task <Document> ConvertToGeneratedDllImport(
            Document doc,
            MethodDeclarationSyntax methodSyntax,
            IMethodSymbol methodSymbol,
            AttributeData dllImportAttr,
            INamedTypeSymbol generatedDllImportAttrType,
            bool usePreprocessorDefines,
            CancellationToken cancellationToken)
        {
            DocumentEditor editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false);

            SyntaxGenerator generator = editor.Generator;

            var dllImportSyntax = (AttributeSyntax)dllImportAttr !.ApplicationSyntaxReference !.GetSyntax(cancellationToken);

            // Create GeneratedDllImport attribute based on the DllImport attribute
            SyntaxNode generatedDllImportSyntax = GetGeneratedDllImportAttribute(
                editor,
                generator,
                dllImportSyntax,
                methodSymbol.GetDllImportData() !,
                generatedDllImportAttrType,
                out SyntaxNode? unmanagedCallConvAttributeMaybe);

            // Add annotation about potential behavioural and compatibility changes
            generatedDllImportSyntax = generatedDllImportSyntax.WithAdditionalAnnotations(
                WarningAnnotation.Create(string.Format(Resources.ConvertToGeneratedDllImportWarning, "[TODO] Documentation link")));

            // Replace DllImport with GeneratedDllImport
            SyntaxNode generatedDeclaration = generator.ReplaceNode(methodSyntax, dllImportSyntax, generatedDllImportSyntax);

            if (unmanagedCallConvAttributeMaybe is not null)
            {
                generatedDeclaration = generator.AddAttributes(generatedDeclaration, unmanagedCallConvAttributeMaybe);
            }

            // Replace extern keyword with partial keyword
            generatedDeclaration = generator.WithModifiers(
                generatedDeclaration,
                generator.GetModifiers(methodSyntax)
                .WithIsExtern(false)
                .WithPartial(true));

            if (!usePreprocessorDefines)
            {
                // Replace the original method with the updated one
                editor.ReplaceNode(methodSyntax, generatedDeclaration);
            }
            else
            {
                // #if DLLIMPORTGENERATOR_ENABLED
                generatedDeclaration = generatedDeclaration.WithLeadingTrivia(
                    generatedDeclaration.GetLeadingTrivia()
                    .AddRange(new[] {
                    SyntaxFactory.Trivia(SyntaxFactory.IfDirectiveTrivia(SyntaxFactory.IdentifierName("DLLIMPORTGENERATOR_ENABLED"), isActive: true, branchTaken: true, conditionValue: true)),
                    SyntaxFactory.ElasticMarker
                }));

                // #else
                generatedDeclaration = generatedDeclaration.WithTrailingTrivia(
                    generatedDeclaration.GetTrailingTrivia()
                    .AddRange(new[] {
                    SyntaxFactory.Trivia(SyntaxFactory.ElseDirectiveTrivia(isActive: false, branchTaken: false)),
                    SyntaxFactory.ElasticMarker
                }));

                // Remove existing leading trivia - it will be on the GeneratedDllImport method
                MethodDeclarationSyntax updatedDeclaration = methodSyntax.WithLeadingTrivia();

                // #endif
                updatedDeclaration = updatedDeclaration.WithTrailingTrivia(
                    methodSyntax.GetTrailingTrivia()
                    .AddRange(new[] {
                    SyntaxFactory.Trivia(SyntaxFactory.EndIfDirectiveTrivia(isActive: true)),
                    SyntaxFactory.ElasticMarker
                }));

                // Add the GeneratedDllImport method
                editor.InsertBefore(methodSyntax, generatedDeclaration);

                // Replace the original method with the updated DllImport method
                editor.ReplaceNode(methodSyntax, updatedDeclaration);
            }

            return(editor.GetChangedDocument());
        }
 private static bool IsHResultOrErrorCodeReturningMethod(IMethodSymbol method)
 {
     // Tune this method to match the FxCop behavior once https://github.com/dotnet/roslyn/issues/7282 is addressed.
     return method.GetDllImportData() != null &&
         (method.ReturnType.SpecialType == SpecialType.System_Int32 ||
         method.ReturnType.SpecialType == SpecialType.System_UInt32);
 }