private AttributeListSyntax BuildUnmanagedFunctionPointerAttribute(DllImportData dllImportData) { var charset = string.Format("CharSet = CharSet.{0}", dllImportData.CharacterSet); var charsetArgument = Syntax.AttributeArgument(Syntax.ParseExpression(charset)); var setLastError = string.Format("SetLastError = {0}", dllImportData.SetLastError.ToProperString()); var setLastErrorArgument = Syntax.AttributeArgument(Syntax.ParseExpression(setLastError)); var callingConvention = string.Format("CallingConvention.{0}", dllImportData.CallingConvention); var callingConventionArgument = Syntax.AttributeArgument(Syntax.ParseExpression(callingConvention)); var arguments = Syntax.SeparatedList(callingConventionArgument).Add(setLastErrorArgument, charsetArgument); if (dllImportData.BestFitMapping.HasValue) { var bestFitMapping = string.Format("BestFitMapping = {0}", dllImportData.BestFitMapping.ToProperString()); var bestFitMappingArgument = Syntax.AttributeArgument(Syntax.ParseExpression(bestFitMapping)); arguments = arguments.Add(bestFitMappingArgument); } if (dllImportData.ThrowOnUnmappableCharacter.HasValue) { var throwOnUnmappableCharacter = string.Format("ThrowOnUnmappableChar = {0}", dllImportData.ThrowOnUnmappableCharacter.ToProperString()); var throwOnUnmappableCharacterArgument = Syntax.AttributeArgument(Syntax.ParseExpression(throwOnUnmappableCharacter)); arguments = arguments.Add(throwOnUnmappableCharacterArgument); } var unmanagedFunctionPointerAttribute = Syntax.Attribute(Syntax.ParseName("UnmanagedFunctionPointer")) .WithArgumentList(Syntax.AttributeArgumentList(arguments)); return Syntax.AttributeList(Syntax.SeparatedList(unmanagedFunctionPointerAttribute)); }
public void AnalyzeSymbol(SymbolAnalysisContext context) { var methodSymbol = (IMethodSymbol)context.Symbol; if (methodSymbol == null) { return; } DllImportData dllImportData = methodSymbol.GetDllImportData(); if (dllImportData == null) { return; } AttributeData dllAttribute = methodSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(_dllImportType)); Location defaultLocation = dllAttribute == null?methodSymbol.Locations.FirstOrDefault() : GetAttributeLocation(dllAttribute); // CA1401 - PInvoke methods should not be visible if (methodSymbol.GetResultantVisibility() == SymbolVisibility.Public) { context.ReportDiagnostic(context.Symbol.CreateDiagnostic(RuleCA1401, methodSymbol.Name)); } // CA2101 - Specify marshalling for PInvoke string arguments if (dllImportData.BestFitMapping != false) { bool appliedCA2101ToMethod = false; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { if (parameter.Type.SpecialType == SpecialType.System_String || parameter.Type.Equals(_stringBuilderType)) { AttributeData marshalAsAttribute = parameter.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Equals(_marshalAsType)); CharSet? charSet = marshalAsAttribute == null ? dllImportData.CharacterSet : MarshalingToCharSet(GetParameterMarshaling(marshalAsAttribute)); // only unicode marshaling is considered safe if (charSet != CharSet.Unicode) { if (marshalAsAttribute != null) { // track the diagnostic on the [MarshalAs] attribute Location marshalAsLocation = GetAttributeLocation(marshalAsAttribute); context.ReportDiagnostic(Diagnostic.Create(RuleCA2101, marshalAsLocation)); } else if (!appliedCA2101ToMethod) { // track the diagnostic on the [DllImport] attribute appliedCA2101ToMethod = true; context.ReportDiagnostic(Diagnostic.Create(RuleCA2101, defaultLocation)); } } } } // only unicode marshaling is considered safe, but only check this if we haven't already flagged the attribute if (!appliedCA2101ToMethod && dllImportData.CharacterSet != CharSet.Unicode && (methodSymbol.ReturnType.SpecialType == SpecialType.System_String || methodSymbol.ReturnType.Equals(_stringBuilderType))) { context.ReportDiagnostic(Diagnostic.Create(RuleCA2101, defaultLocation)); } } }