public AbstractLegacyProject( string projectSystemName, IVsHierarchy hierarchy, string language, IServiceProvider serviceProvider, IThreadingContext threadingContext, string externalErrorReportingPrefix, HostDiagnosticUpdateSource hostDiagnosticUpdateSourceOpt, ICommandLineParserService commandLineParserServiceOpt) : base(threadingContext) { Contract.ThrowIfNull(hierarchy); var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel)); Workspace = componentModel.GetService <VisualStudioWorkspace>(); var projectFilePath = hierarchy.TryGetProjectFilePath(); if (projectFilePath != null && !File.Exists(projectFilePath)) { projectFilePath = null; } if (projectFilePath != null) { _projectDirectory = Path.GetDirectoryName(projectFilePath); } var projectFactory = componentModel.GetService <VisualStudioProjectFactory>(); VisualStudioProject = projectFactory.CreateAndAddToWorkspace( 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), }); ((VisualStudioWorkspaceImpl)Workspace).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); Hierarchy = hierarchy; ConnectHierarchyEvents(); RefreshBinOutputPath(); // TODO: remove this terrible hack, which is working around shims throwing in not-good ways try { _externalErrorReporter = new ProjectExternalErrorReporter(VisualStudioProject.Id, externalErrorReportingPrefix, Workspace, componentModel.GetService <ExternalErrorDiagnosticUpdateSource>()); _editAndContinueProject = new VsENCRebuildableProjectImpl(Workspace, VisualStudioProject, serviceProvider); } catch (Exception) { } _batchScopeCreator = componentModel.GetService <SolutionEventsBatchScopeCreator>(); _batchScopeCreator.StartTrackingProject(VisualStudioProject, Hierarchy); }
public AbstractLegacyProject( string projectSystemName, IVsHierarchy hierarchy, string language, IServiceProvider serviceProvider, IThreadingContext threadingContext, string externalErrorReportingPrefix, HostDiagnosticUpdateSource hostDiagnosticUpdateSourceOpt, ICommandLineParserService commandLineParserServiceOpt) : 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); } var projectFactory = componentModel.GetService <VisualStudioProjectFactory>(); VisualStudioProject = projectFactory.CreateAndAddToWorkspace( 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), }); 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); }
// TODO: remove the AllowDefault = true on HostDiagnosticUpdateSource by making it a proper mock public VisualStudioProjectFactory(VisualStudioWorkspaceImpl visualStudioWorkspaceImpl, [Import(AllowDefault = true)] HostDiagnosticUpdateSource hostDiagnosticUpdateSource) { _visualStudioWorkspaceImpl = visualStudioWorkspaceImpl; _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource; }
public VisualStudioAnalyzer(string fullPath, IVsFileChangeEx fileChangeService, HostDiagnosticUpdateSource hostDiagnosticUpdateSource, ProjectId projectId, Workspace workspace, IAnalyzerAssemblyLoader loader, string language) { _fullPath = fullPath; _tracker = new FileChangeTracker(fileChangeService, fullPath); _tracker.UpdatedOnDisk += OnUpdatedOnDisk; _tracker.StartFileChangeListeningAsync(); _tracker.EnsureSubscription(); _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource; _projectId = projectId; _workspace = workspace; _loader = loader; _language = language; }
// Method is static to prevent accidental use of mutable state in this class private static void AnalyzeAndReportConflictsInSolution( Solution solution, ImmutableHashSet <string> currentAnalyzerPaths, HostDiagnosticUpdateSource hostDiagnosticUpdateSource, CancellationToken cancellationToken) { var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().Select(assembly => AssemblyIdentity.FromAssemblyDefinition(assembly)); var loadedAssembliesList = new IgnorableAssemblyIdentityList(loadedAssemblies); var ignorableAssemblyLists = new[] { s_systemPrefixList, s_codeAnalysisPrefixList, s_explicitlyIgnoredAssemblyList, s_assembliesIgnoredByNameList, loadedAssembliesList }; cancellationToken.ThrowIfCancellationRequested(); var results = AnalyzerDependencyChecker.ComputeDependencyConflicts(currentAnalyzerPaths, ignorableAssemblyLists, s_bindingRedirectionService, cancellationToken); var builder = ImmutableArray.CreateBuilder <DiagnosticData>(); var conflicts = results.Conflicts; var missingDependencies = results.MissingDependencies; foreach (var project in solution.Projects) { builder.Clear(); // If our analysis has been cancelled, it means another request has been queued behind us; thus it's OK to stop // doing the analysis now and let that other one fix up any stale results. cancellationToken.ThrowIfCancellationRequested(); var analyzerFilePaths = new HashSet <string>( project.AnalyzerReferences .OfType <AnalyzerFileReference>() .Select(f => f.FullPath), StringComparer.OrdinalIgnoreCase); foreach (var conflict in conflicts) { if (analyzerFilePaths.Contains(conflict.AnalyzerFilePath1) || analyzerFilePaths.Contains(conflict.AnalyzerFilePath2)) { var messageArguments = new string[] { conflict.AnalyzerFilePath1, conflict.AnalyzerFilePath2, conflict.Identity.ToString() }; if (DiagnosticData.TryCreate(s_analyzerDependencyConflictRule, messageArguments, project, out var diagnostic)) { builder.Add(diagnostic); } } } foreach (var missingDependency in missingDependencies) { if (analyzerFilePaths.Contains(missingDependency.AnalyzerPath)) { var messageArguments = new string[] { missingDependency.AnalyzerPath, missingDependency.DependencyIdentity.ToString() }; if (DiagnosticData.TryCreate(s_missingAnalyzerReferenceRule, messageArguments, project, out var diagnostic)) { builder.Add(diagnostic); } } } hostDiagnosticUpdateSource.UpdateDiagnosticsForProject(project.Id, s_dependencyConflictErrorId, builder.ToImmutable()); } foreach (var conflict in conflicts) { LogConflict(conflict); } foreach (var missingDependency in missingDependencies) { LogMissingDependency(missingDependency); } }