public void Audit(ProjectReport projectReport) { var progressBar = new ProgressBarDisplay("Analyzing Scripts", "Analyzing project scripts", m_PlayerAssemblies.Length); var assemblies = GetPlayerAssemblies(); if (assemblies.Count > 0) { // Analyse all Player assemblies, including Package assemblies. foreach (var assemblyPath in assemblies) { progressBar.AdvanceProgressBar(); if (!File.Exists(assemblyPath)) { Debug.LogError(assemblyPath + " not found."); return; } AnalyzeAssembly(assemblyPath, projectReport); } } progressBar.ClearProgressBar(); }
public void Audit(ProjectReport projectReport, IProgressBar progressBar = null) { var userAssemblies = GetPlayerAssemblies(); if (userAssemblies.Count > 0) { m_AssemblyResolver = new DefaultAssemblyResolver(); #if UNITY_2019_1_OR_NEWER List <string> assemblyPaths = new List <string>(); assemblyPaths.AddRange(CompilationPipeline.GetPrecompiledAssemblyPaths(CompilationPipeline.PrecompiledAssemblySources .UserAssembly)); assemblyPaths.AddRange(CompilationPipeline.GetPrecompiledAssemblyPaths(CompilationPipeline.PrecompiledAssemblySources .UnityEngine)); foreach (var dir in assemblyPaths.Select(path => Path.GetDirectoryName(path)).Distinct()) { m_AssemblyResolver.AddSearchDirectory(dir); } #else m_AssemblyResolver.AddSearchDirectory(Path.Combine(EditorApplication.applicationContentsPath, "Managed", "UnityEngine")); #endif m_AssemblyResolver.AddSearchDirectory(Path.Combine(EditorApplication.applicationContentsPath, "UnityExtensions", "Unity", "GUISystem")); foreach (var dir in userAssemblies.Select(path => Path.GetDirectoryName(path)).Distinct()) { m_AssemblyResolver.AddSearchDirectory(dir); } var callCrawler = new CallCrawler(); if (progressBar != null) { progressBar.Initialize("Analyzing Scripts", "Analyzing project scripts", m_PlayerAssemblies.Length); } // Analyse all Player assemblies, including Package assemblies. foreach (var assemblyPath in userAssemblies) { if (progressBar != null) { progressBar.AdvanceProgressBar(string.Format("Analyzing {0} scripts", Path.GetFileName(assemblyPath))); } if (!File.Exists(assemblyPath)) { Debug.LogError(assemblyPath + " not found."); continue; } AnalyzeAssembly(assemblyPath, projectReport, callCrawler); } if (progressBar != null) { progressBar.ClearProgressBar(); } callCrawler.BuildCallHierarchies(projectReport, progressBar); } }
private void Analyze() { m_ProjectReport = new ProjectReport(); m_ProjectAuditor.Audit(m_ProjectReport); RefreshDisplay(); }
public void Audit(ProjectReport projectReport, IProgressBar progressBar = null) { if (!AssemblyHelper.CompileAssemblies()) { return; } var callCrawler = new CallCrawler(); using (var assemblyResolver = new DefaultAssemblyResolver()) { var compiledAssemblyPaths = AssemblyHelper.GetCompiledAssemblyPaths(); foreach (var dir in AssemblyHelper.GetPrecompiledAssemblyDirectories()) { assemblyResolver.AddSearchDirectory(dir); } foreach (var dir in AssemblyHelper.GetPrecompiledEngineAssemblyDirectories()) { assemblyResolver.AddSearchDirectory(dir); } foreach (var dir in AssemblyHelper.GetCompiledAssemblyDirectories()) { assemblyResolver.AddSearchDirectory(dir); } if (progressBar != null) { progressBar.Initialize("Analyzing Scripts", "Analyzing project scripts", m_PlayerAssemblies.Length); } // Analyse all Player assemblies, including Package assemblies. foreach (var assemblyPath in compiledAssemblyPaths) { if (progressBar != null) { progressBar.AdvanceProgressBar(string.Format("Analyzing {0} scripts", Path.GetFileName(assemblyPath))); } if (!File.Exists(assemblyPath)) { Debug.LogError(assemblyPath + " not found."); continue; } AnalyzeAssembly(assemblyPath, assemblyResolver, projectReport, callCrawler); } } if (progressBar != null) { progressBar.ClearProgressBar(); } callCrawler.BuildCallHierarchies(projectReport, progressBar); }
public void Audit(ProjectReport projectReport) { foreach (var auditor in m_Auditors) { auditor.Audit(projectReport); } EditorUtility.ClearProgressBar(); }
private void Analyze() { m_ProjectReport = m_ProjectAuditor.Audit(new ProgressBarDisplay()); m_ValidReport = true; m_IssueTables.Clear(); RefreshDisplay(); }
public ProjectReport Audit(IProgressBar progressBar = null) { var projectReport = new ProjectReport(); foreach (var auditor in m_Auditors) { auditor.Audit(projectReport, progressBar); } return(projectReport); }
/// <summary> /// Runs all available auditors (code, project settings) and generate a report of all found issues. /// </summary> /// <param name="progressBar"> Progress bar, if applicable </param> /// <returns> Generated report </returns> public ProjectReport Audit(IProgressBar progressBar = null) { var projectReport = new ProjectReport(); var completed = false; Audit(projectReport.AddIssue, _completed => { completed = _completed; }, progressBar); while (!completed) { Thread.Sleep(50); } return(projectReport); }
public void OnPreprocessBuild(BuildReport report) { if (m_EnableOnBuild) { var projectReport = new ProjectReport(); Audit(projectReport); var numIssues = projectReport.NumIssues; if (numIssues > 0) { Debug.LogError("Project Auditor found " + numIssues + " issues"); } } }
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 void Audit(ProjectReport projectReport) { var progressBar = new ProgressBarDisplay("Analyzing Scripts", "Analyzing project settings", m_ProblemDescriptors.Count); // do we actually need to look in all assemblies? var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var p in m_ProblemDescriptors) { progressBar.AdvanceProgressBar(); SearchAndEval(p, assemblies, projectReport); } progressBar.ClearProgressBar(); }
private void AnalyzeAssembly(string assemblyPath, ProjectReport projectReport, CallCrawler callCrawler) { using (var a = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters() { ReadSymbols = true, AssemblyResolver = m_AssemblyResolver })) { foreach (var methodDefinition in MonoCecilHelper.AggregateAllTypeDefinitions(a.MainModule.Types).SelectMany(t => t.Methods)) { if (!methodDefinition.HasBody) { continue; } AnalyzeMethodBody(projectReport, a, methodDefinition, callCrawler); } } }
private void AddIssue(ProblemDescriptor descriptor, string description, ProjectReport projectReport) { string projectWindowPath = ""; var mappings = m_ProjectSettingsMapping.Where(p => p.Key.Contains(descriptor.type)); if (mappings.Count() > 0) { projectWindowPath = mappings.First().Value; } projectReport.AddIssue(new ProjectIssue ( descriptor, description = description, IssueCategory.ProjectSettings, new Location { path = projectWindowPath } )); }
private void Analyze() { m_ShouldRefresh = true; m_AnalysisState = AnalysisState.InProgress; m_ProjectReport = new ProjectReport(); foreach (var view in m_AnalysisViews) { view.m_Table.Reset(); } var newIssues = new List <ProjectIssue>(); try { m_ProjectAuditor.Audit((projectIssue) => { newIssues.Add(projectIssue); m_ProjectReport.AddIssue(projectIssue); }, (bool completed) => { // add batch of issues foreach (var view in m_AnalysisViews) { view.AddIssues(newIssues); } newIssues.Clear(); if (completed) { m_AnalysisState = AnalysisState.Completed; } m_ShouldRefresh = true; }, new ProgressBarDisplay()); } catch (AssemblyCompilationException e) { m_AnalysisState = AnalysisState.NotStarted; Debug.LogError(e); } }
public void Audit(ProjectReport projectReport, IProgressBar progressBar = null) { if (progressBar != null) { progressBar.Initialize("Analyzing Settings", "Analyzing project settings", m_ProblemDescriptors.Count); } foreach (var descriptor in m_ProblemDescriptors) { if (progressBar != null) { progressBar.AdvanceProgressBar(); } SearchAndEval(descriptor, projectReport); } if (progressBar != null) { progressBar.ClearProgressBar(); } }
private void SearchAndEval(ProblemDescriptor descriptor, ProjectReport projectReport) { if (string.IsNullOrEmpty(descriptor.customevaluator)) { // do we actually need to look in all assemblies? Maybe we can find a way to only evaluate on the right assembly foreach (var assembly in m_Assemblies) { try { var value = MethodEvaluator.Eval(assembly.Location, descriptor.type, "get_" + descriptor.method, new System.Type[0] { }, new object[0] { }); if (value.ToString() == descriptor.value) { AddIssue(descriptor, string.Format("{0}: {1}", descriptor.description, value), projectReport); // stop iterating assemblies break; } } catch (Exception) { // this is safe to ignore } } } else { Type helperType = m_Helpers.GetType(); MethodInfo theMethod = helperType.GetMethod(descriptor.customevaluator); bool isIssue = (bool)theMethod.Invoke(m_Helpers, null); if (isIssue) { AddIssue(descriptor, descriptor.description, projectReport); } } }
public void BuildCallHierarchies(ProjectReport projectReport, IProgressBar progressBar = null) { foreach (var entry in m_CallPairs) { if (!m_BucketedCallPairs.ContainsKey(entry.Value.callee.FullName)) { m_BucketedCallPairs.Add(entry.Value.callee.FullName, new List <CallPair>()); } m_BucketedCallPairs[entry.Value.callee.FullName].Add(entry.Value); } var numIssues = projectReport.GetNumIssues(IssueCategory.ApiCalls); if (numIssues > 0) { var issues = projectReport.GetIssues(IssueCategory.ApiCalls); if (progressBar != null) { progressBar.Initialize("Analyzing Scripts", "Analyzing call trees", numIssues); } foreach (var issue in issues) { if (progressBar != null) { progressBar.AdvanceProgressBar(); } int depth = 0; BuildHierarchy(issue.callTree.GetChild(), depth); } if (progressBar != null) { progressBar.ClearProgressBar(); } } }
public static IEnumerable <ProjectIssue> FindScriptIssues(ProjectReport projectReport, string relativePath) { return(projectReport.GetIssues(IssueCategory.ApiCalls).Where(i => i.relativePath.Equals(relativePath))); }
private void AnalyzeAssembly(string assemblyPath, ProjectReport projectReport) { using (var a = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters() { ReadSymbols = true })) { foreach (var m in a.MainModule.Types.SelectMany(t => t.Methods)) { if (!m.HasBody) { continue; } List <ProjectIssue> methodBobyIssues = new List <ProjectIssue>(); foreach (var inst in m.Body.Instructions.Where(i => (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt))) { var calledMethod = ((MethodReference)inst.Operand); // HACK: need to figure out a way to know whether a method is actually a property var p = m_ProblemDescriptors.SingleOrDefault(c => c.type == calledMethod.DeclaringType.FullName && (c.method == calledMethod.Name || ("get_" + c.method) == calledMethod.Name)); if (p == null) { // Are we trying to warn about a whole namespace? p = m_ProblemDescriptors.SingleOrDefault(c => c.type == calledMethod.DeclaringType.Namespace && c.method == "*"); } //if (p.type != null && m.HasCustomDebugInformations) if (p != null && m.DebugInformation.HasSequencePoints) { //var msg = string.Empty; SequencePoint s = null; for (var i = inst; i != null; i = i.Previous) { s = m.DebugInformation.GetSequencePoint(i); if (s != null) { // msg = i == inst ? " exactly" : "nearby"; break; } } if (s != null) { // Ignore whitelisted packages // (SteveM - I'd put this code further up in one of the outer loops but I don't // know if it's possible to get the URL further up to compare with the whitelist) bool isPackageWhitelisted = false; foreach (string package in m_WhitelistedPackages) { if (s.Document.Url.Contains(package)) { isPackageWhitelisted = true; break; } } if (!isPackageWhitelisted) { var description = p.description; if (description.Contains(".*")) { description = calledMethod.DeclaringType.FullName + "::" + calledMethod.Name; } // do not add the same type of issue again (for example multiple Linq instructions) var foundIssues = methodBobyIssues.Where(i => i.descriptor == p && i.line == s.StartLine && i.column == s.StartColumn); if (foundIssues.FirstOrDefault() == null) { var projectIssue = new ProjectIssue { description = description, category = IssueCategory.ApiCalls, descriptor = p, callingMethod = m.FullName, url = s.Document.Url.Replace("\\", "/"), line = s.StartLine, column = s.StartColumn }; projectReport.AddIssue(projectIssue); methodBobyIssues.Add(projectIssue); } } } } } } } }
void SearchAndEval(ProblemDescriptor p, System.Reflection.Assembly[] assemblies, ProjectReport projectReport) { if (string.IsNullOrEmpty(p.customevaluator)) { // try all assemblies. Need to find a way to only evaluate on the right assembly foreach (var assembly in assemblies) { try { var value = MethodEvaluator.Eval(assembly.Location, p.type, "get_" + p.method, new System.Type[0] { }, new object[0] { }); if (value.ToString() == p.value) { projectReport.AddIssue(new ProjectIssue { description = p.description, category = IssueCategory.ProjectSettings, descriptor = p }); // stop iterating assemblies break; } } catch (Exception) { // this is safe to ignore } } } else { Type helperType = m_Helpers.GetType(); MethodInfo theMethod = helperType.GetMethod(p.customevaluator); bool isIssue = (bool)theMethod.Invoke(m_Helpers, null); if (isIssue) { projectReport.AddIssue(new ProjectIssue { description = p.description, category = IssueCategory.ProjectSettings, descriptor = p }); } } }