Skip to content

Commit 1c60a5b

Browse files
committed
add IType.FilePath
1 parent 3b400c4 commit 1c60a5b

8 files changed

Lines changed: 99 additions & 37 deletions

File tree

src/NetArchTest.Rules/Assemblies/TypeWrapper.cs renamed to src/NetArchTest.Rules/Assemblies/TypeContainer.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
namespace NetArchTest.Assemblies
77
{
88
[DebuggerDisplay("{FullName}")]
9-
internal sealed class TypeWrapper : IType
9+
internal sealed class TypeContainer : IType
1010
{
1111
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
1212
private readonly TypeDefinition _monoTypeDefinition;
1313
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
14-
private readonly Lazy<Type> _type;
14+
private readonly Lazy<Type> _reflactionType;
15+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
16+
private readonly Lazy<string> _filePath;
17+
1518

16-
internal TypeWrapper(TypeDefinition monoTypeDefinition, string explanation)
19+
internal TypeContainer(TypeDefinition monoTypeDefinition, string explanation)
1720
{
1821
_monoTypeDefinition = monoTypeDefinition;
19-
_type = new Lazy<Type>(() =>
22+
_reflactionType = new Lazy<Type>(() =>
2023
{
2124
try
2225
{
@@ -27,17 +30,19 @@ internal TypeWrapper(TypeDefinition monoTypeDefinition, string explanation)
2730
}
2831
return null;
2932
});
33+
_filePath = new Lazy<string>(() => _monoTypeDefinition.GetFilePath());
3034
Explanation = explanation;
3135
}
3236

3337

34-
public Type ReflectionType => _type.Value;
38+
public Type ReflectionType => _reflactionType.Value;
3539
public string FullName => _monoTypeDefinition.FullName;
3640
public string Name => _monoTypeDefinition.Name;
3741
public string Explanation { get; }
42+
public string FilePath => _filePath.Value;
3843

3944

40-
public static implicit operator System.Type(TypeWrapper type)
45+
public static implicit operator System.Type(TypeContainer type)
4146
{
4247
return type.ReflectionType;
4348
}

src/NetArchTest.Rules/Assemblies/TypeSource.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,28 @@
33
using System.Linq;
44
using System.Reflection;
55
using Mono.Cecil;
6+
using Mono.Cecil.Cil;
67
using NetArchTest.Dependencies.DataStructures;
78

89
namespace NetArchTest.Assemblies
910
{
1011
internal sealed class TypeSource
1112
{
12-
private static readonly List<string> exclusionList = new List<string>{ "System", "Microsoft", "Mono.Cecil", "netstandard", "NetArchTest.Rules", "<Module>", "xunit", "<PrivateImplementationDetails>" };
13+
private static readonly List<string> exclusionList = new List<string>{ "System", "Microsoft", "Mono.Cecil", "netstandard", "NetArchTest.Rules", "<Module>", "xunit", "NuGet" , "<PrivateImplementationDetails>" };
1314
private static readonly NamespaceTree exclusionTree = new NamespaceTree(exclusionList);
1415

1516

1617

1718
public static IEnumerable<TypeSpec> FromAssemblies(IEnumerable<Assembly> assemblies, IEnumerable<string> searchDirectories = null)
1819
{
1920
foreach (var assembly in assemblies)
20-
{
21-
if (exclusionTree.GetAllMatchingNames(assembly.FullName).Any() || assembly.IsDynamic)
21+
{
22+
if (exclusionTree.GetAllMatchingNames(assembly.GetName().Name).Any() || assembly.IsDynamic)
2223
{
2324
continue;
2425
}
2526

26-
foreach (var type in ReadTypes(assembly.Location))
27+
foreach (var type in ReadTypes(assembly.Location, searchDirectories: searchDirectories))
2728
{
2829
yield return type;
2930
}
@@ -33,16 +34,16 @@ public static IEnumerable<TypeSpec> FromFiles(IEnumerable<string> fileNames, IEn
3334
{
3435
foreach (var fileName in fileNames)
3536
{
36-
foreach (var type in ReadTypes(fileName))
37+
foreach (var type in ReadTypes(fileName, searchDirectories: searchDirectories))
3738
{
3839
yield return type;
3940
}
4041
}
4142
}
4243

43-
private static IEnumerable<TypeSpec> ReadTypes(string assemblyLocation, IEnumerable<string> searchDirectories = null)
44+
private static IEnumerable<TypeSpec> ReadTypes(string assemblyLocation, bool readSymbols = true, IEnumerable<string> searchDirectories = null)
4445
{
45-
ReaderParameters readerParameters = null;
46+
ReaderParameters readerParameters = new ReaderParameters { ReadSymbols = readSymbols, SymbolReaderProvider = new DefaultSymbolReaderProvider(false) };
4647

4748
if (searchDirectories?.Any() == true)
4849
{
@@ -52,7 +53,7 @@ private static IEnumerable<TypeSpec> ReadTypes(string assemblyLocation, IEnumera
5253
assemblyResolver.AddSearchDirectory(searchDirectory);
5354
}
5455

55-
readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver };
56+
readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = readSymbols, SymbolReaderProvider = new DefaultSymbolReaderProvider(false) };
5657
}
5758

5859
var assemblyDefinition = ReadAssemblyDefinition(assemblyLocation, readerParameters);
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
1-
using System.Diagnostics;
1+
using System;
2+
using System.Diagnostics;
23
using Mono.Cecil;
34

45
namespace NetArchTest.Assemblies
56
{
67
[DebuggerDisplay("TypeSpec: {FullName}")]
78
internal sealed class TypeSpec
89
{
10+
private readonly Lazy<string> _filePath;
11+
912
public TypeDefinition Definition { get; }
1013
public string FullName => Definition.FullName;
1114
// Only for use by FunctionSequence
1215
internal bool IsSelectedInMarkPhase { get; set; }
1316
// Can be use by any function
1417
internal bool IsPassing { get; set; }
1518
public string Explanation { get; set; }
19+
public string FilePath => _filePath.Value;
1620

1721

1822
public TypeSpec(TypeDefinition definition)
1923
{
2024
Definition = definition;
25+
_filePath = new Lazy<string>(() => Definition.GetFilePath());
2126
}
2227

2328

2429

25-
public TypeWrapper CreateWrapper()
30+
public TypeContainer CreateWrapper()
2631
{
27-
return new TypeWrapper(Definition, Explanation);
32+
return new TypeContainer(Definition, Explanation);
2833
}
2934
}
3035
}

src/NetArchTest.Rules/Condition_Names.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public ConditionList NotBeOfType(params Type[] type)
2828
/// <summary>
2929
/// Selects types that have a specific name.
3030
/// </summary>
31-
/// <param name="name">The name of the class to match against.</param>
31+
/// <remarks>
32+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
33+
/// </remarks>
3234
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
3335
public ConditionList HaveName(string name)
3436
{
@@ -39,7 +41,9 @@ public ConditionList HaveName(string name)
3941
/// <summary>
4042
/// Selects types that do not have a particular name.
4143
/// </summary>
42-
/// <param name="name">The name of the class to match against.</param>
44+
/// <remarks>
45+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
46+
/// </remarks>
4347
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
4448
public ConditionList NotHaveName(string name)
4549
{
@@ -72,7 +76,9 @@ public ConditionList NotHaveNameMatching(string pattern)
7276
/// <summary>
7377
/// Selects types whose names start with the specified text.
7478
/// </summary>
75-
/// <param name="start">The text to match against.</param>
79+
/// <remarks>
80+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
81+
/// </remarks>
7682
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
7783
public ConditionList HaveNameStartingWith(string start)
7884
{
@@ -83,18 +89,22 @@ public ConditionList HaveNameStartingWith(string start)
8389
/// <summary>
8490
/// Selects types whose names do not start with the specified text.
8591
/// </summary>
86-
/// <param name="start">The text to match against.</param>
92+
/// <remarks>
93+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
94+
/// </remarks>
8795
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
8896
public ConditionList NotHaveNameStartingWith(string start)
8997
{
9098
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNameStartingWith(context, inputTypes, new[] { start }, false));
9199
return CreateConditionList();
92-
}
100+
}
93101

94102
/// <summary>
95103
/// Selects types whose names do not end with the specified text.
96104
/// </summary>
97-
/// <param name="end">The text to match against.</param>
105+
/// <remarks>
106+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
107+
/// </remarks>
98108
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
99109
public ConditionList HaveNameEndingWith(string end)
100110
{
@@ -105,7 +115,9 @@ public ConditionList HaveNameEndingWith(string end)
105115
/// <summary>
106116
/// Selects types whose names do not end with the specified text.
107117
/// </summary>
108-
/// <param name="end">The text to match against.</param>
118+
/// <remarks>
119+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing
120+
/// </remarks>
109121
/// <returns>An updated set of conditions that can be applied to a list of types.</returns>
110122
public ConditionList NotHaveNameEndingWith(string end)
111123
{

src/NetArchTest.Rules/Extensions/Mono.Cecil/TypeDefinitionExtensions.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2-
using System.Linq;
32
using System.Collections.Generic;
3+
using System.Linq;
44
using System.Runtime.CompilerServices;
55

66
namespace Mono.Cecil
@@ -170,5 +170,25 @@ public static bool IsStruct(this TypeDefinition typeDefinition)
170170
{
171171
return typeDefinition.IsValueType && typeDefinition.BaseType?.FullName == "System.ValueType";
172172
}
173+
174+
175+
176+
public static string GetFilePath(this TypeDefinition typeDefinition)
177+
{
178+
if (typeDefinition.HasMethods)
179+
{
180+
foreach (var method in typeDefinition.Methods)
181+
{
182+
if (method.DebugInformation.HasSequencePoints)
183+
{
184+
foreach (var s in method.DebugInformation.SequencePoints)
185+
{
186+
return s.Document.Url;
187+
}
188+
}
189+
}
190+
}
191+
return null;
192+
}
173193
}
174-
}
194+
}

src/NetArchTest.Rules/IType.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,14 @@ public interface IType
2929
/// It contains explanation why this Type has failed dependecy search.
3030
/// </summary>
3131
string Explanation { get; }
32+
33+
34+
/// <summary>
35+
/// Path to the source file where type is defined.
36+
/// </summary>
37+
/// <remarks>
38+
/// This property may be null if assembly debug symbols (PDB) were not loaded correctly or given type does not have any instructions inside.
39+
/// </remarks>
40+
string FilePath { get; }
3241
}
3342
}

src/NetArchTest.Rules/Predicate_Names.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public PredicateList AreNotOfType(params Type[] type)
2828
/// <summary>
2929
/// Selects types that have a specific name.
3030
/// </summary>
31-
/// <param name="name">The name of the class to match against.</param>
31+
/// <remarks>
32+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
33+
/// </remarks>
3234
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
3335
public PredicateList HaveName(params string[] name)
3436
{
@@ -39,7 +41,9 @@ public PredicateList HaveName(params string[] name)
3941
/// <summary>
4042
/// Selects types that do not have a particular name.
4143
/// </summary>
42-
/// <param name="name">The name of the class to match against.</param>
44+
/// <remarks>
45+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
46+
/// </remarks>
4347
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
4448
public PredicateList DoNotHaveName(params string[] name)
4549
{
@@ -72,40 +76,48 @@ public PredicateList DoNotHaveNameMatching(string pattern)
7276
/// <summary>
7377
/// Selects types whose names start with the specified text.
7478
/// </summary>
75-
/// <param name="start">The text to match against.</param>
79+
/// <remarks>
80+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
81+
/// </remarks>
7682
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
7783
public PredicateList HaveNameStartingWith(params string[] start)
7884
{
7985
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNameStartingWith(context, inputTypes, start, true));
8086
return CreatePredicateList();
81-
}
87+
}
8288

8389
/// <summary>
8490
/// Selects types whose names do not start with the specified text.
8591
/// </summary>
86-
/// <param name="start">The text to match against.</param>
92+
/// <remarks>
93+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
94+
/// </remarks>
8795
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
8896
public PredicateList DoNotHaveNameStartingWith(params string[] start)
8997
{
9098
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNameStartingWith(context, inputTypes, start, false));
9199
return CreatePredicateList();
92-
}
100+
}
93101

94102
/// <summary>
95103
/// Selects types whose names end with the specified text.
96104
/// </summary>
97-
/// <param name="end">The text to match against.</param>
105+
/// <remarks>
106+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
107+
/// </remarks>
98108
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
99109
public PredicateList HaveNameEndingWith(params string[] end)
100110
{
101111
AddFunctionCall((context, inputTypes) => FunctionDelegates.HaveNameEndingWith(context, inputTypes, end, true));
102112
return CreatePredicateList();
103-
}
113+
}
104114

105115
/// <summary>
106116
/// Selects types whose names do not end with the specified text.
107117
/// </summary>
108-
/// <param name="end">The text to match against.</param>
118+
/// <remarks>
119+
/// StringComparison.InvariantCultureIgnoreCase is used for comparing, can be changed through Options
120+
/// </remarks>
109121
/// <returns>An updated set of predicates that can be applied to a list of types.</returns>
110122
public PredicateList DoNotHaveNameEndingWith(params string[] end)
111123
{

src/NetArchTest.Rules/RuleEngine/FunctionSequenceExecutionContext.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ namespace NetArchTest.RuleEngine
44
{
55
internal class FunctionSequenceExecutionContext
66
{
7-
public static readonly FunctionSequenceExecutionContext Default = new FunctionSequenceExecutionContext(false);
8-
97
public bool IsFailPathRun { get; }
108
public IDependencyFilter DependencyFilter { get; }
119
public Options UserOptions { get; }

0 commit comments

Comments
 (0)