Skip to content

Commit 89c1409

Browse files
authored
Add processing of exclude type attribute (#179)
***NO_CI***
1 parent 4df9a34 commit 89c1409

File tree

12 files changed

+226
-38
lines changed

12 files changed

+226
-38
lines changed

MetadataProcessor.Console/Program.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
namespace nanoFramework.Tools.MetadataProcessor.Console
1818
{
1919
internal static class MainClass
20-
{
20+
{
2121
private sealed class MetadataProcessor
2222
{
2323
private readonly IDictionary<string, string> _loadHints =
@@ -40,10 +40,10 @@ public void Parse(string fileName)
4040
{
4141
try
4242
{
43-
if(Verbose) System.Console.WriteLine("Parsing assembly...");
43+
if (Verbose) System.Console.WriteLine("Parsing assembly...");
4444

4545
_assemblyDefinition = AssemblyDefinition.ReadAssembly(fileName,
46-
new ReaderParameters { AssemblyResolver = new LoadHintsAssemblyResolver(_loadHints)});
46+
new ReaderParameters { AssemblyResolver = new LoadHintsAssemblyResolver(_loadHints) });
4747
}
4848
catch (Exception)
4949
{
@@ -98,7 +98,7 @@ public void Compile(
9898
_assemblyBuilder.Write(writer);
9999
}
100100

101-
if(DumpMetadata)
101+
if (DumpMetadata)
102102
{
103103
nanoDumperGenerator dumper = new nanoDumperGenerator(
104104
_assemblyBuilder.TablesContext,
@@ -187,7 +187,7 @@ public void GenerateDependency(string fileName)
187187
}
188188

189189
public static void Main(string[] args)
190-
{
190+
{
191191
FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
192192

193193
bool isCoreLibrary = false;
@@ -206,9 +206,9 @@ public static void Main(string[] args)
206206
{
207207
var arg = args[i].ToLower(CultureInfo.InvariantCulture);
208208

209-
if ( (arg == "-h" ||
209+
if ((arg == "-h" ||
210210
arg == "-help" ||
211-
arg == "?") &&
211+
arg == "?") &&
212212
(i + 1 < args.Length))
213213
{
214214
System.Console.WriteLine("");
@@ -244,6 +244,10 @@ public static void Main(string[] args)
244244
}
245245
else if (arg == "-excludeclassbyname" && i + 1 < args.Length)
246246
{
247+
System.Console.WriteLine("*********************************************** WARNING *************************************************");
248+
System.Console.WriteLine("Use ExcludeTypeAttribute instead of passing this option. This will be removed in a future version of MDP.");
249+
System.Console.WriteLine("*********************************************************************************************************");
250+
247251
md.AddClassToExclude(args[++i]);
248252
}
249253
else if (arg == "-verbose")
@@ -296,6 +300,6 @@ public static void Main(string[] args)
296300
System.Console.Error.WriteLine("Unknown command line option '{0}' ignored.", arg);
297301
}
298302
}
299-
}
303+
}
300304
}
301305
}

MetadataProcessor.MsBuildTask/MetaDataProcessorTask.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class MetaDataProcessorTask : Task
3737

3838
public string LoadStrings { get; set; }
3939

40+
[Obsolete("Use ExcludeTypeAttribute instead of passing this parameter. This will be removed in a future version of MDP.")]
4041
public ITaskItem[] ExcludeClassByName { get; set; }
4142

4243
public ITaskItem[] ImportResources { get; set; }
@@ -154,13 +155,16 @@ public override bool Execute()
154155
if (ExcludeClassByName != null &&
155156
ExcludeClassByName.Any())
156157
{
157-
if (Verbose) Log.LogCommandLine(MessageImportance.Normal, "Processing class exclusion list..");
158+
if (Verbose) Log.LogCommandLine(MessageImportance.Normal, "Processing class exclusion list.");
158159

159-
foreach (var className in ExcludeClassByName)
160+
foreach (ITaskItem className in ExcludeClassByName)
160161
{
161162
_classNamesToExclude.Add(className.ToString());
162163

163-
if (Verbose) Log.LogCommandLine(MessageImportance.Normal, $"Adding '{className.ToString()}' to collection of classes to exclude");
164+
if (Verbose)
165+
{
166+
Log.LogCommandLine(MessageImportance.Normal, $"Adding '{className.ToString()}' to collection of classes to exclude");
167+
}
164168
}
165169
}
166170

MetadataProcessor.Shared/Tables/nanoTablesContext.cs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
// See LICENSE file in the project root for full license information.
55
//
66

7-
using Mono.Cecil;
87
using System;
98
using System.Collections.Generic;
109
using System.Linq;
10+
using Mono.Cecil;
1111

1212
namespace nanoFramework.Tools.MetadataProcessor
1313
{
@@ -24,18 +24,21 @@ public sealed class nanoTablesContext
2424
"System.Runtime.InteropServices.GuidAttribute",
2525

2626
// Compiler-specific attributes
27-
//"System.ParamArrayAttribute",
28-
//"System.SerializableAttribute",
29-
//"System.NonSerializedAttribute",
30-
//"System.Runtime.InteropServices.StructLayoutAttribute",
31-
//"System.Runtime.InteropServices.LayoutKind",
32-
//"System.Runtime.InteropServices.OutAttribute",
33-
//"System.Runtime.CompilerServices.ExtensionAttribute",
34-
//"System.Runtime.CompilerServices.MethodImplAttribute",
35-
//"System.Runtime.CompilerServices.InternalsVisibleToAttribute",
36-
//"System.Runtime.CompilerServices.IndexerNameAttribute",
37-
//"System.Runtime.CompilerServices.MethodImplOptions",
38-
//"System.Reflection.FieldNoReflectionAttribute",
27+
"System.ParamArrayAttribute",
28+
"System.SerializableAttribute",
29+
"System.NonSerializedAttribute",
30+
"System.Runtime.InteropServices.StructLayoutAttribute",
31+
"System.Runtime.InteropServices.LayoutKind",
32+
"System.Runtime.InteropServices.OutAttribute",
33+
"System.Runtime.CompilerServices.ExtensionAttribute",
34+
"System.Runtime.CompilerServices.MethodImplAttribute",
35+
"System.Runtime.CompilerServices.NullableAttribute",
36+
"System.Runtime.CompilerServices.NullableContextAttribute",
37+
"System.Runtime.CompilerServices.InternalsVisibleToAttribute",
38+
"System.Runtime.CompilerServices.IndexerNameAttribute",
39+
"System.Runtime.CompilerServices.MethodImplOptions",
40+
"System.Runtime.CompilerServices.RefSafetyRulesAttribute",
41+
"System.Reflection.FieldNoReflectionAttribute",
3942

4043
// Debugger-specific attributes
4144
"System.Diagnostics.DebuggableAttribute",
@@ -56,7 +59,7 @@ public sealed class nanoTablesContext
5659
// Intellisense filtering attributes
5760
"System.ComponentModel.EditorBrowsableAttribute",
5861

59-
//Not supported
62+
// Not supported
6063
"System.Reflection.DefaultMemberAttribute",
6164

6265
// Not supported attributes
@@ -79,8 +82,11 @@ public nanoTablesContext(
7982
_verbose = verbose;
8083
_isCoreLibrary = isCoreLibrary;
8184

85+
// add default types to exclude
86+
SetDefaultTypesToExclude();
87+
8288
// check CustomAttributes against list of classes to exclude
83-
foreach (var item in assemblyDefinition.CustomAttributes)
89+
foreach (CustomAttribute item in assemblyDefinition.CustomAttributes)
8490
{
8591
// add it to ignore list, if it's not already there
8692
if ((ClassNamesToExclude.Contains(item.AttributeType.FullName) ||
@@ -93,7 +99,7 @@ public nanoTablesContext(
9399
}
94100

95101
// check ignoring attributes against ClassNamesToExclude
96-
foreach (var className in ClassNamesToExclude)
102+
foreach (string className in ClassNamesToExclude)
97103
{
98104
if (!IgnoringAttributes.Contains(className))
99105
{
@@ -133,10 +139,13 @@ public nanoTablesContext(
133139

134140
// Internal types definitions
135141

136-
var types = GetOrderedTypes(mainModule, explicitTypesOrder);
142+
List<TypeDefinition> types = GetOrderedTypes(mainModule, explicitTypesOrder);
137143

138144
TypeDefinitionTable = new nanoTypeDefinitionTable(types, this);
139145

146+
// get types to exclude from the types attributes
147+
ProcessTypesToExclude(types);
148+
140149
var fields = types
141150
.SelectMany(item => GetOrderedFields(item.Fields.Where(field => !field.HasConstant)))
142151
.ToList();
@@ -459,5 +468,29 @@ internal void ResetResourcesTables()
459468
ResourceDataTable = new nanoResourceDataTable();
460469
ResourceFileTable = new nanoResourceFileTable(this);
461470
}
471+
472+
private static void ProcessTypesToExclude(List<TypeDefinition> types)
473+
{
474+
// loop through all types and find out which ones have the ExcludeTypeAttribute, so they are added to the exclusion lis
475+
foreach (TypeDefinition type in types)
476+
{
477+
if (type.HasCustomAttributes)
478+
{
479+
CustomAttribute excludeTypeAttribute = type.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExcludeTypeAttribute");
480+
if (excludeTypeAttribute != null)
481+
{
482+
ClassNamesToExclude.Add(type.FullName);
483+
}
484+
}
485+
}
486+
}
487+
488+
private void SetDefaultTypesToExclude()
489+
{
490+
ClassNamesToExclude.Add("ThisAssembly");
491+
ClassNamesToExclude.Add("System.Runtime.CompilerServices.RefSafetyRulesAttribute");
492+
ClassNamesToExclude.Add("System.Runtime.CompilerServices.AccessedThroughPropertyAttribute");
493+
}
494+
462495
}
463496
}

MetadataProcessor.Shared/nanoDumperGenerator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ private void DumpCustomAttributes(DumpAllTable dumpTable)
9191
TypeToken = fa.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("x8")
9292
};
9393

94-
if (fa.CustomAttributes[0].HasConstructorArguments)
94+
if (!nanoTablesContext.IgnoringAttributes.Contains(fa.CustomAttributes[0].AttributeType.FullName)
95+
&& fa.CustomAttributes[0].HasConstructorArguments)
9596
{
96-
foreach (var value in fa.CustomAttributes[0].ConstructorArguments)
97+
foreach (CustomAttributeArgument value in fa.CustomAttributes[0].ConstructorArguments)
9798
{
9899
attribute.FixedArgs.AddRange(BuildFixedArgsAttribute(value));
99100
}

MetadataProcessor.Shared/nanoSkeletonGenerator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Copyright (c) .NET Foundation and Contributors
33
// See LICENSE file in the project root for full license information.
44
//
@@ -90,7 +90,8 @@ private void GenerateStubs()
9090
foreach (var c in _tablesContext.TypeDefinitionTable.TypeDefinitions)
9191
{
9292
if (c.IncludeInStub() &&
93-
!c.IsToExclude())
93+
!c.IsToExclude() &&
94+
!nanoTablesContext.IgnoringAttributes.Contains(c.FullName))
9495
{
9596
var className = NativeMethodsCrc.GetClassName(c);
9697

MetadataProcessor.Tests/Core/ClrIntegrationTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,10 @@ private string ComposeLocalClrInstancePath()
330330
{
331331
StringBuilder arguments = new StringBuilder(" --localinstance");
332332

333-
//#if DEBUG
334-
// arguments.Append($" \"{_localClrInstancePath}\"");
333+
#if DEBUG
334+
arguments.Append($" \"{_localClrInstancePath}\"");
335335

336-
//#else
336+
#else
337337
if (string.IsNullOrEmpty(TestObjectHelper.NanoClrLocalInstance))
338338
{
339339
return null;
@@ -342,7 +342,7 @@ private string ComposeLocalClrInstancePath()
342342
{
343343
arguments.Append($" \"{TestObjectHelper.NanoClrLocalInstance}\"");
344344
}
345-
//#endif
345+
#endif
346346

347347
return arguments.ToString();
348348
}

MetadataProcessor.Tests/Core/Extensions/TypeDefinitionExtensionsTests.cs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
using System.Linq;
88
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
99
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using Mono.Cecil;
11+
using System.IO;
12+
using System.Collections.Generic;
1013

1114
namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Extensions
1215
{
@@ -58,7 +61,6 @@ public void IncludeInStubTest()
5861
public void IsClassToExcludeTest()
5962
{
6063
var nanoTablesContext = TestObjectHelper.GetTestNFAppNanoTablesContext();
61-
Assert.IsFalse(nanoTablesContext.ClassNamesToExclude.Any());
6264

6365
var oneClassOverAllTypeDefinition = TestObjectHelper.GetTestNFAppOneClassOverAllTypeDefinition(nanoTablesContext.AssemblyDefinition);
6466
var oneClassOverAllSubClassTypeDefinition = TestObjectHelper.GetTestNFAppOneClassOverAllSubClassTypeDefinition(nanoTablesContext.AssemblyDefinition);
@@ -92,5 +94,81 @@ public void IsClassToExcludeTest()
9294

9395
Assert.IsTrue(r);
9496
}
97+
98+
[TestMethod]
99+
public void TypesInLibraryToExcludeTests()
100+
{
101+
// Arrange
102+
string libLocation = Path.Combine(
103+
TestObjectHelper.TestExecutionLocation,
104+
"TestNFClassLibrary");
105+
106+
string libAssemblyLocation = Path.Combine(
107+
libLocation,
108+
"TestNFClassLibrary.dll");
109+
110+
AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(libAssemblyLocation);
111+
112+
nanoTablesContext nanoTablesContext = new nanoTablesContext(
113+
assemblyDefinition,
114+
null,
115+
// adding this here, equivalent to the NFMDP_PE_ExcludeClassByName project property
116+
new List<string>() { "TestNFClassLibrary.IAmATypeToExclude" },
117+
null,
118+
false,
119+
false,
120+
false);
121+
122+
ModuleDefinition testNFLibraryModule = nanoTablesContext.AssemblyDefinition.Modules[0];
123+
124+
// Assert
125+
126+
// test if <TestNFClassLibrary.ClassOnAnotherAssembly> type is present
127+
Assert.IsNotNull(testNFLibraryModule.Types.FirstOrDefault(i => i.FullName == "TestNFClassLibrary.ClassOnAnotherAssembly"), "TestNFClassLibrary.ClassOnAnotherAssembly type not found");
128+
129+
// test if <TestNFClassLibrary.IAmATypeToExclude> type is present
130+
Assert.IsNotNull(testNFLibraryModule.Types.FirstOrDefault(i => i.FullName == "TestNFClassLibrary.IAmATypeToExclude"), "TestNFClassLibrary.IAmATypeToExclude type not found");
131+
132+
// test if <TestNFClassLibrary.IAmATypeToExclude> type is to be excluded
133+
// this is being excluded with the NFMDP_PE_ExcludeClassByName project property
134+
Assert.IsTrue(testNFLibraryModule.Types.First(i => i.FullName == "TestNFClassLibrary.IAmATypeToExclude").IsToExclude(), "TestNFClassLibrary.IAmATypeToExclude type is not listed to be excluded, when it should");
135+
136+
// test if <TestNFClassLibrary.IAmAlsoATypeToExclude> type is present
137+
Assert.IsNotNull(testNFLibraryModule.Types.FirstOrDefault(i => i.FullName == "TestNFClassLibrary.IAmAlsoATypeToExclude"), "TestNFClassLibrary.IAmAlsoATypeToExclude type not found");
138+
139+
// test if <TestNFClassLibrary.IAmAlsoATypeToExclude> type is to be excluded
140+
// this is being excluded with the ExcludeType attribute
141+
Assert.IsTrue(testNFLibraryModule.Types.First(i => i.FullName == "TestNFClassLibrary.IAmAlsoATypeToExclude").IsToExclude(), "TestNFClassLibrary.IAmAlsoATypeToExclude type is not listed to be excluded, when it should");
142+
143+
// test if <TestNFClassLibrary.IAmAnEnumToExclude> type is present
144+
Assert.IsNotNull(testNFLibraryModule.Types.FirstOrDefault(i => i.FullName == "TestNFClassLibrary.IAmAnEnumToExclude"), "TestNFClassLibrary.IAmAnEnumToExclude type not found");
145+
146+
// test if <TestNFClassLibrary.IAmAnEnumToExclude> type is to be excluded
147+
// this is being excluded with the ExcludeType attribute
148+
Assert.IsTrue(testNFLibraryModule.Types.First(i => i.FullName == "TestNFClassLibrary.IAmAnEnumToExclude").IsToExclude(), "TestNFClassLibrary.IAmAnEnumToExclude type is not listed to be excluded, when it should");
149+
}
150+
151+
[TestMethod]
152+
public void DefaultTypesToExcludeTests()
153+
{
154+
// Arrange
155+
AssemblyDefinition mscorlibAssemblyDefinition = AssemblyDefinition.ReadAssembly(TestObjectHelper.MscorlibFullPath);
156+
157+
nanoTablesContext context = new nanoTablesContext(
158+
mscorlibAssemblyDefinition,
159+
null,
160+
new List<string>(),
161+
null,
162+
false,
163+
false,
164+
true);
165+
166+
ModuleDefinition mscorlibModule = context.AssemblyDefinition.Modules[0];
167+
168+
// Assert
169+
Assert.IsNotNull(context);
170+
171+
Assert.IsTrue(mscorlibModule.Types.First(i => i.FullName == "ThisAssembly").IsToExclude(), "ThisAssembly type is not listed to be excluded, when it should");
172+
}
95173
}
96174
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace TestNFClassLibrary
7+
{
8+
// this type does nothing, its here to test the backwards compatibility with NFMDP_PE_ExcludeClassByName project property to exclude types
9+
public class IAmATypeToExclude
10+
{
11+
}
12+
}

0 commit comments

Comments
 (0)