|
|
@ -22,7 +22,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public class AssemblyAnalyzer |
|
|
|
public class AssemblyAnalyzer |
|
|
|
{ |
|
|
|
{ |
|
|
|
CecilLoader loader = new CecilLoader(true) { IncludeInternalMembers = true }; |
|
|
|
Dictionary<object, object> unresolvedTypeSystemToCecilDict = new Dictionary<object, object>(); |
|
|
|
ICompilation compilation; |
|
|
|
ICompilation compilation; |
|
|
|
internal Dictionary<IAssembly, AssemblyNode> assemblyMappings; |
|
|
|
internal Dictionary<IAssembly, AssemblyNode> assemblyMappings; |
|
|
|
internal Dictionary<string, NamespaceNode> namespaceMappings; |
|
|
|
internal Dictionary<string, NamespaceNode> namespaceMappings; |
|
|
@ -73,7 +73,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
|
|
|
|
|
|
|
|
public ReadOnlyCollection<AssemblyNode> Analyze() |
|
|
|
public ReadOnlyCollection<AssemblyNode> Analyze() |
|
|
|
{ |
|
|
|
{ |
|
|
|
IUnresolvedAssembly[] loadedAssemblies = LoadAssemblies().ToArray(); |
|
|
|
var loadedAssemblies = LoadAssemblies(); |
|
|
|
compilation = new SimpleCompilation(loadedAssemblies.First(), loadedAssemblies.Skip(1)); |
|
|
|
compilation = new SimpleCompilation(loadedAssemblies.First(), loadedAssemblies.Skip(1)); |
|
|
|
|
|
|
|
|
|
|
|
assemblyMappings = new Dictionary<IAssembly, AssemblyNode>(); |
|
|
|
assemblyMappings = new Dictionary<IAssembly, AssemblyNode>(); |
|
|
@ -92,7 +92,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
foreach (var field in type.Fields) { |
|
|
|
foreach (var field in type.Fields) { |
|
|
|
var node = new FieldNode(field); |
|
|
|
var node = new FieldNode(field); |
|
|
|
fieldMappings.Add(field, node); |
|
|
|
fieldMappings.Add(field, node); |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedField)field.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedField)field.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
cecilMappings[cecilObj] = field; |
|
|
|
cecilMappings[cecilObj] = field; |
|
|
|
tn.AddChild(node); |
|
|
|
tn.AddChild(node); |
|
|
@ -101,7 +101,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
foreach (var method in type.Methods) { |
|
|
|
foreach (var method in type.Methods) { |
|
|
|
var node = new MethodNode(method); |
|
|
|
var node = new MethodNode(method); |
|
|
|
methodMappings.Add(method, node); |
|
|
|
methodMappings.Add(method, node); |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)method.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)method.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
cecilMappings[cecilObj] = method; |
|
|
|
cecilMappings[cecilObj] = method; |
|
|
|
tn.AddChild(node); |
|
|
|
tn.AddChild(node); |
|
|
@ -110,16 +110,16 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
foreach (var property in type.Properties) { |
|
|
|
foreach (var property in type.Properties) { |
|
|
|
var node = new PropertyNode(property); |
|
|
|
var node = new PropertyNode(property); |
|
|
|
propertyMappings.Add(property, node); |
|
|
|
propertyMappings.Add(property, node); |
|
|
|
var cecilPropObj = loader.GetCecilObject((IUnresolvedProperty)property.UnresolvedMember); |
|
|
|
var cecilPropObj = GetCecilObject((IUnresolvedProperty)property.UnresolvedMember); |
|
|
|
if (cecilPropObj != null) |
|
|
|
if (cecilPropObj != null) |
|
|
|
cecilMappings[cecilPropObj] = property; |
|
|
|
cecilMappings[cecilPropObj] = property; |
|
|
|
if (property.CanGet) { |
|
|
|
if (property.CanGet) { |
|
|
|
var cecilMethodObj = loader.GetCecilObject((IUnresolvedMethod)property.Getter.UnresolvedMember); |
|
|
|
var cecilMethodObj = GetCecilObject((IUnresolvedMethod)property.Getter.UnresolvedMember); |
|
|
|
if (cecilMethodObj != null) |
|
|
|
if (cecilMethodObj != null) |
|
|
|
cecilMappings[cecilMethodObj] = property; |
|
|
|
cecilMappings[cecilMethodObj] = property; |
|
|
|
} |
|
|
|
} |
|
|
|
if (property.CanSet) { |
|
|
|
if (property.CanSet) { |
|
|
|
var cecilMethodObj = loader.GetCecilObject((IUnresolvedMethod)property.Setter.UnresolvedMember); |
|
|
|
var cecilMethodObj = GetCecilObject((IUnresolvedMethod)property.Setter.UnresolvedMember); |
|
|
|
if (cecilMethodObj != null) |
|
|
|
if (cecilMethodObj != null) |
|
|
|
cecilMappings[cecilMethodObj] = property; |
|
|
|
cecilMappings[cecilMethodObj] = property; |
|
|
|
} |
|
|
|
} |
|
|
@ -129,21 +129,21 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
foreach (var @event in type.Events) { |
|
|
|
foreach (var @event in type.Events) { |
|
|
|
var node = new EventNode(@event); |
|
|
|
var node = new EventNode(@event); |
|
|
|
eventMappings.Add(@event, node); |
|
|
|
eventMappings.Add(@event, node); |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedEvent)@event.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedEvent)@event.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
cecilMappings[cecilObj] = @event; |
|
|
|
cecilMappings[cecilObj] = @event; |
|
|
|
if (@event.CanAdd) { |
|
|
|
if (@event.CanAdd) { |
|
|
|
var cecilMethodObj = loader.GetCecilObject((IUnresolvedMethod)@event.AddAccessor.UnresolvedMember); |
|
|
|
var cecilMethodObj = GetCecilObject((IUnresolvedMethod)@event.AddAccessor.UnresolvedMember); |
|
|
|
if (cecilMethodObj != null) |
|
|
|
if (cecilMethodObj != null) |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
} |
|
|
|
} |
|
|
|
if (@event.CanInvoke) { |
|
|
|
if (@event.CanInvoke) { |
|
|
|
var cecilMethodObj = loader.GetCecilObject((IUnresolvedMethod)@event.InvokeAccessor.UnresolvedMember); |
|
|
|
var cecilMethodObj = GetCecilObject((IUnresolvedMethod)@event.InvokeAccessor.UnresolvedMember); |
|
|
|
if (cecilMethodObj != null) |
|
|
|
if (cecilMethodObj != null) |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
} |
|
|
|
} |
|
|
|
if (@event.CanRemove) { |
|
|
|
if (@event.CanRemove) { |
|
|
|
var cecilMethodObj = loader.GetCecilObject((IUnresolvedMethod)@event.RemoveAccessor.UnresolvedMember); |
|
|
|
var cecilMethodObj = GetCecilObject((IUnresolvedMethod)@event.RemoveAccessor.UnresolvedMember); |
|
|
|
if (cecilMethodObj != null) |
|
|
|
if (cecilMethodObj != null) |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
cecilMappings[cecilMethodObj] = @event; |
|
|
|
} |
|
|
|
} |
|
|
@ -151,7 +151,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ILAnalyzer analyzer = new ILAnalyzer(loadedAssemblies.Select(asm => loader.GetCecilObject(asm)).ToArray(), this); |
|
|
|
ILAnalyzer analyzer = new ILAnalyzer(loadedAssemblies.Select(asm => GetCecilObject(asm)).ToArray(), this); |
|
|
|
int count = typeMappings.Count + methodMappings.Count + fieldMappings.Count + propertyMappings.Count; |
|
|
|
int count = typeMappings.Count + methodMappings.Count + fieldMappings.Count + propertyMappings.Count; |
|
|
|
int i = 0; |
|
|
|
int i = 0; |
|
|
|
|
|
|
|
|
|
|
@ -164,7 +164,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
|
|
|
|
|
|
|
|
foreach (var element in methodMappings) { |
|
|
|
foreach (var element in methodMappings) { |
|
|
|
ReportProgress(++i / (double)count); |
|
|
|
ReportProgress(++i / (double)count); |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)element.Key.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, element.Value); |
|
|
|
analyzer.Analyze(cecilObj.Body, element.Value); |
|
|
|
var node = element.Value; |
|
|
|
var node = element.Value; |
|
|
@ -194,12 +194,12 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
var node = element.Value; |
|
|
|
var node = element.Value; |
|
|
|
var property = element.Key; |
|
|
|
var property = element.Key; |
|
|
|
if (property.CanGet) { |
|
|
|
if (property.CanGet) { |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.Getter.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)element.Key.Getter.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
} |
|
|
|
} |
|
|
|
if (property.CanSet) { |
|
|
|
if (property.CanSet) { |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.Setter.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)element.Key.Setter.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
} |
|
|
|
} |
|
|
@ -213,17 +213,17 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
var node = element.Value; |
|
|
|
var node = element.Value; |
|
|
|
var @event = element.Key; |
|
|
|
var @event = element.Key; |
|
|
|
if (@event.CanAdd) { |
|
|
|
if (@event.CanAdd) { |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)@event.AddAccessor.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)@event.AddAccessor.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
} |
|
|
|
} |
|
|
|
if (@event.CanInvoke) { |
|
|
|
if (@event.CanInvoke) { |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)@event.InvokeAccessor.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)@event.InvokeAccessor.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
} |
|
|
|
} |
|
|
|
if (@event.CanRemove) { |
|
|
|
if (@event.CanRemove) { |
|
|
|
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)@event.RemoveAccessor.UnresolvedMember); |
|
|
|
var cecilObj = GetCecilObject((IUnresolvedMethod)@event.RemoveAccessor.UnresolvedMember); |
|
|
|
if (cecilObj != null) |
|
|
|
if (cecilObj != null) |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
analyzer.Analyze(cecilObj.Body, node); |
|
|
|
} |
|
|
|
} |
|
|
@ -295,7 +295,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
IEnumerable<IUnresolvedAssembly> LoadAssemblies() |
|
|
|
IList<IUnresolvedAssembly> LoadAssemblies() |
|
|
|
{ |
|
|
|
{ |
|
|
|
var resolver = new AssemblyResolver(); |
|
|
|
var resolver = new AssemblyResolver(); |
|
|
|
foreach (var path in fileNames.Select(f => Path.GetDirectoryName(f)).Distinct(StringComparer.OrdinalIgnoreCase)) |
|
|
|
foreach (var path in fileNames.Select(f => Path.GetDirectoryName(f)).Distinct(StringComparer.OrdinalIgnoreCase)) |
|
|
@ -305,13 +305,54 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
assemblies.Add(resolver.LoadAssemblyFile(file)); |
|
|
|
assemblies.Add(resolver.LoadAssemblyFile(file)); |
|
|
|
foreach (var asm in assemblies.ToArray()) |
|
|
|
foreach (var asm in assemblies.ToArray()) |
|
|
|
assemblies.AddRange(asm.Modules.SelectMany(m => m.AssemblyReferences).Select(r => resolver.TryResolve(r)).Where(r => r != null)); |
|
|
|
assemblies.AddRange(asm.Modules.SelectMany(m => m.AssemblyReferences).Select(r => resolver.TryResolve(r)).Where(r => r != null)); |
|
|
|
return assemblies.Distinct().Select(asm => loader.LoadAssembly(asm)); |
|
|
|
CecilLoader loader = new CecilLoader { IncludeInternalMembers = true }; |
|
|
|
|
|
|
|
// Emulate the old CecilLoader.GetCecilObject() API:
|
|
|
|
|
|
|
|
loader.OnEntityLoaded = delegate(IUnresolvedEntity entity, MemberReference cecilObj) { |
|
|
|
|
|
|
|
unresolvedTypeSystemToCecilDict[entity] = cecilObj; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
var loadedAssemblies = new List<IUnresolvedAssembly>(); |
|
|
|
|
|
|
|
foreach (var asm in assemblies.Distinct()) { |
|
|
|
|
|
|
|
var loadedAssembly = loader.LoadAssembly(asm); |
|
|
|
|
|
|
|
loadedAssemblies.Add(loadedAssembly); |
|
|
|
|
|
|
|
unresolvedTypeSystemToCecilDict[loadedAssembly] = asm; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return loadedAssemblies; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AssemblyDefinition GetCecilObject(IUnresolvedAssembly assembly) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
object cecilObj; |
|
|
|
|
|
|
|
if (unresolvedTypeSystemToCecilDict.TryGetValue(assembly, out cecilObj)) { |
|
|
|
|
|
|
|
return cecilObj as AssemblyDefinition; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MemberReference GetCecilObject(IUnresolvedEntity entity) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
object cecilObj; |
|
|
|
|
|
|
|
if (unresolvedTypeSystemToCecilDict.TryGetValue(entity, out cecilObj)) { |
|
|
|
|
|
|
|
return cecilObj as MemberReference; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MethodDefinition GetCecilObject(IUnresolvedMethod method) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
object cecilObj; |
|
|
|
|
|
|
|
if (unresolvedTypeSystemToCecilDict.TryGetValue(method, out cecilObj)) { |
|
|
|
|
|
|
|
return cecilObj as MethodDefinition; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
NamespaceNode GetOrCreateNamespace(AssemblyNode assembly, string namespaceName) |
|
|
|
NamespaceNode GetOrCreateNamespace(AssemblyNode assembly, string namespaceName) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NamespaceNode result; |
|
|
|
NamespaceNode result; |
|
|
|
var asmDef = loader.GetCecilObject(assembly.AssemblyInfo.UnresolvedAssembly); |
|
|
|
var asmDef = GetCecilObject(assembly.AssemblyInfo.UnresolvedAssembly); |
|
|
|
if (!namespaceMappings.TryGetValue(namespaceName + "," + asmDef.FullName, out result)) { |
|
|
|
if (!namespaceMappings.TryGetValue(namespaceName + "," + asmDef.FullName, out result)) { |
|
|
|
result = new NamespaceNode(namespaceName); |
|
|
|
result = new NamespaceNode(namespaceName); |
|
|
|
assembly.AddChild(result); |
|
|
|
assembly.AddChild(result); |
|
|
@ -343,7 +384,7 @@ namespace ICSharpCode.CodeQuality.Engine |
|
|
|
throw new Exception("TypeNode not found: " + type.DeclaringTypeDefinition.FullName); |
|
|
|
throw new Exception("TypeNode not found: " + type.DeclaringTypeDefinition.FullName); |
|
|
|
} else |
|
|
|
} else |
|
|
|
ns.AddChild(node); |
|
|
|
ns.AddChild(node); |
|
|
|
cecilMappings[loader.GetCecilObject(type.Parts.First())] = type; |
|
|
|
cecilMappings[GetCecilObject(type.Parts.First())] = type; |
|
|
|
typeMappings.Add(type, node); |
|
|
|
typeMappings.Add(type, node); |
|
|
|
return node; |
|
|
|
return node; |
|
|
|
} |
|
|
|
} |
|
|
|