From 13965a78f9ae6da0bd5fa74e88d15abcde0ed197 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 28 Jan 2012 21:51:46 +0100 Subject: [PATCH] implement method usage in method bodies --- SharpDevelop.sln | 9 +- .../Analysis/CodeQuality/CodeQuality.csproj | 4 + .../CodeQuality/Engine/AssemblyAnalyzer.cs | 87 ++++++++++++++----- .../CodeQuality/Engine/Dom/AssemblyNode.cs | 25 +++--- .../CodeQuality/Engine/Dom/EventNode.cs | 10 ++- .../CodeQuality/Engine/Dom/FieldNode.cs | 24 ++--- .../CodeQuality/Engine/Dom/MethodNode.cs | 33 ++++--- .../CodeQuality/Engine/Dom/NamespaceNode.cs | 19 ++-- .../CodeQuality/Engine/Dom/PropertyNode.cs | 4 +- .../CodeQuality/Engine/Dom/Relationship.cs | 29 +++++-- .../CodeQuality/Engine/Dom/TypeNode.cs | 28 ++++-- .../Analysis/CodeQuality/Engine/ILAnalyzer.cs | 72 ++++++++++++++- .../Gui/Controls/DependencyMatrix.cs | 2 +- .../CodeQuality/Gui/DependencyMatrixView.xaml | 2 +- .../Gui/DependencyMatrixView.xaml.cs | 33 ++++++- .../CodeQuality/Gui/NodeIconService.cs | 2 +- .../CodeQuality/Utils/DependencyColorizer.cs | 6 +- .../Analysis/CodeQuality/Utils/Extensions.cs | 16 +++- .../Analysis/CodeQuality/Utils/Utils.cs | 20 +++++ 19 files changed, 325 insertions(+), 100 deletions(-) diff --git a/SharpDevelop.sln b/SharpDevelop.sln index 9ba2db847d..d87da710fa 100644 --- a/SharpDevelop.sln +++ b/SharpDevelop.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.2.0.8363-alpha +# SharpDevelop 4.2.0.8380-alpha Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" ProjectSection(SolutionItems) = postProject EndProjectSection @@ -505,10 +505,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceAnalysis", "src\AddIn EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineSpecifications", "src\AddIns\Analysis\MachineSpecifications\MachineSpecifications\MachineSpecifications.csproj", "{D1DA3B8F-7313-4BDA-8880-461C5F007751}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeQuality", "CodeQuality", "{558479FB-A397-4EE9-A1AD-879F80D1FCD0}" - ProjectSection(SolutionItems) = postProject - EndProjectSection -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeQuality", "src\AddIns\Analysis\CodeQuality\CodeQuality.csproj", "{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7}" EndProject Project("{00000000-0000-0000-0000-000000000000}") = "Tools", "src\Tools\Tools.build", "{3DF4060F-5EE0-41CF-8096-F27355FD5511}" @@ -1266,7 +1262,6 @@ Global {08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789} {CE498514-D12D-4B6E-AE0E-FEC29BD43748} = {F355E45F-F54F-4B42-8916-9A633A392789} {D1DA3B8F-7313-4BDA-8880-461C5F007751} = {F355E45F-F54F-4B42-8916-9A633A392789} - {558479FB-A397-4EE9-A1AD-879F80D1FCD0} = {F355E45F-F54F-4B42-8916-9A633A392789} - {3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {558479FB-A397-4EE9-A1AD-879F80D1FCD0} + {3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {F355E45F-F54F-4B42-8916-9A633A392789} EndGlobalSection EndGlobal diff --git a/src/AddIns/Analysis/CodeQuality/CodeQuality.csproj b/src/AddIns/Analysis/CodeQuality/CodeQuality.csproj index 6331b5f74a..2c8ac115de 100644 --- a/src/AddIns/Analysis/CodeQuality/CodeQuality.csproj +++ b/src/AddIns/Analysis/CodeQuality/CodeQuality.csproj @@ -106,6 +106,10 @@ Mono.Cecil False + + {53DCA265-3C3C-42F9-B647-F72BA678122B} + ICSharpCode.NRefactory.CSharp + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} ICSharpCode.NRefactory diff --git a/src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs b/src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs index dd9b40a31b..9b893a3893 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Reflection; using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -18,13 +17,14 @@ namespace ICSharpCode.CodeQuality.Engine /// public class AssemblyAnalyzer { - CecilLoader loader = new CecilLoader(true); + CecilLoader loader = new CecilLoader(true) { IncludeInternalMembers = true }; ICompilation compilation; - Dictionary assemblyMappings; - Dictionary namespaceMappings; - Dictionary typeMappings; - Dictionary methodMappings; - Dictionary fieldMappings; + internal Dictionary assemblyMappings; + internal Dictionary namespaceMappings; + internal Dictionary typeMappings; + internal Dictionary methodMappings; + internal Dictionary fieldMappings; + internal Dictionary cecilMappings; List fileNames; public AssemblyAnalyzer() @@ -45,25 +45,54 @@ namespace ICSharpCode.CodeQuality.Engine assemblyMappings = new Dictionary(); namespaceMappings = new Dictionary(); typeMappings = new Dictionary(); + fieldMappings = new Dictionary(); + methodMappings = new Dictionary(); + cecilMappings = new Dictionary(); foreach (var type in compilation.GetAllTypeDefinitions()) { - AnalyzeType(type); + ReadType(type); + } + foreach (TypeNode type in typeMappings.Values) { + foreach (var field in type.TypeDefinition.Fields) { + var node = new FieldNode(field); + fieldMappings.Add(field, node); + try { + var cecilObj = loader.GetCecilObject((IUnresolvedField)field.UnresolvedMember); + cecilMappings[cecilObj] = field; + } catch (InvalidOperationException) {} + type.Children.Add(node); + } + + foreach (var method in type.TypeDefinition.Methods) { + var node = new MethodNode(method); + methodMappings.Add(method, node); + try { + var cecilObj = loader.GetCecilObject((IUnresolvedMethod)method.UnresolvedMember); + cecilMappings[cecilObj] = method; + } catch (InvalidOperationException) {} + type.Children.Add(node); + } + } + ILAnalyzer analyzer = new ILAnalyzer(loadedAssemblies.Select(asm => loader.GetCecilObject(asm)).ToArray(), this); + foreach (var element in methodMappings) { + int cc; + try { + var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.UnresolvedMember); + analyzer.Analyze(cecilObj.Body, element.Value, out cc); + } catch (InvalidOperationException) {} } return new ReadOnlyCollection(assemblyMappings.Values.ToList()); } IEnumerable LoadAssemblies() { - var resolver = new DefaultAssemblyResolver(); - foreach (var file in fileNames) { - var mainAsm = loader.LoadAssemblyFile(file); - yield return mainAsm; - var referencedAssemblies = loader.GetCecilObject(mainAsm).Modules - .SelectMany(m => m.AssemblyReferences) - .Select(r => resolver.Resolve(r)); - foreach (var asm in referencedAssemblies) - yield return loader.LoadAssembly(asm); - } + var resolver = new AssemblyResolver(); + List assemblies = new List(); + foreach (var file in fileNames.Distinct(StringComparer.OrdinalIgnoreCase)) + assemblies.Add(resolver.LoadAssemblyFile(file)); + foreach (var asm in assemblies.ToArray()) + assemblies.AddRange(asm.Modules.SelectMany(m => m.AssemblyReferences).Select(r => resolver.Resolve(r))); + return assemblies.Distinct().Select(asm => loader.LoadAssembly(asm)); } NamespaceNode GetOrCreateNamespace(AssemblyNode assembly, string namespaceName) @@ -88,13 +117,31 @@ namespace ICSharpCode.CodeQuality.Engine return result; } - void AnalyzeType(ITypeDefinition type) + void ReadType(ITypeDefinition type) { var asm = GetOrCreateAssembly(type.ParentAssembly); var ns = GetOrCreateNamespace(asm, type.Namespace); + TypeNode parent; var node = new TypeNode(type); + if (type.DeclaringTypeDefinition != null) { + if (typeMappings.TryGetValue(type.DeclaringTypeDefinition, out parent)) + parent.Children.Add(node); + else + throw new Exception("TypeNode not found: " + type.DeclaringTypeDefinition.FullName); + } else + ns.Children.Add(node); + cecilMappings[loader.GetCecilObject(type.Parts.First())] = type; typeMappings.Add(type, node); - ns.Children.Add(node); + } + + class AssemblyResolver : DefaultAssemblyResolver + { + public AssemblyDefinition LoadAssemblyFile(string fileName) + { + var assembly = AssemblyDefinition.ReadAssembly(fileName, new ReaderParameters { AssemblyResolver = this }); + RegisterAssembly(assembly); + return assembly; + } } } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs index 68ff36d5dd..f3f8d001f0 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.CodeQuality.Engine.Dom { @@ -27,21 +29,16 @@ namespace ICSharpCode.CodeQuality.Engine.Dom get { return namespaces; } } - public IEnumerable Uses { - get { - throw new NotImplementedException(); - } + public IEnumerable Descendants { + get { return TreeTraversal.PreOrder(Children, node => node.Children); } } - public IEnumerable UsedBy { - get { - throw new NotImplementedException(); - } + public IEnumerable Uses { + get { return Descendants.SelectMany(node => node.Uses); } } - public void CalculateMetricsAndFreeze(IEnumerable assemblies) - { - + public IEnumerable UsedBy { + get { return Descendants.SelectMany(node => node.UsedBy); } } public Relationship GetRelationship(INode value) @@ -49,6 +46,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom Relationship r = new Relationship(); if (value == this) r.AddRelationship(RelationshipType.Same); + if (Uses.Contains(value)) + r.AddRelationship(RelationshipType.Uses); + if (UsedBy.Contains(value)) + r.AddRelationship(RelationshipType.UsedBy); + if (Descendants.Contains(value)) + r.AddRelationship(RelationshipType.Contains); return r; } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs index a9256f36c5..af5ccdfb65 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Linq; + using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.CodeQuality.Engine.Dom @@ -16,9 +18,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom } public IList Children { - get { - throw new NotImplementedException(); - } + get { return null; } } public IEnumerable Uses { @@ -38,6 +38,10 @@ namespace ICSharpCode.CodeQuality.Engine.Dom Relationship r = new Relationship(); if (value == this) r.AddRelationship(RelationshipType.Same); + if (Uses.Contains(value)) + r.AddRelationship(RelationshipType.Uses); + if (UsedBy.Contains(value)) + r.AddRelationship(RelationshipType.UsedBy); return r; } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs index 08e43f0450..800f426c1b 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs @@ -3,34 +3,34 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.CodeQuality.Engine.Dom { public class FieldNode : INode { + public IField FieldDefinition { get; private set; } + + public FieldNode(IField fieldDefinition) + { + this.FieldDefinition = fieldDefinition; + } + public string Name { - get { - throw new NotImplementedException(); - } + get { return FieldDefinition.PrintFullName(); } } public IList Children { - get { - throw new NotImplementedException(); - } + get { return null; } } public IEnumerable Uses { - get { - throw new NotImplementedException(); - } + get { return Enumerable.Empty(); } } public IEnumerable UsedBy { - get { - throw new NotImplementedException(); - } + get { return Enumerable.Empty(); } } public Relationship GetRelationship(INode value) diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs index e729c108e3..bb024ede2b 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs @@ -3,34 +3,39 @@ using System; using System.Collections.Generic; +using System.Linq; + using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.CodeQuality.Engine.Dom { public class MethodNode : INode { + public IMethod MethodDefinition { get; private set; } + + public MethodNode(IMethod methodDefinition) + { + this.MethodDefinition = methodDefinition; + uses = new List(); + usedBy = new List(); + } + public string Name { - get { - throw new NotImplementedException(); - } + get { return MethodDefinition.PrintFullName(); } } public IList Children { - get { - throw new NotImplementedException(); - } + get { return null; } } + internal IList uses, usedBy; + public IEnumerable Uses { - get { - throw new NotImplementedException(); - } + get { return uses; } } public IEnumerable UsedBy { - get { - throw new NotImplementedException(); - } + get { return usedBy; } } public Relationship GetRelationship(INode value) @@ -38,6 +43,10 @@ namespace ICSharpCode.CodeQuality.Engine.Dom Relationship r = new Relationship(); if (value == this) r.AddRelationship(RelationshipType.Same); + if (Uses.Contains(value)) + r.AddRelationship(RelationshipType.Uses); + if (UsedBy.Contains(value)) + r.AddRelationship(RelationshipType.UsedBy); return r; } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs index c8ee0824cc..8a65ef4a23 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.CodeQuality.Engine.Dom { @@ -25,16 +26,16 @@ namespace ICSharpCode.CodeQuality.Engine.Dom get { return types; } } + public IEnumerable Descendants { + get { return TreeTraversal.PreOrder(Children, node => node.Children); } + } + public IEnumerable Uses { - get { - throw new NotImplementedException(); - } + get { return Descendants.SelectMany(node => node.Uses); } } public IEnumerable UsedBy { - get { - throw new NotImplementedException(); - } + get { return Descendants.SelectMany(node => node.UsedBy); } } public Relationship GetRelationship(INode value) @@ -42,6 +43,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom Relationship r = new Relationship(); if (value == this) r.AddRelationship(RelationshipType.Same); + if (Uses.Contains(value)) + r.AddRelationship(RelationshipType.Uses); + if (UsedBy.Contains(value)) + r.AddRelationship(RelationshipType.UsedBy); + if (Descendants.Contains(value)) + r.AddRelationship(RelationshipType.Contains); return r; } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs index 945e230518..8381ec0c95 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs @@ -16,9 +16,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom } public IList Children { - get { - throw new NotImplementedException(); - } + get { return null; } } public IEnumerable Uses { diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs index 33342f5f80..47bf1f8f01 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs @@ -30,7 +30,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom public void AddRelationship(RelationshipType type) { - if (type == RelationshipType.UseThis || type == RelationshipType.UsedBy) + if (type == RelationshipType.Uses || type == RelationshipType.UsedBy) OccurrenceCount++; Relationships.Add(type); @@ -48,13 +48,30 @@ namespace ICSharpCode.CodeQuality.Engine.Dom } } + /// + /// Type of relationship between two INodes. + /// public enum RelationshipType { - OneWayTo, - UseThis, - UsedBy, - Same, + /// + /// a and b are not related to each other. + /// + None, + /// + /// a contains b. + /// Contains, - None + /// + /// a uses b. + /// + Uses, + /// + /// a is used by b. + /// + UsedBy, + /// + /// a and b are the same INode + /// + Same } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs b/src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs index c0e0294c02..12c92fa88e 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs @@ -3,7 +3,10 @@ using System; using System.Collections.Generic; +using System.Linq; + using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.CodeQuality.Engine.Dom { @@ -14,28 +17,29 @@ namespace ICSharpCode.CodeQuality.Engine.Dom public TypeNode(ITypeDefinition typeDefinition) { this.TypeDefinition = typeDefinition; + children = new List(); } public string Name { get { return TypeDefinition.Name; } } + List children; + public IList Children { - get { - return new List(); - } + get { return children; } + } + + public IEnumerable Descendants { + get { return TreeTraversal.PreOrder(Children, node => node.Children); } } public IEnumerable Uses { - get { - throw new NotImplementedException(); - } + get { return Descendants.SelectMany(node => node.Uses); } } public IEnumerable UsedBy { - get { - throw new NotImplementedException(); - } + get { return Descendants.SelectMany(node => node.UsedBy); } } public Relationship GetRelationship(INode value) @@ -43,6 +47,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom Relationship r = new Relationship(); if (value == this) r.AddRelationship(RelationshipType.Same); + if (Uses.Contains(value)) + r.AddRelationship(RelationshipType.Uses); + if (UsedBy.Contains(value)) + r.AddRelationship(RelationshipType.UsedBy); + if (Descendants.Contains(value)) + r.AddRelationship(RelationshipType.Contains); return r; } } diff --git a/src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs b/src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs index 9de0b6fffa..23b832b9d8 100644 --- a/src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs +++ b/src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs @@ -2,6 +2,12 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.CodeQuality.Engine.Dom; +using ICSharpCode.NRefactory.TypeSystem; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace ICSharpCode.CodeQuality.Engine { @@ -10,8 +16,72 @@ namespace ICSharpCode.CodeQuality.Engine /// public class ILAnalyzer { - public ILAnalyzer() + AssemblyDefinition[] assemblies; + AssemblyAnalyzer mappings; + + public ILAnalyzer(AssemblyDefinition[] assemblies, AssemblyAnalyzer mappings) { + if (assemblies == null) + throw new ArgumentNullException("assemblies"); + this.assemblies = assemblies; + this.mappings = mappings; + } + + public void Analyze(MethodBody body, MethodNode analyzedMethod, out int cyclomaticComplexity) + { + cyclomaticComplexity = 0; + + if (body == null) + return; + + foreach (var instruction in body.Instructions) { + // IL cyclomatic complexity + if (instruction.OpCode.FlowControl == FlowControl.Cond_Branch) + cyclomaticComplexity++; + + var operand = ReadOperand(instruction); + + if (operand is MethodDefinition) { + var md = (MethodDefinition)operand; + if (assemblies.Contains(md.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(md)) { + var opMethod = (IMethod)mappings.cecilMappings[md]; + var methodNode = mappings.methodMappings[opMethod]; + analyzedMethod.uses.Add(methodNode); + methodNode.usedBy.Add(analyzedMethod); + } + } +// +// if (operand is MethodDefinition && ((MethodDefinition)operand).DeclaringType.Module.Assembly == assemblyDefinition) { +// var md = (MethodDefinition)operand; +// if (md.DeclaringType.Name == "" || md.DeclaringType.Name.StartsWith("<")) { +// // TODO : Handle generated members +// } else { +// var opMethod = (IMethod)cecilMappings[md]; +// var methodNode = methodMappings[opMethod]; +// m.typeUses.Add(methodNode.DeclaringType); +// m.methodUses.Add(methodNode); +// } +// } +// +// if (operand is FieldDefinition && ((FieldDefinition)operand).DeclaringType.Module.Assembly == assemblyDefinition) { +// var fd = (FieldDefinition)operand; +// if (fd.DeclaringType.Name == "" || fd.DeclaringType.Name.StartsWith("<")) { +// // TODO : Handle generated members +// } else { +// var field = (IField)cecilMappings[fd]; +// var fieldNode = fieldMappings[field]; +// m.fieldUses.Add(fieldNode); +// } +// } + } + } + + public object ReadOperand(Instruction instruction) + { + while (instruction.Operand is Instruction) + instruction = (Instruction)instruction.Operand; + + return instruction.Operand; } } } diff --git a/src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs b/src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs index c0d2941db1..3c57c70d2c 100644 --- a/src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs +++ b/src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs @@ -22,7 +22,7 @@ namespace ICSharpCode.CodeQuality.Gui // add other way foreach (var relationship in fromRelationship.Relationships) { - if (relationship == RelationshipType.UseThis) + if (relationship == RelationshipType.Uses) toRelationship.AddRelationship(RelationshipType.UsedBy); } diff --git a/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml b/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml index 30cfce8ffd..56bb99808f 100644 --- a/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml +++ b/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml @@ -70,7 +70,7 @@ Grid.Row="2" Grid.Column="2" CanContentScroll="True" ScrollChanged="ViewScrollChanged"> - + diff --git a/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs b/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs index 3f447b2132..09e68811c2 100644 --- a/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs +++ b/src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs @@ -15,7 +15,6 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Threading; - using ICSharpCode.CodeQuality; using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.SharpDevelop; @@ -30,6 +29,7 @@ namespace ICSharpCode.CodeQuality.Gui { ScrollViewer topTreeScrollViewer, leftTreeScrollViewer; NodeDescriptionViewModel nodeDescriptionViewModel; + ToolTip infoTooltip; public DependencyMatrixView() { @@ -44,6 +44,7 @@ namespace ICSharpCode.CodeQuality.Gui matrix.Colorizer = new DependencyColorizer(); matrix.ScrollOwner = scrollViewer; + infoTooltip = new ToolTip() { StaysOpen = false }; } @@ -64,6 +65,7 @@ namespace ICSharpCode.CodeQuality.Gui topCol.CollectionChanged += BuildTopINodeList; var matrix = new DependencyMatrix(); + if (nodes != null) AddChildrenToMatrix(matrix, nodes); this.matrix.Matrix = matrix; BuildLeftINodeList(null, null); @@ -76,6 +78,7 @@ namespace ICSharpCode.CodeQuality.Gui foreach (var node in nodes) { matrix.AddColumn(node); matrix.AddRow(node); + if (node.Children != null) AddChildrenToMatrix(matrix, node.Children); } } @@ -145,6 +148,7 @@ namespace ICSharpCode.CodeQuality.Gui matrix.HighlightLine(HeaderType.Rows, n.Node); leftTree.SelectedItem = n; } + infoTooltip.IsOpen = false; } void TopTreeMouseMove(object sender, System.Windows.Input.MouseEventArgs e) @@ -155,6 +159,7 @@ namespace ICSharpCode.CodeQuality.Gui matrix.HighlightLine(HeaderType.Columns, n.Node); topTree.SelectedItem = n; } + infoTooltip.IsOpen = false; } MatrixTreeNode ConvertNode(DependencyObject node) @@ -175,6 +180,32 @@ namespace ICSharpCode.CodeQuality.Gui topTree.SelectedItem = topTree.Items[e.HoveredCell.ColumnIndex + 1]; } } + + void MatrixMouseMove(object sender, MouseEventArgs e) + { + infoTooltip.Placement = PlacementMode.Relative; + infoTooltip.VerticalOffset = 15; + infoTooltip.PlacementTarget = this; + infoTooltip.Content = GetTooltip(matrix.HoveredCell.Value); + infoTooltip.IsOpen = true; + } + + object GetTooltip(Relationship relationship) + { + string text = "is not related to"; + if (relationship.Relationships.Any(r => r == RelationshipType.Uses)) + text = "uses"; + else if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy)) + text = "is used by"; + else if (relationship.Relationships.Any(r => r == RelationshipType.Same)) + text = "is the same as"; + return string.Format("{0} {1} {2}", relationship.From.Name, text, relationship.To.Name); + } + + void MatrixMouseLeave(object sender, MouseEventArgs e) + { + infoTooltip.IsOpen = false; + } #endregion } } \ No newline at end of file diff --git a/src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs b/src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs index a058ffb22b..00e719018b 100644 --- a/src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs +++ b/src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs @@ -15,7 +15,7 @@ namespace ICSharpCode.CodeQuality.Gui public static class NodeIconService { static readonly BitmapSource NamespaceNode = GetImage("Icons.16x16.NameSpace"); - static readonly BitmapSource Assembly = GetImage("Icons.16x16.Assembly"); + static readonly BitmapSource Assembly = GetImage("Icons.16x16.Reference"); static readonly BitmapSource Class = GetImage("Icons.16x16.Class"); static readonly BitmapSource InternalClass = GetImage("Icons.16x16.InternalClass"); diff --git a/src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs b/src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs index d8adc83e5e..ed0b8cb06d 100644 --- a/src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs +++ b/src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs @@ -41,10 +41,10 @@ namespace ICSharpCode.CodeQuality if (relationship == null) return Colors.Transparent; - if (relationship.Relationships.Any(r => r == RelationshipType.UseThis)) - return Colors.LightBlue; + if (relationship.Relationships.Any(r => r == RelationshipType.Uses)) + return Colors.LightGreen; if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy)) - return Colors.Violet; + return Colors.LightBlue; if (relationship.Relationships.Any(r => r == RelationshipType.Same)) return Colors.Gray; diff --git a/src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs b/src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs index a8eec0e71d..5e9c7ec98b 100644 --- a/src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs +++ b/src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs @@ -6,9 +6,10 @@ using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media; - using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.CodeQuality.Gui; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.TreeView; namespace ICSharpCode.CodeQuality @@ -21,7 +22,8 @@ namespace ICSharpCode.CodeQuality public static void FillTree(SharpTreeView tree, IEnumerable rootNodes) { tree.Root = new SharpTreeNode(); - CreateItems(rootNodes, tree.Root); + if (rootNodes != null) + CreateItems(rootNodes, tree.Root); } static void CreateItems(IEnumerable nodes, SharpTreeNode parent) @@ -29,7 +31,8 @@ namespace ICSharpCode.CodeQuality foreach (INode node in nodes) { var item = new MatrixTreeNode(node); parent.Children.Add(item); - CreateItems(node.Children, item); + if (node.Children != null) + CreateItems(node.Children, item); } } @@ -73,5 +76,12 @@ namespace ICSharpCode.CodeQuality (byte)(c1.G * amountFrom + c2.G * percent), (byte)(c1.B * amountFrom + c2.B * percent)); } + + static readonly IAmbience amb = new CSharpAmbience() { ConversionFlags = ConversionFlags.ShowParameterList | ConversionFlags.ShowParameterNames | ConversionFlags.ShowReturnType | ConversionFlags.ShowTypeParameterList }; + + public static string PrintFullName(this IEntity entity) + { + return amb.ConvertEntity(entity); + } } } \ No newline at end of file diff --git a/src/AddIns/Analysis/CodeQuality/Utils/Utils.cs b/src/AddIns/Analysis/CodeQuality/Utils/Utils.cs index 6ac7d8e334..7c1be9d0b8 100644 --- a/src/AddIns/Analysis/CodeQuality/Utils/Utils.cs +++ b/src/AddIns/Analysis/CodeQuality/Utils/Utils.cs @@ -2,8 +2,11 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using System.Runtime.InteropServices; +using Mono.Cecil; + namespace ICSharpCode.CodeQuality { /// @@ -14,4 +17,21 @@ namespace ICSharpCode.CodeQuality [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); } + + public class AssemblyNameReferenceComparer : IEqualityComparer + { + public bool Equals(AssemblyNameReference x, AssemblyNameReference y) + { + if (x == y) return true; + if (x != null && y != null) + return x.FullName == y.FullName; + return false; + } + + public int GetHashCode(AssemblyNameReference obj) + { + if (obj == null) return 0; + return obj.FullName.GetHashCode(); + } + } }