예제 #1
0
        /// <summary>
        /// Does actual query to Packag Index to find packages where a given type is defined.
        /// Note: At diagnostic level there no way to know in which document, project or workspace
        /// we are for a given SyntaxNode (or it's SyntaxNodeAnalysisContext) since diagnostics
        /// work at csc.exe level (in command line for example) and there no container objects defined
        /// at that time.
        /// Thus we will display information about all packages returned form index to suggest user where
        /// type can be located, however when user clicks Ctrl+. we would display only code fixes for packages
        /// that satisfy current project target frameworks list.
        /// </summary>
        protected override IEnumerable <string> AnalyzeNode(TIdentifierNameSyntax node)
        {
            var projectFilter = GetProjectFilter();

            if (!projectFilter.IsProjectSupported(node.GetLocation().SourceTree.FilePath))
            {
                return(null);
            }

            var typeName = node.ToString();
            var packagesWithGivenType = _packageSearcher.Search(typeName);

            if (!packagesWithGivenType.Any())
            {
                return(null);
            }

            var projectTargetFrameworks = _targetFrameworkProvider.GetTargetFrameworks(node.GetLocation().SourceTree.FilePath);

            // Note: allowHigherVersions=true here since we want to show diagnostic message for type if it exists in some package
            // for discoverability (tooltip) but we would not supply a code fix if package already installed in the project with
            // any version, user needs to upgrade on his own.
            // Note2: the problem here is that we don't know if type exist in older versions of the package or not and to store
            // all package versions in index might slow things down. If we receive feedback that we need ot be more smart here
            // we should consider adding all package versions to the local index.
            return(GetFriendlyPackagesString(TargetFrameworkHelper.GetSupportedPackages(packagesWithGivenType, projectTargetFrameworks, allowHigherVersions: true)
                                             .Take(MaxPackageSuggestions)));
        }
예제 #2
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var diagnostics       = context.Diagnostics;
            var cancellationToken = context.CancellationToken;
            var project           = document.Project;
            var diagnostic        = diagnostics.First();
            var root              = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var token     = root.FindToken(span.Start, findInsideTrivia: true);
            var ancestors = token.GetAncestors <SyntaxNode>();

            if (!ancestors.Any())
            {
                return;
            }

            var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root);

            if (node == null)
            {
                return;
            }

            var placeSystemNamespaceFirst = true;

            if (!cancellationToken.IsCancellationRequested)
            {
                if (CanAddImport(node, cancellationToken))
                {
                    var typeName = node.ToString();
                    var projectTargetFrameworks = _targetFrameworkProvider.GetTargetFrameworks(document.FilePath);
                    // Note: allowHigherVersions=false here since we don't want to provide code fix that adds another
                    // dependency for the same package but different version, user should upgrade it on his own when
                    // see Diagnostic suggestion
                    var packagesWithGivenType = TargetFrameworkHelper.GetSupportedPackages(_packageSearcher.Search(typeName), projectTargetFrameworks, allowHigherVersions: false)
                                                .Take(MaxPackageSuggestions);

                    foreach (var typeInfo in packagesWithGivenType)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        var namespaceName = typeInfo.FullName.Contains(".") ? Path.GetFileNameWithoutExtension(typeInfo.FullName) : null;
                        if (!string.IsNullOrEmpty(namespaceName))
                        {
                            var action = new AddPackageCodeAction(_packageInstaller, typeInfo, ActionTitle,
                                                                  (c) => AddImportAsync(node, namespaceName, document, placeSystemNamespaceFirst, cancellationToken));
                            context.RegisterCodeFix(action, diagnostic);
                        }
                    }
                }
            }
        }