async Task <ProjectCacheInfo> WaitForProjectInfoCacheToChange(
            Solution sol,
            Project p,
            ProjectCacheInfo oldCacheInfo)
        {
            const int timeout  = 10000;           // ms
            int       howLong  = 0;
            const int interval = 200;             // ms

            while (true)
            {
                var cacheInfo = GetProjectCacheInfo(sol, p);
                if (cacheInfo != null)
                {
                    if (!oldCacheInfo.Equals(cacheInfo))
                    {
                        return(cacheInfo);
                    }
                }

                if (howLong >= timeout)
                {
                    Assert.Fail("Timed out waiting for project info cache file to be updated");
                }

                await Task.Delay(interval);

                howLong += interval;
            }
        }
        public async Task TestWorkspaceFilesCache_CacheOutOfDate_CacheUpdatedFromMSBuold()
        {
            // First we create the cache by loading the solution.
            string           solFile         = Util.GetSampleProject("console-project", "ConsoleProject.sln");
            FilePath         projectFileName = null;
            ProjectCacheInfo cacheInfo       = null;

            await IdeServices.Workspace.OpenWorkspaceItem(solFile);

            await IdeServices.TypeSystemService.ProcessPendingLoadOperations();

            var sol = IdeServices.Workspace.GetAllItems <Solution> ().First();

            IdeServices.Workspace.ActiveConfigurationId = sol.DefaultConfigurationId;

            var p = sol.FindProjectByName("ConsoleProject") as DotNetProject;

            projectFileName = p.FileName;
            cacheInfo       = GetProjectCacheInfo(sol, p);
            Assert.IsNotNull(cacheInfo);
            Assert.IsFalse(cacheInfo.References.Any(r => StringComparer.OrdinalIgnoreCase.Equals(r.FilePath.FileNameWithoutExtension, "System.Net")));

            await IdeServices.Workspace.Close();

            // Project file changed so cache is now invalid.
            var updatedProjectFile = projectFileName + ".reference-added";

            File.Copy(updatedProjectFile, projectFileName, overwrite: true);

            // Reload project and check cache is updated.
            await IdeServices.Workspace.OpenWorkspaceItem(solFile);

            await IdeServices.TypeSystemService.ProcessPendingLoadOperations();

            sol = IdeServices.Workspace.GetAllItems <Solution> ().First();
            IdeServices.Workspace.ActiveConfigurationId = sol.DefaultConfigurationId;

            p = sol.FindProjectByName("ConsoleProject") as DotNetProject;
            var updatedCacheInfo = await WaitForProjectInfoCacheToChange(sol, p, cacheInfo);

            Assert.IsTrue(updatedCacheInfo.References.Any(r => r.FilePath.FileNameWithoutExtension == "System.Net"));
            Assert.IsTrue(updatedCacheInfo.References.Any(r => r.FilePath.FileNameWithoutExtension == "System.Xml.Linq"));
            Assert.IsTrue(p.References.Any(r => r.Include == "System.Net"));
            Assert.IsTrue(p.References.Any(r => r.Include == "System.Xml.Linq"));

            var ws        = IdeServices.TypeSystemService.GetWorkspace(sol);
            var projectId = ws.GetProjectId(p);

            foreach (var reference in p.References)
            {
                var analysisProject  = ws.CurrentSolution.GetProject(projectId);
                var matchedReference = analysisProject
                                       .MetadataReferences
                                       .OfType <MonoDevelopMetadataReference.Snapshot> ()
                                       .FirstOrDefault(r => ((FilePath)r.FilePath).FileNameWithoutExtension == reference.Include);
                Assert.IsNotNull(matchedReference, "Reference not found: " + reference.Include);
            }
        }
