Exemple #1
0
        public DocumentId FindProjectDocumentIdWithItemId(uint itemidInsertionPoint)
        {
            var hierarchy = _workspace.GetHierarchy(_project.Id);

            foreach (var document in _workspace.CurrentSolution.GetProject(_project.Id).Documents)
            {
                if (document.FilePath != null && hierarchy.TryGetItemId(document.FilePath) == itemidInsertionPoint)
                {
                    return(document.Id);
                }
            }

            return(null);
        }
Exemple #2
0
        private static bool ProjectIdMatchesHierarchy(VisualStudioWorkspace workspace, ProjectId projectId, IVsHierarchy hierarchy)
        {
            var hierarchyForProject = workspace.GetHierarchy(projectId);

            if (hierarchyForProject == null)
            {
                return(false);
            }

            if (hierarchyForProject == hierarchy)
            {
                return(true);
            }

            // For CPS, the hierarchy for the Roslyn project isn't the same as the one
            // we get from Solution Explorer (it's a wrapper implementation), so we'll
            // have to compare properties.

            hierarchyForProject.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out var rawValue);

            if (rawValue is string projectName)
            {
                hierarchy.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out rawValue);
                return(projectName == (rawValue as string));
            }

            return(false);
        }
            private Assembly ResolveAssembly(ProjectId projectId, string assemblyName)
            {
                this.AssertIsForeground();

                if (_workspace == null)
                {
                    return(null);
                }

                var hierarchy = _workspace.GetHierarchy(projectId);

                if (hierarchy == null ||
                    !hierarchy.TryGetProperty((__VSHPROPID)__VSHPROPID4.VSHPROPID_TargetFrameworkMoniker, out string targetMoniker) ||
                    targetMoniker == null)
                {
                    return(null);
                }

                try
                {
                    // Below we use the DesignTimeAssemblyResolver functionality of VS to
                    // determine if we can resolve the specified assembly name in the context
                    // of this project.  However, this service does not do the right thing
                    // in UWP apps.  Specifically, it *will* resolve the assembly to a
                    // reference assembly, even though that's never what we want.  In order
                    // to deal with that, we put in this little check where we do not allow
                    // reference assembly resolution if the projects TargetFrameworkMoniker
                    // is ".NETCore, Version=5.0" or greater.

                    var frameworkName = new FrameworkName(targetMoniker);
                    if (StringComparer.OrdinalIgnoreCase.Equals(frameworkName.Identifier, ".NETCore") &&
                        frameworkName.Version >= new Version(major: 5, minor: 0))
                    {
                        return(null);
                    }
                }
                catch (ArgumentException)
                {
                    // Something wrong with our TFM.  We don't have enough information to
                    // properly resolve this assembly name.
                    return(null);
                }

                try
                {
                    var frameworkProvider = new VsTargetFrameworkProvider(
                        (IVsFrameworkMultiTargeting)_serviceProvider.GetService(typeof(SVsFrameworkMultiTargeting)),
                        targetMoniker,
                        (IVsSmartOpenScope)_serviceProvider.GetService(typeof(SVsSmartOpenScope)));
                    return(frameworkProvider.GetReflectionAssembly(new AssemblyName(assemblyName)));
                }
                catch (InvalidOperationException)
                {
                    // VsTargetFrameworkProvider throws InvalidOperationException in the
                    // some cases (like when targeting packs are missing).  In that case
                    // we can't resolve this path.
                    return(null);
                }
            }
