/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpProjectShim.ICSharpProjectSite.cs
177 строк
7 KB
Cyrus Najmabadi
Use file scoped namespaces. (#77854)
27 мар 2025, 09:55
Не верифицирован
27 мар 2025, 09:55
98d41b8
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim; internal partial class CSharpProjectShim : ICSharpProjectSite { /// <summary> /// When the project property page calls GetValidStartupClasses on us, it assumes /// the strings passed to it are in the native C# language service's string table /// and never frees them. To avoid leaking our strings, we allocate them on the /// native heap for each call and keep the pointers here. On subsequent calls /// or on disposal, we free the old strings before allocating the new ones. /// </summary> private IntPtr[]? _startupClasses = null; public void GetCompiler(out ICSCompiler compiler, out ICSInputSet inputSet) { compiler = this; inputSet = this; } public bool CheckInputFileTimes(System.Runtime.InteropServices.ComTypes.FILETIME output) => throw new NotImplementedException(); public void BuildProject(object progress) => throw new NotImplementedException(); public void Unused() => throw new NotImplementedException(); public void OnSourceFileAdded(string filename) { // TODO: uncomment when fixing https://github.com/dotnet/roslyn/issues/5325 //var sourceCodeKind = extension.Equals(".csx", StringComparison.OrdinalIgnoreCase) // ? SourceCodeKind.Script // : SourceCodeKind.Regular; AddFile(filename, SourceCodeKind.Regular); } public void OnSourceFileRemoved(string filename) => RemoveFile(filename); public int OnResourceFileAdded(string filename, string resourceName, bool embedded) => VSConstants.S_OK; public int OnResourceFileRemoved(string filename) => VSConstants.S_OK; public int OnImportAdded(string filename, string project) { // OnImportAdded is superseded by OnImportAddedEx. We maintain back-compat by treating // it as a non-NoPIA reference. return OnImportAddedEx(filename, project, CompilerOptions.OPTID_IMPORTS); } public int OnImportAddedEx(string filename, string project, CompilerOptions optionID) { if (optionID is not CompilerOptions.OPTID_IMPORTS and not CompilerOptions.OPTID_IMPORTSUSINGNOPIA) { throw new ArgumentException("optionID was an unexpected value.", nameof(optionID)); } var embedInteropTypes = optionID == CompilerOptions.OPTID_IMPORTSUSINGNOPIA; ProjectSystemProject.AddMetadataReference(filename, new MetadataReferenceProperties(embedInteropTypes: embedInteropTypes)); return VSConstants.S_OK; } public void OnImportRemoved(string filename, string project) { filename = FileUtilities.NormalizeAbsolutePath(filename); ProjectSystemProject.RemoveMetadataReference(filename, properties: ProjectSystemProject.GetPropertiesForMetadataReference(filename).Single()); } public void OnOutputFileChanged(string filename) { // We have nothing to do here } public void OnActiveConfigurationChanged(string configName) { // We have nothing to do here } public void OnProjectLoadCompletion() { // Despite the name, this is not necessarily called when the project has actually been // completely loaded. If you plan on using this, be careful! } public int CreateCodeModel(object parent, out EnvDTE.CodeModel codeModel) { codeModel = ProjectCodeModel.GetOrCreateRootCodeModel((EnvDTE.Project)parent); return VSConstants.S_OK; } public int CreateFileCodeModel(string fileName, object parent, out EnvDTE.FileCodeModel ppFileCodeModel) { ppFileCodeModel = ProjectCodeModel.GetOrCreateFileCodeModel(fileName, parent); return VSConstants.S_OK; } public void OnModuleAdded(string filename) => throw new NotImplementedException(); public void OnModuleRemoved(string filename) => throw new NotImplementedException(); public int GetValidStartupClasses(IntPtr[] classNames, ref int count) { var (result, newCount) = this.ThreadingContext.JoinableTaskFactory.Run(GetValidStartupClassesAsync); if (newCount.HasValue) count = newCount.Value; return result; async Task<(int result, int? newCount)> GetValidStartupClassesAsync() { var project = Workspace.CurrentSolution.GetRequiredProject(ProjectSystemProject.Id); var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None).ConfigureAwait(true); var entryPoints = CSharpEntryPointFinder.FindEntryPoints(compilation); // If classNames is NULL, then we need to populate the number of valid startup // classes only if (classNames == null) { return (VSConstants.S_OK, entryPoints.Count()); } else { // We return S_FALSE if we have more entrypoints than places in the array. var entryPointNames = entryPoints.Select(e => e.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))).ToArray(); if (entryPointNames.Length > classNames.Length) return (VSConstants.S_FALSE, null); // The old language service stored startup class names in its string table, // so the property page never freed them. To avoid leaking memory, we're // going to allocate our strings on the native heap and keep the pointers to them. // Subsequent calls to this function will free the old strings and allocate the // new ones. The last set of marshalled strings is freed in the destructor. if (_startupClasses != null) { foreach (var @class in _startupClasses) Marshal.FreeHGlobal(@class); } _startupClasses = [.. entryPointNames.Select(Marshal.StringToHGlobalUni)]; Array.Copy(_startupClasses, classNames, _startupClasses.Length); return (VSConstants.S_OK, entryPointNames.Length); } } } public void OnAliasesChanged(string file, string project, int previousAliasesCount, string[] previousAliases, int currentAliasesCount, string[] currentAliases) { using (ProjectSystemProject.CreateBatchScope()) { var existingProperties = ProjectSystemProject.GetPropertiesForMetadataReference(file).Single(); ProjectSystemProject.RemoveMetadataReference(file, existingProperties); ProjectSystemProject.AddMetadataReference(file, existingProperties.WithAliases(currentAliases)); } } }