示例#3
0
        public void Equals_EditorConfigFiles()
        {
            var cacheInfo1 = new ProjectCacheInfo {
                AdditionalFiles   = ImmutableArray <FilePath> .Empty,
                AnalyzerFiles     = ImmutableArray <FilePath> .Empty,
                EditorConfigFiles = ImmutableArray <FilePath> .Empty,
                ProjectReferences = ImmutableArray <Microsoft.CodeAnalysis.ProjectReference> .Empty,
                References        = ImmutableArray <MonoDevelopMetadataReference> .Empty,
                SourceFiles       = ImmutableArray <ProjectFile> .Empty,
            };

            var cacheInfo2 = new ProjectCacheInfo {
                AdditionalFiles   = ImmutableArray <FilePath> .Empty,
                AnalyzerFiles     = ImmutableArray <FilePath> .Empty,
                EditorConfigFiles = ImmutableArray <FilePath> .Empty,
                ProjectReferences = ImmutableArray <Microsoft.CodeAnalysis.ProjectReference> .Empty,
                References        = ImmutableArray <MonoDevelopMetadataReference> .Empty,
                SourceFiles       = ImmutableArray <ProjectFile> .Empty,
            };

            Assert.IsTrue(cacheInfo1.Equals(cacheInfo2));

            var files1 = new FilePath [] {
                "a/.editorconfig",
                "b/.editorconfig"
            };

            cacheInfo1.AdditionalFiles = files1.ToImmutableArray();
            cacheInfo2.AdditionalFiles = files1.ToImmutableArray();
            Assert.IsTrue(cacheInfo1.Equals(cacheInfo2));

            var files2 = new FilePath [] {
                "a/.editorconfig",
                "c/.editorconfig"
            };

            cacheInfo2.AdditionalFiles = files2.ToImmutableArray();
            Assert.IsFalse(cacheInfo1.Equals(cacheInfo2));
        }
 public bool TryGetCachedItems(Project p, MonoDevelopMetadataReferenceManager provider, MonoDevelopWorkspace.ProjectDataMap projectMap,
                               out ProjectCacheInfo info)
 {
     info = new ProjectCacheInfo();
     return(TryGetCachedItems(p, provider, projectMap, out info.SourceFiles, out info.AnalyzerFiles, out info.References, out info.ProjectReferences));
 }
 public void Update(ProjectConfiguration projConfig, Project proj, MonoDevelopWorkspace.ProjectDataMap projectMap, ProjectCacheInfo info)
 {
     Update(projConfig, proj, projectMap, info.SourceFiles, info.AnalyzerFiles, info.References, info.ProjectReferences);
 }
示例#6
0
            async Task <ProjectDocuments> CreateDocuments(ProjectData projectData, MonoDevelop.Projects.Project p, CancellationToken token, ProjectCacheInfo cacheInfo, ProjectData oldProjectData)
            {
                var projectDocuments = new ProjectDocuments();
                var duplicates       = new HashSet <DocumentId> ();

                // use given source files instead of project.Files because there may be additional files added by msbuild targets
                foreach (var f in cacheInfo.SourceFiles)
                {
                    if (token.IsCancellationRequested)
                    {
                        return(null);
                    }
                    if (f.Subtype == MonoDevelop.Projects.Subtype.Directory)
                    {
                        continue;
                    }

                    if (CanCompile(p, f) || CanGenerateAnalysisContextForNonCompileable(p, f))
                    {
                        var filePath = (FilePath)f.Name;
                        var id       = projectData.DocumentData.GetOrCreate(filePath.ResolveLinks(), oldProjectData?.DocumentData);
                        if (!duplicates.Add(id))
                        {
                            continue;
                        }
                        projectDocuments.Documents.Add(CreateDocumentInfo(solutionData, p.Name, projectData, f));
                    }
                    else
                    {
                        foreach (var projectedDocument in await GenerateProjections(f, projectData.DocumentData, p, token, oldProjectData, null))
                        {
                            var projectedId = projectData.DocumentData.GetOrCreate(projectedDocument.FilePath, oldProjectData?.DocumentData);
                            if (!duplicates.Add(projectedId))
                            {
                                continue;
                            }
                            projectDocuments.Documents.Add(projectedDocument);
                        }
                    }
                }

                foreach (var f in cacheInfo.AdditionalFiles)
                {
                    var filePath = f.ResolveLinks();
                    var id       = projectData.DocumentData.GetOrCreate(filePath, oldProjectData?.DocumentData);
                    if (duplicates.Add(id))
                    {
                        projectDocuments.AdditionalDocuments.Add(CreateDocumentInfo(solutionData, p.Name, projectData, filePath, filePath));
                    }
                }

                foreach (var f in cacheInfo.EditorConfigFiles)
                {
                    var filePath = f.ResolveLinks();
                    var id       = projectData.DocumentData.GetOrCreate(filePath, oldProjectData?.DocumentData);
                    if (duplicates.Add(id))
                    {
                        projectDocuments.EditorConfigDocuments.Add(CreateDocumentInfo(solutionData, p.Name, projectData, filePath, filePath));
                    }
                }
                return(projectDocuments);
            }