Exemple #4
0
        public IReadOnlyDictionary <string, IEnumerable <DiagnosticDescriptor> > GetAllDiagnosticDescriptors(IVsHierarchy?hierarchy)
        {
            var currentSolution = _workspace.CurrentSolution;
            var infoCache       = _diagnosticService.AnalyzerInfoCache;
            var hostAnalyzers   = currentSolution.State.Analyzers;

            if (hierarchy == null)
            {
                return(Transform(hostAnalyzers.GetDiagnosticDescriptorsPerReference(infoCache)));
            }

            // Analyzers are only supported for C# and VB currently.
            var projectsWithHierarchy = currentSolution.Projects
                                        .Where(p => p.Language is LanguageNames.CSharp or LanguageNames.VisualBasic)
                                        .Where(p => _workspace.GetHierarchy(p.Id) == hierarchy);

            if (projectsWithHierarchy.Count() <= 1)
            {
                var project = projectsWithHierarchy.FirstOrDefault();
                if (project == null)
                {
                    return(Transform(hostAnalyzers.GetDiagnosticDescriptorsPerReference(infoCache)));
                }
                else
                {
                    return(Transform(hostAnalyzers.GetDiagnosticDescriptorsPerReference(infoCache, project)));
                }
            }
            else
            {
                // Multiple workspace projects map to the same hierarchy, return a union of descriptors for all projects.
                // For example, this can happen for web projects where we create on the fly projects for aspx files.
                var descriptorsMap = ImmutableDictionary.CreateBuilder <string, IEnumerable <DiagnosticDescriptor> >();
                foreach (var project in projectsWithHierarchy)
                {
                    var descriptorsPerReference = hostAnalyzers.GetDiagnosticDescriptorsPerReference(infoCache, project);
                    foreach (var(displayName, descriptors) in descriptorsPerReference)
                    {
                        if (descriptorsMap.TryGetValue(displayName, out var existingDescriptors))
                        {
                            descriptorsMap[displayName] = existingDescriptors.Concat(descriptors).Distinct();
                        }
                        else
                        {
                            descriptorsMap[displayName] = descriptors;
                        }
                    }
                }

                return(descriptorsMap.ToImmutable());
            }
        }
        private Dictionary <IVsHierarchy, List <uint> > GetHierarchiesAndItemIDsFromDocumentIDs(
            VisualStudioWorkspace visualStudioWorkspace,
            IEnumerable <DocumentId> changedDocumentIDs
            )
        {
            AssertIsForeground();

            var hierarchyToItemIDsMap = new Dictionary <IVsHierarchy, List <uint> >();

            foreach (var documentId in changedDocumentIDs)
            {
                var hierarchy = visualStudioWorkspace.GetHierarchy(documentId.ProjectId);

                if (hierarchy == null)
                {
                    continue;
                }

                var document = visualStudioWorkspace.CurrentSolution.GetDocument(documentId);
                var itemID   = hierarchy.TryGetItemId(document.FilePath);

                if (itemID == VSConstants.VSITEMID_NIL)
                {
                    continue;
                }

                if (
                    !hierarchyToItemIDsMap.TryGetValue(
                        hierarchy,
                        out var itemIDsForCurrentHierarchy
                        )
                    )
                {
                    itemIDsForCurrentHierarchy = new List <uint>();
                    hierarchyToItemIDsMap.Add(hierarchy, itemIDsForCurrentHierarchy);
                }

                if (!itemIDsForCurrentHierarchy.Contains(itemID))
                {
                    itemIDsForCurrentHierarchy.Add(itemID);
                }
            }

            return(hierarchyToItemIDsMap);
        }
