private void BuildNode(List <TreeViewItem> items, CallTreeNode callTree, int depth) { var id = items.Count; items.Add(new TreeViewItem { id = id, depth = depth, displayName = callTree.GetPrettyName(true) }); m_CallTreeDictionary.Add(id, callTree); // if the tree is too deep, serialization will exceed the 7 levels limit. if (callTree.children == null) { items.Add(new TreeViewItem { id = id + 1, depth = depth + 1, displayName = "<Serialization Limit>" }); } else { foreach (var parent in callTree.children) { BuildNode(items, parent, depth + 1); } } }
private void BuildHierarchy(CallTreeNode callee, int depth) { if (depth++ == m_MaxDepth) { return; } // let's find all callers with matching callee if (m_BucketedCallPairs.ContainsKey(callee.name)) { var callPairs = m_BucketedCallPairs[callee.name]; foreach (var call in callPairs) { // ignore recursive calls if (!call.caller.FullName.Equals(callee.name)) { var callerInstance = new CallTreeNode(call.caller); callerInstance.location = call.location; BuildHierarchy(callerInstance, depth); callee.children.Add(callerInstance); } } } }
public ProjectIssue(ProblemDescriptor descriptor, string description, IssueCategory category, CallTreeNode dependenciesNode) : this(descriptor, description, category) { dependencies = dependenciesNode; }
public ProjectIssue(ProblemDescriptor descriptor, string description, IssueCategory category, CallTreeNode dependenciesNode) { this.descriptor = descriptor; this.description = description; this.category = category; dependencies = dependenciesNode; }
protected override void DoubleClickedItem(int id) { if (m_CallTreeDictionary.ContainsKey(id)) { CallTreeNode node = m_CallTreeDictionary[id]; if (node.location != null) { node.location.Open(); } } }
public CallTreeNode(string _name, CallTreeNode caller = null) { name = _name; typeName = string.Empty; methodName = string.Empty; if (caller != null) { children.Add(caller); } }
public ProjectIssue Analyze(MethodDefinition methodDefinition, Instruction inst) { var type = (TypeReference)inst.Operand; if (type.IsGenericParameter) { bool isValueType = true; // assume it's value type var genericType = (GenericParameter)type; if (genericType.HasReferenceTypeConstraint) { isValueType = false; } else { foreach (var constraint in genericType.Constraints) { if (!constraint.IsValueType) { isValueType = false; } } } if (!isValueType) { // boxing on ref types are no-ops, so not a problem return(null); } } string typeName = type.Name; if (type.FullName.Equals("System.Single")) { typeName = "float"; } else if (type.FullName.Equals("System.Double")) { typeName = "double"; } var description = string.Format("Conversion from value type '{0}' to ref type", typeName); var calleeNode = new CallTreeNode(descriptor.description); return(new ProjectIssue ( descriptor, description, IssueCategory.ApiCalls, calleeNode )); }
private void AnalyzeMethodBody(ProjectReport projectReport, AssemblyDefinition a, MethodDefinition caller, CallCrawler callCrawler) { if (!caller.DebugInformation.HasSequencePoints) { return; } var callerNode = new CallTreeNode(caller); foreach (var inst in caller.Body.Instructions.Where(i => m_OpCodes.Contains(i.OpCode))) { //var msg = string.Empty; SequencePoint s = null; for (var i = inst; i != null; i = i.Previous) { s = caller.DebugInformation.GetSequencePoint(i); if (s != null) { // msg = i == inst ? " exactly" : "nearby"; break; } } var location = callerNode.location = new Location { path = s.Document.Url.Replace("\\", "/"), line = s.StartLine }; if (inst.OpCode == OpCodes.Call || inst.OpCode == OpCodes.Callvirt) { callCrawler.Add(caller, (MethodReference)inst.Operand, location); } foreach (var analyzer in m_InstructionAnalyzers) { if (analyzer.GetOpCodes().Contains(inst.OpCode)) { var projectIssue = analyzer.Analyze(caller, inst); if (projectIssue != null) { projectIssue.callTree.AddChild(callerNode); projectIssue.location = location; projectIssue.assembly = a.Name.Name; projectReport.AddIssue(projectIssue); } } } } }
public CallTreeNode(MethodReference methodReference, CallTreeNode caller = null) { name = methodReference.FullName; methodName = "(anonymous)"; // default value // check if it's a coroutine if (methodReference.DeclaringType.FullName.IndexOf("/<") >= 0) { var fullName = methodReference.DeclaringType.FullName; var methodStartIndex = fullName.IndexOf("<") + 1; if (methodStartIndex > 0) { var length = fullName.IndexOf(">") - methodStartIndex; typeName = fullName.Substring(0, fullName.IndexOf("/")); if (length > 0) { methodName = fullName.Substring(methodStartIndex, length); } else { // handle example: System.Int32 DelegateTest/<>c::<Update>b__1_0() methodStartIndex = name.LastIndexOf("<") + 1; if (methodStartIndex > 0) { length = name.LastIndexOf(">") - methodStartIndex; methodName = name.Substring(methodStartIndex, length) + ".(anonymous)"; } } } else { // for some reason, some generated types don't have the same syntax typeName = fullName; } } else { typeName = methodReference.DeclaringType.Name; methodName = methodReference.Name; } if (caller != null) { children.Add(caller); } }
private void DrawCallHierarchy(CallTreeNode callTree) { EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.Width(LayoutSize.FoldoutWidth), GUILayout.MinHeight(LayoutSize.FoldoutMinHeight * 2)); m_ShowCallTree = BoldFoldout(m_ShowCallTree, Styles.CallTreeFoldout); if (m_ShowCallTree) { if (callTree != null) { Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(400)); m_CallHierarchyView.OnGUI(r); } else { EditorGUILayout.LabelField(NoIssueSelectedText); } } EditorGUILayout.EndVertical(); }
public ProjectIssue Analyze(MethodDefinition methodDefinition, Instruction inst) { var callee = ((MethodReference)inst.Operand); // replace root with callee node var calleeNode = new CallTreeNode(callee); var description = string.Empty; var descriptor = m_Descriptors.SingleOrDefault(c => c.type == callee.DeclaringType.FullName && (c.method == callee.Name || ("get_" + c.method) == callee.Name)); if (descriptor != null) { // by default use descriptor issue description description = descriptor.description; } else { // Are we trying to warn about a whole namespace? descriptor = m_Descriptors.SingleOrDefault(c => c.type == callee.DeclaringType.Namespace && c.method == "*"); if (descriptor == null) { // no issue found return(null); } // use callee name since it's more informative description = calleeNode.prettyName; } return(new ProjectIssue ( descriptor, description, IssueCategory.ApiCalls, calleeNode )); }
private void DrawFoldouts() { ProblemDescriptor problemDescriptor = null; var selectedItems = m_ActiveIssueTable.GetSelectedItems(); var selectedDescriptors = selectedItems.Select(i => i.ProblemDescriptor); var selectedIssues = selectedItems.Select(i => i.ProjectIssue); // find out if all descriptors are the same var firstDescriptor = selectedDescriptors.FirstOrDefault(); if (selectedDescriptors.Count() == selectedDescriptors.Count(d => d.id == firstDescriptor.id)) { problemDescriptor = firstDescriptor; } DrawDetailsFoldout(problemDescriptor); DrawRecommendationFoldout(problemDescriptor); if (m_ActiveAnalysisView.desc.showInvertedCallTree) { CallTreeNode callTree = null; if (selectedIssues.Count() == 1) { var issue = selectedIssues.First(); if (issue != null) { // get caller sub-tree callTree = issue.callTree.GetChild(); } } if (m_CurrentCallTree != callTree) { m_CallHierarchyView.SetCallTree(callTree); m_CallHierarchyView.Reload(); m_CurrentCallTree = callTree; } DrawCallHierarchy(callTree); } }
public void AddChild(CallTreeNode child) { children.Add(child); }
public void SetCallTree(CallTreeNode callTree) { m_CallTree = callTree; }