示例#7
0
            internal async Task <ProjectInfo> LoadProject(
                MonoDevelop.Projects.Project p,
                CancellationToken token,
                MonoDevelop.Projects.Project oldProject,
                ProjectCacheInfo cacheInfo,
                string framework)
            {
                var projectId = projectMap.GetOrCreateId(p, oldProject, framework);

                var config = await GetDotNetProjectConfiguration(p, framework).ConfigureAwait(false);

                MonoDevelop.Projects.DotNetCompilerParameters cp = config?.CompilationParameters;
                FilePath fileName = IdeApp.IsInitialized ? p.GetOutputFileName(IdeApp.Workspace.ActiveConfiguration) : (FilePath)"";

                if (fileName.IsNullOrEmpty)
                {
                    fileName = new FilePath(p.Name + ".dll");
                }

                if (cacheInfo == null)
                {
                    cacheInfo = await LoadProjectCacheInfo(p, config, framework, token).ConfigureAwait(false);

                    if (token.IsCancellationRequested)
                    {
                        return(null);
                    }

                    if (config != null)
                    {
                        workspaceCache.Update(config, framework, p, projectMap, cacheInfo);
                    }
                }

                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                var loader = workspace.Services.GetService <IAnalyzerService> ().GetLoader();

                ProjectData      projectData, oldProjectData;
                ProjectDocuments projectDocuments;

                try {
                    await workspace.LoadLock.WaitAsync().ConfigureAwait(false);

                    //when reloading e.g. after a save, preserve document IDs
                    projectData = projectMap.ReplaceData(projectId, cacheInfo.References, out oldProjectData);

                    projectDocuments = await CreateDocuments(projectData, p, token, cacheInfo, oldProjectData).ConfigureAwait(false);

                    if (projectDocuments == null)
                    {
                        // Restore old document data if cancellation happens here.
                        projectMap.ReplaceData(projectId, oldProjectData, out _);
                        return(null);
                    }
                } finally {
                    workspace.LoadLock.Release();
                }

                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                IEnumerable <DocumentInfo> documents = projectDocuments.Documents;
                var virtualDocuments = workspace.GetVirtualDocuments(projectId);

                if (virtualDocuments.Any())
                {
                    documents = documents.Concat(virtualDocuments);
                }

                // TODO: Pass in the WorkspaceMetadataFileReferenceResolver
                var info = ProjectInfo.Create(
                    projectId,
                    GetVersionStamp(p),
                    GetProjectInfoName(p.Name, framework),
                    fileName.FileNameWithoutExtension,
                    (p as MonoDevelop.Projects.DotNetProject)?.RoslynLanguageName ?? LanguageNames.CSharp,
                    p.FileName,
                    fileName,
                    null,                     // outputRefPath
                    null,                     // defaultNamespace
                    cp?.CreateCompilationOptions(),
                    cp?.CreateParseOptions(config),
                    documents,
                    cacheInfo.ProjectReferences,
                    cacheInfo.References.Select(x => x.CurrentSnapshot),
                    analyzerReferences: cacheInfo.AnalyzerFiles.SelectAsArray(x => {
                    var analyzer = new MonoDevelopAnalyzer(x, hostDiagnosticUpdateSource.Value, projectId, workspace, loader, LanguageNames.CSharp);
                    analyzersToDispose.Add(analyzer);
                    return(analyzer.GetReference());
                }),
                    analyzerConfigDocuments: projectDocuments.EditorConfigDocuments,
                    additionalDocuments: projectDocuments.AdditionalDocuments,
                    isSubmission: false,
                    hostObjectType: null,
                    hasAllInformation: true
                    );

                info = workspace.WithDynamicDocuments(p, info);

                return(info);
            }