Exemple #6
0
        // *DO NOT DELETE*
        // This is used by Ruleset Editor from ManagedSourceCodeAnalysis.dll.
        public IReadOnlyDictionary <string, IEnumerable <DiagnosticDescriptor> > GetAllDiagnosticDescriptors(IVsHierarchy hierarchyOpt)
        {
            if (hierarchyOpt == null)
            {
                return(Transform(_diagnosticService.CreateDiagnosticDescriptorsPerReference(projectOpt: null)));
            }

            // Analyzers are only supported for C# and VB currently.
            var projectsWithHierarchy = _workspace.CurrentSolution.Projects
                                        .Where(p => p.Language == LanguageNames.CSharp || p.Language == LanguageNames.VisualBasic)
                                        .Where(p => _workspace.GetHierarchy(p.Id) == hierarchyOpt);

            if (projectsWithHierarchy.Count() <= 1)
            {
                return(Transform(_diagnosticService.CreateDiagnosticDescriptorsPerReference(projectsWithHierarchy.FirstOrDefault())));
            }
            else
            {
                // Multiple workspace projects map to the same hierarchy, return a union of descriptors for all projects.
                // For example, this can happen for web projects where we create on the fly projects for aspx files.
                var descriptorsMap = ImmutableDictionary.CreateBuilder <string, IEnumerable <DiagnosticDescriptor> >();
                foreach (var project in projectsWithHierarchy)
                {
                    var newDescriptorTuples = _diagnosticService.CreateDiagnosticDescriptorsPerReference(project);
                    foreach (var kvp in newDescriptorTuples)
                    {
                        if (descriptorsMap.TryGetValue(kvp.Key, out var existingDescriptors))
                        {
                            descriptorsMap[kvp.Key] = existingDescriptors.Concat(kvp.Value).Distinct();
                        }
                        else
                        {
                            descriptorsMap[kvp.Key] = kvp.Value;
                        }
                    }
                }

                return(descriptorsMap.ToImmutable());
            }
        }
        public AbstractLegacyProject(
            string projectSystemName,
            IVsHierarchy hierarchy,
            string language,
            bool isVsIntellisenseProject,
            IServiceProvider serviceProvider,
            IThreadingContext threadingContext,
            string externalErrorReportingPrefix
            ) : base(threadingContext, assertIsForeground: true)
        {
            Contract.ThrowIfNull(hierarchy);

            var componentModel = (IComponentModel)serviceProvider.GetService(
                typeof(SComponentModel)
                );

            Workspace = componentModel.GetService <VisualStudioWorkspace>();
            var workspaceImpl = (VisualStudioWorkspaceImpl)Workspace;

            var projectFilePath = hierarchy.TryGetProjectFilePath();

            if (projectFilePath != null && !File.Exists(projectFilePath))
            {
                projectFilePath = null;
            }

            if (projectFilePath != null)
            {
                _projectDirectory = Path.GetDirectoryName(projectFilePath);
            }

            if (isVsIntellisenseProject)
            {
                // IVsIntellisenseProjects are usually used for contained language cases, which means these projects don't have any real
                // output path that we should consider. Since those point to the same IVsHierarchy as another project, we end up with two projects
                // with the same output path, which potentially breaks conversion of metadata references to project references. However they're
                // also used for database projects and a few other cases where there there isn't a "primary" IVsHierarchy.
                // As a heuristic here we'll ignore the output path if we already have another project tied to the IVsHierarchy.
                foreach (var projectId in Workspace.CurrentSolution.ProjectIds)
                {
                    if (Workspace.GetHierarchy(projectId) == hierarchy)
                    {
                        _ignoreOutputPath = true;
                        break;
                    }
                }
            }

            var projectFactory = componentModel.GetService <VisualStudioProjectFactory>();

            VisualStudioProject = threadingContext.JoinableTaskFactory.Run(
                () =>
                projectFactory.CreateAndAddToWorkspaceAsync(
                    projectSystemName,
                    language,
                    new VisualStudioProjectCreationInfo
            {
                // The workspace requires an assembly name so we can make compilations. We'll use
                // projectSystemName because they'll have a better one eventually.
                AssemblyName = projectSystemName,
                FilePath     = projectFilePath,
                Hierarchy    = hierarchy,
                ProjectGuid  = GetProjectIDGuid(hierarchy),
            },
                    CancellationToken.None
                    )
                );

            workspaceImpl.AddProjectRuleSetFileToInternalMaps(
                VisualStudioProject,
                () => VisualStudioProjectOptionsProcessor.EffectiveRuleSetFilePath
                );

            // Right now VB doesn't have the concept of "default namespace". But we conjure one in workspace
            // by assigning the value of the project's root namespace to it. So various feature can choose to
            // use it for their own purpose.
            // In the future, we might consider officially exposing "default namespace" for VB project
            // (e.g. through a <defaultnamespace> msbuild property)
            VisualStudioProject.DefaultNamespace = GetRootNamespacePropertyValue(hierarchy);

            if (
                TryGetPropertyValue(
                    hierarchy,
                    AdditionalPropertyNames.MaxSupportedLangVersion,
                    out var maxLangVer
                    )
                )
            {
                VisualStudioProject.MaxLangVersion = maxLangVer;
            }

            if (
                TryGetBoolPropertyValue(
                    hierarchy,
                    AdditionalPropertyNames.RunAnalyzers,
                    out var runAnayzers
                    )
                )
            {
                VisualStudioProject.RunAnalyzers = runAnayzers;
            }

            if (
                TryGetBoolPropertyValue(
                    hierarchy,
                    AdditionalPropertyNames.RunAnalyzersDuringLiveAnalysis,
                    out var runAnayzersDuringLiveAnalysis
                    )
                )
            {
                VisualStudioProject.RunAnalyzersDuringLiveAnalysis = runAnayzersDuringLiveAnalysis;
            }

            Hierarchy = hierarchy;
            ConnectHierarchyEvents();
            RefreshBinOutputPath();

            workspaceImpl.SubscribeExternalErrorDiagnosticUpdateSourceToSolutionBuildEvents();

            _externalErrorReporter = new ProjectExternalErrorReporter(
                VisualStudioProject.Id,
                externalErrorReportingPrefix,
                language,
                workspaceImpl
                );
            _batchScopeCreator = componentModel.GetService <SolutionEventsBatchScopeCreator>();
            _batchScopeCreator.StartTrackingProject(VisualStudioProject, Hierarchy);
        }
