private void SetStructLayoutPseudoCustomAttribute(CustomAttributeBuilder customBuilder) { object val = customBuilder.GetConstructorArgument(0); LayoutKind layout; if (val is short) { layout = (LayoutKind)(short)val; } else { layout = (LayoutKind)val; } int?pack = (int?)customBuilder.GetFieldValue("Pack"); int?size = (int?)customBuilder.GetFieldValue("Size"); if (pack.HasValue || size.HasValue) { ClassLayoutTable.Record rec = new ClassLayoutTable.Record(); rec.PackingSize = (short)(pack ?? 0); rec.ClassSize = size ?? 0; rec.Parent = token; this.ModuleBuilder.ClassLayout.AddRecord(rec); } attribs &= ~TypeAttributes.LayoutMask; switch (layout) { case LayoutKind.Auto: attribs |= TypeAttributes.AutoLayout; break; case LayoutKind.Explicit: attribs |= TypeAttributes.ExplicitLayout; break; case LayoutKind.Sequential: attribs |= TypeAttributes.SequentialLayout; break; } CharSet?charSet = customBuilder.GetFieldValue <CharSet>("CharSet"); attribs &= ~TypeAttributes.StringFormatMask; switch (charSet ?? CharSet.None) { case CharSet.None: case CharSet.Ansi: attribs |= TypeAttributes.AnsiClass; break; case CharSet.Auto: attribs |= TypeAttributes.AutoClass; break; case CharSet.Unicode: attribs |= TypeAttributes.UnicodeClass; break; } }
public override void ApplyAttributeBuilder(Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Assembly) { assembly.ApplyAttributeBuilder(a, ctor, cdata, pa); return; } if (a.Type == pa.DefaultCharset) { switch (a.GetCharSetValue()) { case CharSet.Ansi: case CharSet.None: break; case CharSet.Auto: DefaultCharSet = CharSet.Auto; DefaultCharSetType = TypeAttributes.AutoClass; break; case CharSet.Unicode: DefaultCharSet = CharSet.Unicode; DefaultCharSetType = TypeAttributes.UnicodeClass; break; default: Report.Error(1724, a.Location, "Value specified for the argument to `{0}' is not valid", a.GetSignatureForError()); break; } } else if (a.Type == pa.CLSCompliant) { Attribute cls = DeclaringAssembly.CLSCompliantAttribute; if (cls == null) { Report.Warning(3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean()) { Report.SymbolRelatedToPreviousError(cls.Location, cls.GetSignatureForError()); Report.Warning(3017, 1, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly"); return; } } builder.SetCustomAttribute((ConstructorInfo)ctor.GetMetaInfo(), cdata); }
private void SetDllImportPseudoCustomAttribute(CustomAttributeBuilder customBuilder) { CallingConvention?callingConvention = customBuilder.GetFieldValue <CallingConvention>("CallingConvention"); CharSet? charSet = customBuilder.GetFieldValue <CharSet>("CharSet"); SetDllImportPseudoCustomAttribute((string)customBuilder.GetConstructorArgument(0), (string)customBuilder.GetFieldValue("EntryPoint"), callingConvention, charSet, (bool?)customBuilder.GetFieldValue("BestFitMapping"), (bool?)customBuilder.GetFieldValue("ThrowOnUnmappableChar"), (bool?)customBuilder.GetFieldValue("SetLastError"), (bool?)customBuilder.GetFieldValue("PreserveSig"), (bool?)customBuilder.GetFieldValue("ExactSpelling")); }
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Assembly) { assembly.ApplyAttributeBuilder (a, ctor, cdata, pa); return; } if (a.Type == pa.DefaultCharset) { switch (a.GetCharSetValue ()) { case CharSet.Ansi: case CharSet.None: break; case CharSet.Auto: DefaultCharSet = CharSet.Auto; DefaultCharSetType = TypeAttributes.AutoClass; break; case CharSet.Unicode: DefaultCharSet = CharSet.Unicode; DefaultCharSetType = TypeAttributes.UnicodeClass; break; default: Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", a.GetSignatureForError ()); break; } } else if (a.Type == pa.CLSCompliant) { Attribute cls = DeclaringAssembly.CLSCompliantAttribute; if (cls == null) { Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) { Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ()); Report.Warning (3017, 1, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly"); return; } } builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); }
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.IsExternallyVisible()) { context.ReportDiagnostic(context.Symbol.CreateDiagnostic(RuleCA1401, methodSymbol.Name)); } // CA2101 - Specify marshalling for PInvoke string arguments if (dllImportData.BestFitMapping != false || context.Options.GetMSBuildPropertyValue(MSBuildPropertyOptionNames.InvariantGlobalization, context.Compilation) is not "true") { 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)); } } }
internal void SetDllImportPseudoCustomAttribute(string dllName, string entryName, CallingConvention?nativeCallConv, CharSet?nativeCharSet, bool?bestFitMapping, bool?throwOnUnmappableChar, bool?setLastError, bool?preserveSig, bool?exactSpelling) { const short NoMangle = 0x0001; const short CharSetMask = 0x0006; const short CharSetNotSpec = 0x0000; const short CharSetAnsi = 0x0002; const short CharSetUnicode = 0x0004; const short CharSetAuto = 0x0006; const short SupportsLastError = 0x0040; const short CallConvMask = 0x0700; const short CallConvWinapi = 0x0100; const short CallConvCdecl = 0x0200; const short CallConvStdcall = 0x0300; const short CallConvThiscall = 0x0400; const short CallConvFastcall = 0x0500; // non-standard flags const short BestFitOn = 0x0010; const short BestFitOff = 0x0020; const short CharMapErrorOn = 0x1000; const short CharMapErrorOff = 0x2000; short flags = CharSetNotSpec | CallConvWinapi; if (bestFitMapping.HasValue) { flags |= bestFitMapping.Value ? BestFitOn : BestFitOff; } if (throwOnUnmappableChar.HasValue) { flags |= throwOnUnmappableChar.Value ? CharMapErrorOn : CharMapErrorOff; } if (nativeCallConv.HasValue) { flags &= ~CallConvMask; switch (nativeCallConv.Value) { case System.Runtime.InteropServices.CallingConvention.Cdecl: flags |= CallConvCdecl; break; case System.Runtime.InteropServices.CallingConvention.FastCall: flags |= CallConvFastcall; break; case System.Runtime.InteropServices.CallingConvention.StdCall: flags |= CallConvStdcall; break; case System.Runtime.InteropServices.CallingConvention.ThisCall: flags |= CallConvThiscall; break; case System.Runtime.InteropServices.CallingConvention.Winapi: flags |= CallConvWinapi; break; } } if (nativeCharSet.HasValue) { flags &= ~CharSetMask; switch (nativeCharSet.Value) { case CharSet.Ansi: case CharSet.None: flags |= CharSetAnsi; break; case CharSet.Auto: flags |= CharSetAuto; break; case CharSet.Unicode: flags |= CharSetUnicode; break; } } if (exactSpelling.HasValue && exactSpelling.Value) { flags |= NoMangle; } if (!preserveSig.HasValue || preserveSig.Value) { implFlags |= MethodImplAttributes.PreserveSig; } if (setLastError.HasValue && setLastError.Value) { flags |= SupportsLastError; } ImplMapTable.Record rec = new ImplMapTable.Record(); rec.MappingFlags = flags; rec.MemberForwarded = pseudoToken; rec.ImportName = this.ModuleBuilder.Strings.Add(entryName ?? name); rec.ImportScope = this.ModuleBuilder.ModuleRef.FindOrAddRecord(dllName == null ? 0 : this.ModuleBuilder.Strings.Add(dllName)); this.ModuleBuilder.ImplMap.AddRecord(rec); }