示例#8
0
            internal async Task <ProjectInfo> LoadProject(MonoDevelop.Projects.Project p, CancellationToken token, MonoDevelop.Projects.Project oldProject, ProjectCacheInfo cacheInfo)
            {
                var projectId = projectMap.GetOrCreateId(p, oldProject);

                var config = GetDotNetProjectConfiguration(p);

                MonoDevelop.Projects.DotNetCompilerParameters cp = config?.CompilationParameters;
                FilePath fileName = IdeApp.IsInitialized ? p.GetOutputFileName(IdeApp.Workspace.ActiveConfiguration) : (FilePath)"";

                if (fileName.IsNullOrEmpty)
                {
                    fileName = new FilePath(p.Name + ".dll");
                }

                if (cacheInfo == null)
                {
                    cacheInfo = await LoadProjectCacheInfo(p, config, token).ConfigureAwait(false);

                    if (token.IsCancellationRequested)
                    {
                        return(null);
                    }

                    if (config != null)
                    {
                        workspaceCache.Update(config, p, projectMap, cacheInfo);
                    }
                }

                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                var loader = workspace.Services.GetService <IAnalyzerService> ().GetLoader();

                ProjectData         projectData, oldProjectData;
                List <DocumentInfo> mainDocuments, additionalDocuments;

                try {
                    await workspace.LoadLock.WaitAsync().ConfigureAwait(false);

                    //when reloading e.g. after a save, preserve document IDs
                    oldProjectData = projectMap.RemoveData(projectId);
                    projectData    = projectMap.CreateData(projectId, cacheInfo.References);

                    var documents = await CreateDocuments(projectData, p, token, cacheInfo.SourceFiles, oldProjectData).ConfigureAwait(false);

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

                    mainDocuments       = documents.Item1;
                    additionalDocuments = documents.Item2;
                } finally {
                    workspace.LoadLock.Release();
                }

                // TODO: Pass in the WorkspaceMetadataFileReferenceResolver
                var info = ProjectInfo.Create(
                    projectId,
                    GetVersionStamp(p),
                    p.Name,
                    fileName.FileNameWithoutExtension,
                    (p as MonoDevelop.Projects.DotNetProject)?.RoslynLanguageName ?? LanguageNames.CSharp,
                    p.FileName,
                    fileName,
                    cp?.CreateCompilationOptions(),
                    cp?.CreateParseOptions(config),
                    mainDocuments,
                    cacheInfo.ProjectReferences,
                    cacheInfo.References.Select(x => x.CurrentSnapshot),
                    analyzerReferences: cacheInfo.AnalyzerFiles.SelectAsArray(x => {
                    var analyzer = new MonoDevelopAnalyzer(x, hostDiagnosticUpdateSource.Value, projectId, workspace, loader, LanguageNames.CSharp);
                    analyzersToDispose.Add(analyzer);
                    return(analyzer.GetReference());
                }),
                    additionalDocuments: additionalDocuments
                    );

                return(info);
            }
        public bool TryGetCachedItems(Project p, MonoDevelopMetadataReferenceManager provider, MonoDevelopWorkspace.ProjectDataMap projectMap, string framework,
                                      out ProjectCacheInfo info)
        {
            info = new ProjectCacheInfo();

            List <ProjectCache> cachedDataList;

            lock (cachedItems) {
                if (!cachedItems.TryGetValue(p.FileName, out cachedDataList))
                {
                    return(false);
                }
            }

            ProjectCache cachedData = cachedDataList.FirstOrDefault(cache => cache.Framework == framework);

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

            var filesBuilder = ImmutableArray.CreateBuilder <ProjectFile> (cachedData.Files.Length);

            for (int i = 0; i < cachedData.Files.Length; ++i)
            {
                filesBuilder.Add(new ProjectFile(cachedData.Files [i], cachedData.BuildActions [i])
                {
                    Project = p,
                });
            }

            info.SourceFiles = filesBuilder.MoveToImmutable();

            info.AdditionalFiles   = ToImmutableFilePathArray(cachedData.AdditionalFiles);
            info.AnalyzerFiles     = ToImmutableFilePathArray(cachedData.Analyzers);
            info.EditorConfigFiles = ToImmutableFilePathArray(cachedData.EditorConfigFiles);

            var mrBuilder = ImmutableArray.CreateBuilder <MonoDevelopMetadataReference> (cachedData.MetadataReferences.Length);

            foreach (var item in cachedData.MetadataReferences)
            {
                var aliases = item.Aliases != null?item.Aliases.ToImmutableArray() : default;

                var reference = provider.GetOrCreateMetadataReference(item.FilePath, new Microsoft.CodeAnalysis.MetadataReferenceProperties(aliases: aliases));
                mrBuilder.Add(reference);
            }
            info.References = mrBuilder.MoveToImmutable();

            var sol         = p.ParentSolution;
            var solConfig   = sol.GetConfiguration(IdeServices.Workspace.ActiveConfiguration);
            var allProjects = sol.GetAllProjects().ToDictionary(x => x.FileName, x => x);

            var prBuilder = ImmutableArray.CreateBuilder <Microsoft.CodeAnalysis.ProjectReference> (cachedData.ProjectReferences.Length);

            foreach (var item in cachedData.ProjectReferences)
            {
                if (!allProjects.TryGetValue(item.FilePath, out var mdProject))
                {
                    return(false);
                }

                var aliases = item.Aliases != null?item.Aliases.ToImmutableArray() : default;

                var pr = new Microsoft.CodeAnalysis.ProjectReference(projectMap.GetOrCreateId(mdProject, null, item.Framework), aliases.ToImmutableArray());
                prBuilder.Add(pr);
            }
            info.ProjectReferences = prBuilder.MoveToImmutable();
            return(true);
        }