Exemple #8
0
 internal Project GetProjectFromHierarchy(IVsHierarchy hierarchy)
 => _workspace.CurrentSolution.Projects.FirstOrDefault(proj => _workspace.GetHierarchy(proj.Id) == hierarchy);
Exemple #9
0
 public static Project GetProject(IVsHierarchy projectHierarchy, VisualStudioWorkspace visualStudioWorkspace)
 {
     return(visualStudioWorkspace.CurrentSolution.Projects
            .FirstOrDefault(p => projectHierarchy == visualStudioWorkspace.GetHierarchy(p.Id)));
 }
        public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, string targetFrameworkMoniker, out ProjectId projectId)
        {
            // A project node is represented in two different hierarchies: the solution's IVsHierarchy (where it is a leaf node)
            // and the project's own IVsHierarchy (where it is the root node). The IVsHierarchyItem joins them together for the
            // purpose of creating the tree displayed in Solution Explorer. The project's hierarchy is what is passed from the
            // project system to the language service, so that's the one the one to query here. To do that we need to get
            // the "nested" hierarchy from the IVsHierarchyItem.
            var nestedHierarchy   = hierarchyItem.HierarchyIdentity.NestedHierarchy;
            var nestedHierarchyId = hierarchyItem.HierarchyIdentity.NestedItemID;

            if (!nestedHierarchy.TryGetCanonicalName(nestedHierarchyId, out string nestedCanonicalName) ||
                !nestedHierarchy.TryGetItemName(nestedHierarchyId, out string nestedName))
            {
                projectId = default(ProjectId);
                return(false);
            }

            // First filter the projects by matching up properties on the input hierarchy against properties on each
            // project's hierarchy.
            var candidateProjects = _workspace.CurrentSolution.Projects
                                    .Where(p =>
            {
                // We're about to access various properties of the IVsHierarchy associated with the project.
                // The properties supported and the interpretation of their values varies from one project system
                // to another. This code is designed with C# and VB in mind, so we need to filter out everything
                // else.
                if (p.Language != LanguageNames.CSharp &&
                    p.Language != LanguageNames.VisualBasic)
                {
                    return(false);
                }

                // Here we try to match the hierarchy from Solution Explorer to a hierarchy from the Roslyn project.
                // The canonical name of a hierarchy item must be unique _within_ an hierarchy, but since we're
                // examining multiple hierarchies the canonical name could be the same. Indeed this happens when two
                // project files are in the same folder--they both use the full path to the _folder_ as the canonical
                // name. To distinguish them we also examine the "regular" name, which will necessarily be different
                // if the two projects are in the same folder.
                // Note that if a project has been loaded with Lightweight Solution Load it won't even have a
                // hierarchy, so we need to check for null first.
                var hierarchy = _workspace.GetHierarchy(p.Id);

                if (hierarchy != null &&
                    hierarchy.TryGetCanonicalName((uint)VSConstants.VSITEMID.Root, out string projectCanonicalName) &&
                    hierarchy.TryGetItemName((uint)VSConstants.VSITEMID.Root, out string projectName) &&
                    projectCanonicalName.Equals(nestedCanonicalName, System.StringComparison.OrdinalIgnoreCase) &&
                    projectName.Equals(nestedName))
                {
                    if (targetFrameworkMoniker == null)
                    {
                        return(true);
                    }

                    return(hierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out string projectTargetFrameworkMoniker) &&
                           projectTargetFrameworkMoniker.Equals(targetFrameworkMoniker));
                }

                return(false);
            })
                                    .ToArray();

            // If we only have one candidate then no further checks are required.
            if (candidateProjects.Length == 1)
            {
                projectId = candidateProjects[0].Id;
                return(true);
            }

            // If we have multiple candidates then we might be dealing with Web Application Projects. In this case
            // there will be one main project plus one project for each open aspx/cshtml/vbhtml file, all with
            // identical properties on their hierarchies. We can find the main project by taking the first project
            // without a ContainedDocument.
            foreach (var candidateProject in candidateProjects)
            {
                if (!candidateProject.DocumentIds.Any(id => ContainedDocument.TryGetContainedDocument(id) != null))
                {
                    projectId = candidateProject.Id;
                    return(true);
                }
            }

            projectId = default(ProjectId);
            return(false);
        }