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)); }
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()); }
public static CallingConvention GetCallingConvention(this IMethodSymbol iMethodSymbol) { var dllImportData = iMethodSymbol.GetDllImportData(); if (dllImportData != null) { return(dllImportData.CallingConvention); } return(CallingConvention.Cdecl); }
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); }
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 })
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); }
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();
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); }