示例#10
0
        public void Update(ProjectConfiguration projConfig, string framework, Project proj, MonoDevelopWorkspace.ProjectDataMap projectMap, ProjectCacheInfo info)
        {
            if (!loaded)
            {
                return;
            }

            var paths   = new string [info.SourceFiles.Length];
            var actions = new string [info.SourceFiles.Length];

            for (int i = 0; i < info.SourceFiles.Length; ++i)
            {
                paths [i]   = info.SourceFiles [i].FilePath;
                actions [i] = info.SourceFiles [i].BuildAction;
            }

            var projectRefs = new ReferenceItem [info.ProjectReferences.Length];

            for (int i = 0; i < info.ProjectReferences.Length; ++i)
            {
                var pr = info.ProjectReferences [i];
                (Project mdProject, string projectReferenceFramework) = projectMap.GetMonoProjectAndFramework(pr.ProjectId);
                projectRefs [i] = new ReferenceItem {
                    FilePath  = mdProject.FileName,
                    Aliases   = pr.Aliases.ToArray(),
                    Framework = projectReferenceFramework
                };
            }

            var item = new ProjectCache {
                Format             = format,
                AdditionalFiles    = info.AdditionalFiles.Select(x => (string)x).ToArray(),
                Analyzers          = info.AnalyzerFiles.Select(x => (string)x).ToArray(),
                EditorConfigFiles  = info.EditorConfigFiles.Select(x => (string)x).ToArray(),
                Files              = paths,
                BuildActions       = actions,
                MetadataReferences = info.References.Select(x => {
                    var ri = new ReferenceItem {
                        FilePath = x.FilePath,
                        Aliases  = x.Properties.Aliases.ToArray(),
                    };
                    return(ri);
                }).ToArray(),
                ProjectReferences = projectRefs,
            };

            string configId  = GetConfigId(projConfig);
            var    cacheFile = GetProjectCacheFile(proj, configId, framework);

            WriteCacheFile(item, cacheFile);
        }