diff --git a/NuGet.Config b/NuGet.Config index ddbd220b53..b6f538d609 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -7,6 +7,7 @@ + diff --git a/src/OmniSharp.Host/Program.cs b/src/OmniSharp.Host/Program.cs index 7c20d38acb..47bca6edb8 100644 --- a/src/OmniSharp.Host/Program.cs +++ b/src/OmniSharp.Host/Program.cs @@ -86,6 +86,23 @@ public static void Main(string[] args) } } +#if NET46 + if (PlatformHelper.IsMono) + { + // Mono uses ThreadPool threads for its async/await implementation. + // Ensure we have an acceptable lower limit on the threadpool size to avoid deadlocks and ThreadPool starvation. + const int MIN_WORKER_THREADS = 8; + + int currentWorkerThreads, currentCompletionPortThreads; + System.Threading.ThreadPool.GetMinThreads(out currentWorkerThreads, out currentCompletionPortThreads); + + if (currentWorkerThreads < MIN_WORKER_THREADS) + { + System.Threading.ThreadPool.SetMinThreads(MIN_WORKER_THREADS, currentCompletionPortThreads); + } + } +#endif + Environment = new OmnisharpEnvironment(applicationRoot, serverPort, hostPID, logLevel, transportType, otherArgs.ToArray()); var config = new ConfigurationBuilder() diff --git a/src/OmniSharp.Host/project.json b/src/OmniSharp.Host/project.json index 3c81094f77..e20266c203 100644 --- a/src/OmniSharp.Host/project.json +++ b/src/OmniSharp.Host/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "OmniSharp.Abstractions": "1.0.0", - "OmniSharp.Nuget": "1.0.0", "OmniSharp.Stdio": "1.0.0", "OmniSharp.Plugins": "1.0.0", "OmniSharp.Roslyn": "1.0.0", diff --git a/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs b/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs index 0e6037dcda..4fb45491c4 100644 --- a/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs +++ b/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs @@ -180,6 +180,8 @@ private ProjectFileInfo AddProject(string filePath) return null; } + _logger.LogInformation($"Add project: {fileInfo.ProjectFilePath}"); + _projects.Add(fileInfo); var compilationOptions = CreateCompilationOptions(fileInfo); @@ -211,6 +213,24 @@ private static CSharpCompilationOptions CreateCompilationOptions(ProjectFileInfo result = result.WithAllowUnsafe(true); } + var specificDiagnosticOptions = new Dictionary(projectFileInfo.SuppressedDiagnosticIds.Count); + + // Always suppress CS1701 (Assuming assembly reference 'x' used by 'y' matches identity 'z'. you may need to supply runtime policy) + specificDiagnosticOptions.Add("CS1701", ReportDiagnostic.Suppress); + + if (projectFileInfo.SuppressedDiagnosticIds.Any()) + { + foreach (var id in projectFileInfo.SuppressedDiagnosticIds) + { + if (!specificDiagnosticOptions.ContainsKey(id)) + { + specificDiagnosticOptions.Add(id, ReportDiagnostic.Suppress); + } + } + } + + result = result.WithSpecificDiagnosticOptions(specificDiagnosticOptions); + if (projectFileInfo.SignAssembly && !string.IsNullOrEmpty(projectFileInfo.AssemblyOriginatorKeyFile)) { var keyFile = Path.Combine(projectFileInfo.ProjectDirectory, projectFileInfo.AssemblyOriginatorKeyFile); @@ -330,7 +350,13 @@ private void UpdateSourceFiles(Project project, IList sourceFiles) continue; } - // If not, add a new document. + // If the source file doesn't exist on disk, don't try to add it. + if (!File.Exists(sourceFile)) + { + continue; + } + + // If all is OK, add a new document. using (var stream = File.OpenRead(sourceFile)) { var sourceText = SourceText.From(stream, encoding: Encoding.UTF8); @@ -379,7 +405,10 @@ private void UpdateParseOptions(Project project, LanguageVersion languageVersion private void UpdateProjectReferences(Project project, IList projectReferences) { + _logger.LogInformation($"Update project: {project.Name}"); + var existingProjectReferences = new HashSet(project.ProjectReferences); + var addedProjectReferences = new HashSet(); foreach (var projectReference in projectReferences) { @@ -394,7 +423,11 @@ private void UpdateProjectReferences(Project project, IList projectRefer continue; } - _workspace.AddProjectReference(project.Id, reference); + if (!addedProjectReferences.Contains(reference)) + { + _workspace.AddProjectReference(project.Id, reference); + addedProjectReferences.Add(reference); + } } else { @@ -411,6 +444,7 @@ private void UpdateProjectReferences(Project project, IList projectRefer private void UpdateReferences(Project project, IList references) { var existingReferences = new HashSet(project.MetadataReferences); + var addedReferences = new HashSet(); foreach (var referencePath in references) { @@ -427,8 +461,12 @@ private void UpdateReferences(Project project, IList references) continue; } - _logger.LogDebug($"Adding reference '{referencePath}' to '{project.Name}'."); - _workspace.AddMetadataReference(project.Id, metadataReference); + if (!addedReferences.Contains(metadataReference)) + { + _logger.LogDebug($"Adding reference '{referencePath}' to '{project.Name}'."); + _workspace.AddMetadataReference(project.Id, metadataReference); + addedReferences.Add(metadataReference); + } } } diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.PropertyNames.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.PropertyNames.cs index 4b0a8c8f75..fdd90672f4 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.PropertyNames.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.PropertyNames.cs @@ -14,12 +14,14 @@ private static class PropertyNames public const string LangVersion = nameof(LangVersion); public const string OutputType = nameof(OutputType); public const string MSBuildExtensionsPath = nameof(MSBuildExtensionsPath); + public const string NoWarn = nameof(NoWarn); public const string ProjectGuid = nameof(ProjectGuid); public const string ProjectName = nameof(ProjectName); public const string _ResolveReferenceDependencies = nameof(_ResolveReferenceDependencies); public const string SignAssembly = nameof(SignAssembly); public const string SolutionDir = nameof(SolutionDir); public const string TargetFrameworkMoniker = nameof(TargetFrameworkMoniker); + public const string TargetFrameworkRootPath = nameof(TargetFrameworkRootPath); public const string TargetPath = nameof(TargetPath); public const string VisualStudioVersion = nameof(VisualStudioVersion); } diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs index b970bf0012..5a4ac08e49 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs @@ -30,6 +30,7 @@ public partial class ProjectFileInfo public string AssemblyOriginatorKeyFile { get; } public bool GenerateXmlDocumentation { get; } public IList PreprocessorSymbolNames { get; } + public IList SuppressedDiagnosticIds { get; } public IList SourceFiles { get; } public IList References { get; } @@ -55,6 +56,7 @@ private ProjectFileInfo( string assemblyOriginatorKeyFile, bool generateXmlDocumentation, IList defineConstants, + IList suppressedDiagnosticIds, IList sourceFiles, IList references, IList projectReferences, @@ -73,6 +75,7 @@ private ProjectFileInfo( this.AssemblyOriginatorKeyFile = assemblyOriginatorKeyFile; this.GenerateXmlDocumentation = generateXmlDocumentation; this.PreprocessorSymbolNames = defineConstants; + this.SuppressedDiagnosticIds = suppressedDiagnosticIds; this.SourceFiles = sourceFiles; this.References = references; this.ProjectReferences = projectReferences; @@ -101,13 +104,6 @@ public static ProjectFileInfo Create( return null; } -#if NET46 - if (PlatformHelper.IsMono) - { - return CreateForMono(projectFilePath, solutionDirectory, options, logger, diagnostics); - } -#endif - var globalProperties = new Dictionary { { PropertyNames.DesignTimeBuild, "true" }, @@ -120,6 +116,15 @@ public static ProjectFileInfo Create( { globalProperties.Add(PropertyNames.MSBuildExtensionsPath, options.MSBuildExtensionsPath); } + else + { + globalProperties.Add(PropertyNames.MSBuildExtensionsPath, AppContext.BaseDirectory); + } + + if (PlatformHelper.IsMono) + { + globalProperties.Add(PropertyNames.TargetFrameworkRootPath, "/Library/Frameworks/Mono.framework/Libraries/mono/xbuild-frameworks"); + } if (!string.IsNullOrWhiteSpace(options.VisualStudioVersion)) { @@ -128,12 +133,12 @@ public static ProjectFileInfo Create( var collection = new ProjectCollection(globalProperties); - logger.LogInformation($"Using toolset {options.ToolsVersion ?? collection.DefaultToolsVersion} for '{projectFilePath}'"); - var project = string.IsNullOrEmpty(options.ToolsVersion) ? collection.LoadProject(projectFilePath) : collection.LoadProject(projectFilePath, options.ToolsVersion); + logger.LogInformation($"Using tools version: {project.ToolsVersion}"); + var projectInstance = project.CreateProjectInstance(); var buildResult = projectInstance.Build(TargetNames.ResolveReferences, new[] { new MSBuildLogForwarder(logger, diagnostics) }); @@ -155,6 +160,7 @@ public static ProjectFileInfo Create( var assemblyOriginatorKeyFile = projectInstance.GetPropertyValue(PropertyNames.AssemblyOriginatorKeyFile); var documentationFile = projectInstance.GetPropertyValue(PropertyNames.DocumentationFile); var defineConstants = PropertyConverter.ToDefineConstants(projectInstance.GetPropertyValue(PropertyNames.DefineConstants)); + var noWarn = PropertyConverter.ToSuppressDiagnostics(projectInstance.GetPropertyValue(PropertyNames.NoWarn)); var sourceFiles = projectInstance .GetItems(ItemNames.Compile) @@ -180,8 +186,8 @@ public static ProjectFileInfo Create( return new ProjectFileInfo( projectFilePath, assemblyName, name, targetFramework, specifiedLanguageVersion, projectGuid, targetPath, allowUnsafe, outputKind, signAssembly, assemblyOriginatorKeyFile, - !string.IsNullOrWhiteSpace(documentationFile), defineConstants, sourceFiles, references, - projectReferences, analyzers); + !string.IsNullOrWhiteSpace(documentationFile), defineConstants, noWarn, + sourceFiles, references, projectReferences, analyzers); } private static bool ReferenceSourceTargetIsProjectReference(ProjectItemInstance projectItem) diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo_Mono.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo_Mono.cs deleted file mode 100644 index 41e53176e5..0000000000 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo_Mono.cs +++ /dev/null @@ -1,138 +0,0 @@ -#if NET46 - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Versioning; -using Microsoft.Build.BuildEngine; -using Microsoft.CodeAnalysis; -using Microsoft.Extensions.Logging; -using OmniSharp.Models; -using OmniSharp.Options; - -namespace OmniSharp.MSBuild.ProjectFile -{ - public partial class ProjectFileInfo - { - private static ProjectFileInfo CreateForMono( - string projectFilePath, - string solutionDirectory, - MSBuildOptions options, - ILogger logger, - ICollection diagnostics) - { - // On mono we need to use this API since the ProjectCollection - // isn't fully implemented -#pragma warning disable CS0618 - var engine = Engine.GlobalEngine; - engine.DefaultToolsVersion = "4.0"; -#pragma warning restore CS0618 - - // engine.RegisterLogger(new ConsoleLogger()); - engine.RegisterLogger(new MSBuildLogForwarder(logger, diagnostics)); - - var globalProperties = new BuildPropertyGroup(); - globalProperties.SetProperty(PropertyNames.DesignTimeBuild, value: true); - globalProperties.SetProperty(PropertyNames.BuildProjectReferences, value: false); - // Dump entire assembly reference closure - globalProperties.SetProperty(PropertyNames._ResolveReferenceDependencies, value: true); - globalProperties.SetProperty(PropertyNames.SolutionDir, solutionDirectory + Path.DirectorySeparatorChar); - - // propertyGroup.SetProperty("MSBUILDENABLEALLPROPERTYFUNCTIONS", "1"); - - engine.GlobalProperties = globalProperties; - - var project = engine.CreateNewProject(); - project.Load(projectFilePath); - - var buildResult = engine.BuildProjectFile( - projectFilePath, - targetNames: new[] { TargetNames.ResolveReferences }, - globalProperties: globalProperties, - targetOutputs: null, - buildFlags: BuildSettings.None, - toolsVersion: null); - - if (!buildResult) - { - return null; - } - - var items = project.EvaluatedItems - .OfType() - .ToLookup(g => g.Name); - - var properties = project.EvaluatedProperties - .OfType() - .ToDictionary(p => p.Name); - - var assemblyName = properties.GetFinalValue(PropertyNames.AssemblyName); - var name = Path.GetFileNameWithoutExtension(projectFilePath); - - var targetFrameworkMoniker = properties.GetFinalValue(PropertyNames.TargetFrameworkMoniker); - var targetFramework = targetFrameworkMoniker != null - ? new FrameworkName(targetFrameworkMoniker) - : null; - - var langVersion = PropertyConverter.ToLanguageVersion(properties.GetFinalValue(PropertyNames.LangVersion)); - var projectGuid = PropertyConverter.ToGuid(properties.GetFinalValue(PropertyNames.ProjectGuid)); - var targetPath = properties.GetFinalValue(PropertyNames.TargetPath); - var allowUnsafe = PropertyConverter.ToBoolean(properties.GetFinalValue(PropertyNames.AllowUnsafeBlocks), defaultValue: false); - var signAssembly = PropertyConverter.ToBoolean(properties.GetFinalValue(PropertyNames.SignAssembly), defaultValue: false); - var assemblyOriginatorKeyFile = properties.GetFinalValue(PropertyNames.AssemblyOriginatorKeyFile); - var documentationFile = properties.GetFinalValue(PropertyNames.DocumentationFile); - var defineConstants = PropertyConverter.ToDefineConstants(properties.GetFinalValue(PropertyNames.DefineConstants)); - - var projectDirectory = Path.GetDirectoryName(projectFilePath); - - // REVIEW: FullPath metadata value returns the wrong physical path. We need to figure out why. - // Are we setting up something incorrectly? - var sourceFiles = items[ItemNames.Compile] - .Select(item => GetFullPath(item, projectDirectory)) - .ToList(); - - var references = items[ItemNames.ReferencePath] - .Where(item => !item.HasMetadata(MetadataNames.Project)) - .Select(item => GetFullPath(item, projectDirectory)) - .ToList(); - - var projectReferences = items[ItemNames.ProjectReference] - .Select(item => GetFullPath(item, projectDirectory)) - .ToList(); - - var analyzers = items[ItemNames.Analyzer] - .Select(item => GetFullPath(item, projectDirectory)) - .ToList(); - - return new ProjectFileInfo( - projectFilePath, assemblyName, name, targetFramework, langVersion, - projectGuid, targetPath, allowUnsafe, OutputKind.ConsoleApplication, signAssembly, assemblyOriginatorKeyFile, - !string.IsNullOrWhiteSpace(documentationFile), defineConstants, sourceFiles, references, - projectReferences, analyzers); - } - - private static string GetFullPath(BuildItem item, string projectDirectory) - { - return Path.GetFullPath(Path.Combine(projectDirectory, item.FinalItemSpec)); - } - } - - internal static class BuildEngineExtensions - { - public static void SetProperty(this BuildPropertyGroup buildPropertyGroup, string name, bool value) - { - buildPropertyGroup.SetProperty(name, value ? "true" : "false"); - } - - public static string GetFinalValue(this Dictionary dictionary, string key) - { - BuildProperty buildProperty; - - return dictionary.TryGetValue(key, out buildProperty) - ? buildProperty.FinalValue - : null; - } - } -} - -#endif diff --git a/src/OmniSharp.MSBuild/ProjectFile/PropertyConverter.cs b/src/OmniSharp.MSBuild/ProjectFile/PropertyConverter.cs index 2382fecc63..ecdcc378b0 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/PropertyConverter.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/PropertyConverter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -71,11 +72,35 @@ public static IList ToDefineConstants(string propertyValue) return new string[0]; } - var values = propertyValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + var values = propertyValue.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries); return new SortedSet(values).ToArray(); } + public static IList ToSuppressDiagnostics(string propertyValue) + { + if (string.IsNullOrWhiteSpace(propertyValue)) + { + return new string[0]; + } + + // Remove quotes + propertyValue = propertyValue.Trim('"'); + var values = propertyValue.Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); + var result = new SortedSet(); + + foreach (var id in values) + { + ushort number; + if (ushort.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out number)) + { + result.Add("CS" + number.ToString("0000")); + } + } + + return result.ToArray(); + } + public static Guid ToGuid(string propertyValue) { Guid result; diff --git a/src/OmniSharp.MSBuild/UnityHelper.cs b/src/OmniSharp.MSBuild/UnityHelper.cs index 258e7d8b52..ec5cba7f51 100644 --- a/src/OmniSharp.MSBuild/UnityHelper.cs +++ b/src/OmniSharp.MSBuild/UnityHelper.cs @@ -1,7 +1,6 @@ using System; using System.Security.Cryptography; using System.Text; -using Microsoft.CodeAnalysis.MSBuild; namespace OmniSharp.MSBuild { diff --git a/src/OmniSharp.MSBuild/project.json b/src/OmniSharp.MSBuild/project.json index 44dca97d0b..b68aaccf1c 100644 --- a/src/OmniSharp.MSBuild/project.json +++ b/src/OmniSharp.MSBuild/project.json @@ -6,29 +6,19 @@ "dependencies": { "OmniSharp.Abstractions": "1.0.0", "OmniSharp.Roslyn.CSharp": "1.0.0", - "Microsoft.Extensions.Options": "1.0.0" + "Microsoft.Extensions.Options": "1.0.0", + "Microsoft.Build": "15.1.319-preview5", + "Microsoft.Build.Framework": "15.1.319-preview5", + "Microsoft.Build.Tasks.Core": "15.1.319-preview5", + "Microsoft.Build.Utilities.Core": "15.1.319-preview5", + "System.Threading.Tasks.Dataflow": "4.6.0" }, "frameworks": { - "net46": { - "frameworkAssemblies": { - "Microsoft.Build": "", - "Microsoft.Build.Engine": "", - "Microsoft.Build.Framework": "" - } - }, + "net46": {}, "netstandard1.6": { "imports": [ "portable-net45+win8" - ], - "dependencies": { - "MSBuild": "0.1.0-preview-00038-160914", - "Microsoft.Build": "0.1.0-preview-00038-160914", - "Microsoft.Build.Framework": "0.1.0-preview-00038-160914", - "Microsoft.Build.Targets": "0.1.0-preview-00038-160914", - "Microsoft.Build.Tasks.Core": "0.1.0-preview-00038-160914", - "Microsoft.Build.Utilities.Core": "0.1.0-preview-00038-160914", - "Microsoft.Net.Compilers": "2.0.0-rc" - } + ] } } } \ No newline at end of file diff --git a/src/OmniSharp/Microsoft.CSharp.Core.targets b/src/OmniSharp/Microsoft.CSharp.Core.targets old mode 100755 new mode 100644 index 3dd84b9f7d..14d100b653 --- a/src/OmniSharp/Microsoft.CSharp.Core.targets +++ b/src/OmniSharp/Microsoft.CSharp.Core.targets @@ -1,144 +1,152 @@ - - - - - $(NoWarn);1701;1702 - - - - - $(NoWarn);2008 - - - - - - - - - - - $(AppConfig) - - - $(IntermediateOutputPath)$(TargetName).compile.pdb - - - - - false - - - - - - - - - true - - - - - - - - - <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" /> - - - - - + + + + + $(NoWarn);1701;1702 + + + + + $(NoWarn);2008 + + + + + + + + + + + $(AppConfig) + + + $(IntermediateOutputPath)$(TargetName).compile.pdb + + + + + false + + + + + + + + + + true + + + + + + + + + <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" /> + + + + + diff --git a/src/OmniSharp/project.json b/src/OmniSharp/project.json index 27e90300eb..b52f6f5094 100644 --- a/src/OmniSharp/project.json +++ b/src/OmniSharp/project.json @@ -17,21 +17,19 @@ "OmniSharp.Roslyn.CSharp": "1.0.0", "OmniSharp.DotNet": "1.0.0", "OmniSharp.DotNetTest": "1.0.0", - "OmniSharp.MSBuild": "1.0.0" + "OmniSharp.MSBuild": "1.0.0", + "Microsoft.Build.Runtime": "15.1.319-preview5" }, "frameworks": { - "net46": { - "dependencies": { - "OmniSharp.ScriptCs": "1.0.0" - } - }, + "net46": { }, "netcoreapp1.0": { "imports": [ "dotnet5.4", "portable-net45+win8" ], "dependencies": { - "Microsoft.NETCore.App": "1.0.1" + "Microsoft.NETCore.App": "1.0.1", + "System.Runtime": "4.1.0" } } }, diff --git a/tests/OmniSharp.MSBuild.Tests/project.json b/tests/OmniSharp.MSBuild.Tests/project.json index 83258667c4..4f7197d0a3 100644 --- a/tests/OmniSharp.MSBuild.Tests/project.json +++ b/tests/OmniSharp.MSBuild.Tests/project.json @@ -20,6 +20,7 @@ "version": "1.0.1", "type": "platform" }, + "System.Runtime": "4.1.0", "dotnet-test-xunit": "2.2.0-preview2-build1029" } }