Exemple #1
0
        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();
        }
Exemple #2
0
        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();
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        public void Audit(ProjectReport projectReport)
        {
            foreach (var auditor in m_Auditors)
            {
                auditor.Audit(projectReport);
            }

            EditorUtility.ClearProgressBar();
        }
Exemple #6
0
        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);
        }
Exemple #9
0
        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");
                }
            }
        }
Exemple #10
0
        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();
        }
Exemple #12
0
        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);
                }
            }
        }
Exemple #13
0
        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);
            }
        }
Exemple #15
0
        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();
            }
        }
Exemple #16
0
        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();
                }
            }
        }
Exemple #18
0
 public static IEnumerable <ProjectIssue> FindScriptIssues(ProjectReport projectReport, string relativePath)
 {
     return(projectReport.GetIssues(IssueCategory.ApiCalls).Where(i => i.relativePath.Equals(relativePath)));
 }
Exemple #19
0
        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
                    });
                }
            }
        }