Пример #1
0
        /// <summary>
        /// Creates an exclusion list based on the inspection parameters and the project being inspected. The
        /// project itself and any project-references are also added to the list.
        /// </summary>
        /// <param name="parameters">The inspection parameters provided by the user.</param>
        /// <param name="project">The project being inspected.</param>
        public static NamespaceExclusionList CreateFromParameters(InspectionParameters parameters, Project project)
        {
            var namespaces = parameters.ExcludedNamespaces.ToList();

            // Add references to type in the project itself to the exclusions
            if (project.DefaultNamespace != null)
            {
                var projectRootNs = project.DefaultNamespace;

                namespaces.Add(projectRootNs);

                // Stem the root ns
                var offset = projectRootNs.IndexOf('.');

                if (offset > 0 && offset < projectRootNs.Length)
                {
                    namespaces.Add(projectRootNs.Substring(0, offset));
                }
            }

            // Add referenced projects in the same solution to the exclusions
            foreach (var reference in project.ProjectReferences)
            {
                var referencedProject = project.Solution.GetProject(reference.ProjectId);

                if (referencedProject?.DefaultNamespace != null)
                {
                    namespaces.Add(referencedProject.DefaultNamespace);
                }
            }

            return(new NamespaceExclusionList(namespaces));
        }
Пример #2
0
        /// <summary>
        /// Processes the provided <paramref name="project"/>, and computes the provided <paramref name="metrics"/>.
        /// </summary>
        /// <param name="parameters">The inspection parameters provided by the user.</param>
        /// <param name="project">The project to inspect.</param>
        /// <param name="metrics">The metrics to compute.</param>
        /// <param name="ct">A cancellation token.</param>
        private async Task <ProjectInspectionResult> ProcessAsync(InspectionParameters parameters, Project project, IList <IMetric> metrics, CancellationToken ct)
        {
            _logger.LogVerbose($"Inspecting project: {project.Name}");

            var compilation = await project.GetCompilationAsync(ct);

            if (compilation is null)
            {
                throw new InspectionException($"Failed to compile project: {project.Name}");
            }

            var registry = new Registry();
            var resolver = new PackageResolver(_logger);
            var results  = new List <PackageInspectionResult>();

            var documents  = project.Documents.ToImmutableHashSet();
            var exclusions = NamespaceExclusionList.CreateFromParameters(parameters, project);

            await resolver.CreatePackageGraph(project, exclusions, ct);

            var memberLookupTable = await GetMemberAccessLookupTable(compilation, exclusions, ct);

            using (var portableExecutableLoadContext = new PortableExecutableLoadContext(project, _logger))
            {
                foreach (var executable in portableExecutableLoadContext.GetExecutables(exclusions))
                {
                    var package = resolver.CreatePackage(executable);

                    registry.AddPackage(package);

                    foreach (var type in executable.ExportedTypes)
                    {
                        var compilationType = GetCompilationType(compilation, type);

                        if (compilationType is null)
                        {
                            continue;
                        }

                        var isAdded = await AddConstructorReferences(project.Solution, documents, package, registry, compilationType, ct);

                        if (isAdded)
                        {
                            await AddMemberReferences(project.Solution, documents, package, registry, compilationType, memberLookupTable, ct);
                        }
                    }

                    results.Add(ComputeMetrics(project, compilation, package, metrics, registry));
                }
            }

            results.AddRange(AddMissingExplicitPackages(resolver, exclusions, results));

            return(ProjectInspectionResult.Ok(project, results));
        }
        /// <summary>
        /// Instantiates all metrics specified by the <paramref name="parameters"/>.
        /// </summary>
        /// <param name="parameters">The inspection parameters provided by the user.</param>
        public IEnumerable <IMetric> CreateMetricInstances(InspectionParameters parameters)
        {
            if (parameters.Metrics.Count < 1)
            {
                foreach (var factory in _factories.Values)
                {
                    yield return(factory());
                }
            }
            else
            {
                var selected = _factories
                               .Where(kvp => parameters.Metrics.Contains(kvp.Key))
                               .Select(kvp => kvp.Value);

                foreach (var factory in selected)
                {
                    yield return(factory());
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Inspects the provided <paramref name="file"/>. If the file is a solution (.sln) file all
        /// non-excluded projects are inspected. If the file is a project (.csproj) file that project is
        /// inspected.
        /// </summary>
        /// <param name="file">An absolute file path to either a solution (.sln) or project (.csproj) file.</param>
        /// <param name="parameters">The inspection parameters provided by the user.</param>
        /// <param name="ct">A cancellation token.</param>
        /// <exception cref="InspectionException">This exception is thrown if the inspection process encounters an error.</exception>
        public async IAsyncEnumerable <ProjectInspectionResult> InspectAsync(FileSystemInfo file, InspectionParameters parameters, [EnumeratorCancellation] CancellationToken ct)
        {
            MSBuildLocator.RegisterDefaults();

            _logger.LogInformation("Initializing");

            using (var workspace = MSBuildWorkspace.Create())
            {
                workspace.LoadMetadataForReferencedProjects = true;

                var context = new InspectionContext(file, workspace, parameters);
                var metrics = context.CreateMetricInstances(context.Parameters).ToList();

                if (file.HasExtension(".csproj"))
                {
                    _logger.LogVerbose($"Inspecting project: {file}");

                    yield return(await InspectProject(context, metrics, ct));
                }
                else if (file.HasExtension(".sln"))
                {
                    _logger.LogVerbose($"Inspecting solution: {file}");

                    await foreach (var result in InspectSolution(context, metrics, ct))
                    {
                        yield return(result);
                    }
                }
                else
                {
                    throw new InspectionException("The specified file path is not a reference to a solution or project file");
                }
            }
        }
 public InspectionContext(FileSystemInfo file, MSBuildWorkspace workspace, InspectionParameters parameters)
 {
     File       = file;
     Workspace  = workspace;
     Parameters = parameters;
 }