diff --git a/build/Packages.props b/build/Packages.props
index 029f591b78..b0f753faac 100644
--- a/build/Packages.props
+++ b/build/Packages.props
@@ -4,7 +4,7 @@
16.0.461
5.0.0
- 3.2.0-beta4-19326-12
+ 3.3.0-beta2-19376-02
2.4.0
diff --git a/src/OmniSharp.Abstractions/Configuration.cs b/src/OmniSharp.Abstractions/Configuration.cs
index 7e0f2eab0c..56664e7a37 100644
--- a/src/OmniSharp.Abstractions/Configuration.cs
+++ b/src/OmniSharp.Abstractions/Configuration.cs
@@ -4,7 +4,7 @@ internal static class Configuration
{
public static bool ZeroBasedIndices = false;
- public const string RoslynVersion = "3.2.0.0";
+ public const string RoslynVersion = "3.3.0.0";
public const string RoslynPublicKeyToken = "31bf3856ad364e35";
public readonly static string RoslynFeatures = GetRoslynAssemblyFullName("Microsoft.CodeAnalysis.Features");
diff --git a/src/OmniSharp.Http.Driver/app.config b/src/OmniSharp.Http.Driver/app.config
index ff336a2a60..aedd66b2a7 100644
--- a/src/OmniSharp.Http.Driver/app.config
+++ b/src/OmniSharp.Http.Driver/app.config
@@ -7,15 +7,15 @@
-
+
-
+
-
+
diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs
index 585622530c..1920cb64a1 100644
--- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs
+++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs
@@ -51,6 +51,7 @@ private class ProjectData
public RuleSet RuleSet { get; }
public ImmutableDictionary ReferenceAliases { get; }
public bool TreatWarningsAsErrors { get; }
+ public string DefaultNamespace { get; }
private ProjectData()
{
@@ -85,6 +86,7 @@ private ProjectData(
bool signAssembly,
string assemblyOriginatorKeyFile,
bool treatWarningsAsErrors,
+ string defaultNamespace,
RuleSet ruleset)
: this()
{
@@ -114,6 +116,7 @@ private ProjectData(
AssemblyOriginatorKeyFile = assemblyOriginatorKeyFile;
TreatWarningsAsErrors = treatWarningsAsErrors;
RuleSet = ruleset;
+ DefaultNamespace = defaultNamespace;
}
private ProjectData(
@@ -139,11 +142,12 @@ private ProjectData(
ImmutableArray analyzers,
ImmutableArray additionalFiles,
bool treatWarningsAsErrors,
+ string defaultNamespace,
RuleSet ruleset,
ImmutableDictionary referenceAliases)
: this(guid, name, assemblyName, targetPath, outputPath, intermediateOutputPath, projectAssetsFile,
configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode,
- documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, ruleset)
+ documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, ruleset)
{
SourceFiles = sourceFiles.EmptyIfDefault();
ProjectReferences = projectReferences.EmptyIfDefault();
@@ -165,6 +169,7 @@ public static ProjectData Create(MSB.Evaluation.Project project)
var projectAssetsFile = project.GetPropertyValue(PropertyNames.ProjectAssetsFile);
var configuration = project.GetPropertyValue(PropertyNames.Configuration);
var platform = project.GetPropertyValue(PropertyNames.Platform);
+ var defaultNamespace = project.GetPropertyValue(PropertyNames.RootNamespace);
var targetFramework = new FrameworkName(project.GetPropertyValue(PropertyNames.TargetFrameworkMoniker));
@@ -190,7 +195,7 @@ public static ProjectData Create(MSB.Evaluation.Project project)
return new ProjectData(
guid, name, assemblyName, targetPath, outputPath, intermediateOutputPath, projectAssetsFile,
configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode,
- documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, ruleset: null);
+ documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, ruleset: null);
}
public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
@@ -204,6 +209,7 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
var projectAssetsFile = projectInstance.GetPropertyValue(PropertyNames.ProjectAssetsFile);
var configuration = projectInstance.GetPropertyValue(PropertyNames.Configuration);
var platform = projectInstance.GetPropertyValue(PropertyNames.Platform);
+ var defaultNamespace = projectInstance.GetPropertyValue(PropertyNames.RootNamespace);
var targetFramework = new FrameworkName(projectInstance.GetPropertyValue(PropertyNames.TargetFrameworkMoniker));
@@ -277,7 +283,7 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance)
configuration, platform, targetFramework, targetFrameworks,
outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds,
signAssembly, assemblyOriginatorKeyFile,
- sourceFiles, projectReferences, references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, ruleset, referenceAliases.ToImmutableDictionary());
+ sourceFiles, projectReferences, references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, defaultNamespace, ruleset, referenceAliases.ToImmutableDictionary());
}
private static RuleSet ResolveRulesetIfAny(MSB.Execution.ProjectInstance projectInstance)
diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs
index 1e9af6008f..2a2d81221d 100644
--- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs
+++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs
@@ -53,6 +53,8 @@ internal partial class ProjectFileInfo
public ImmutableArray AdditionalFiles => _data.AdditionalFiles;
public ImmutableDictionary ReferenceAliases => _data.ReferenceAliases;
public bool TreatWarningsAsErrors => _data.TreatWarningsAsErrors;
+ public string DefaultNamespace => _data.DefaultNamespace;
+
public ProjectIdInfo ProjectIdInfo { get; }
private ProjectFileInfo(
diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs
index fd61c17442..f6a87674ed 100644
--- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs
+++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfoExtensions.cs
@@ -52,7 +52,6 @@ public static CSharpCompilationOptions CreateCompilationOptions(this ProjectFile
public static ImmutableDictionary GetDiagnosticOptions(this ProjectFileInfo projectFileInfo)
{
var defaultSuppressions = CompilationOptionsHelper.GetDefaultSuppressedDiagnosticOptions(projectFileInfo.SuppressedDiagnosticIds);
-
var specificRules = projectFileInfo.RuleSet?.SpecificDiagnosticOptions ?? ImmutableDictionary.Empty;
return specificRules.Concat(defaultSuppressions.Where(x => !specificRules.Keys.Contains(x.Key))).ToImmutableDictionary();
@@ -71,7 +70,7 @@ public static ProjectInfo CreateProjectInfo(this ProjectFileInfo projectFileInfo
filePath: projectFileInfo.FilePath,
outputFilePath: projectFileInfo.TargetPath,
compilationOptions: projectFileInfo.CreateCompilationOptions(),
- analyzerReferences: analyzerReferences);
+ analyzerReferences: analyzerReferences).WithDefaultNamespace(projectFileInfo.DefaultNamespace);
}
private static IEnumerable ResolveAnalyzerReferencesForProject(ProjectFileInfo projectFileInfo, IAnalyzerAssemblyLoader analyzerAssemblyLoader)
diff --git a/src/OmniSharp.MSBuild/ProjectFile/PropertyNames.cs b/src/OmniSharp.MSBuild/ProjectFile/PropertyNames.cs
index 4bbf8076e2..5178510759 100644
--- a/src/OmniSharp.MSBuild/ProjectFile/PropertyNames.cs
+++ b/src/OmniSharp.MSBuild/ProjectFile/PropertyNames.cs
@@ -29,6 +29,7 @@ internal static class PropertyNames
public const string ProjectGuid = nameof(ProjectGuid);
public const string ProjectName = nameof(ProjectName);
public const string _ResolveReferenceDependencies = nameof(_ResolveReferenceDependencies);
+ public const string RootNamespace = nameof(RootNamespace);
public const string RoslynTargetsPath = nameof(RoslynTargetsPath);
public const string SignAssembly = nameof(SignAssembly);
public const string SkipCompilerExecution = nameof(SkipCompilerExecution);
diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs
index 068d98cd2c..f0ff0e0f4b 100644
--- a/src/OmniSharp.MSBuild/ProjectManager.cs
+++ b/src/OmniSharp.MSBuild/ProjectManager.cs
@@ -434,14 +434,15 @@ private void UpdateProject(string projectFilePath)
UpdateParseOptions(project, projectFileInfo.LanguageVersion, projectFileInfo.PreprocessorSymbolNames, !string.IsNullOrWhiteSpace(projectFileInfo.DocumentationFile));
UpdateProjectReferences(project, projectFileInfo.ProjectReferences);
UpdateReferences(project, projectFileInfo.ProjectReferences, projectFileInfo.References);
- UpdateAnalyzerReferences(projectFileInfo, project);
+ UpdateAnalyzerReferences(project, projectFileInfo);
UpdateAdditionalFiles(project, projectFileInfo.AdditionalFiles);
+ UpdateProjectProperties(project, projectFileInfo);
_workspace.TryPromoteMiscellaneousDocumentsToProject(project);
_workspace.UpdateDiagnosticOptionsForProject(project.Id, projectFileInfo.GetDiagnosticOptions());
}
- private void UpdateAnalyzerReferences(ProjectFileInfo projectFileInfo, Project project)
+ private void UpdateAnalyzerReferences(Project project, ProjectFileInfo projectFileInfo)
{
var analyzerFileReferences = projectFileInfo.Analyzers
.Select(analyzerReferencePath => new AnalyzerFileReference(analyzerReferencePath, _analyzerAssemblyLoader))
@@ -450,6 +451,22 @@ private void UpdateAnalyzerReferences(ProjectFileInfo projectFileInfo, Project p
_workspace.SetAnalyzerReferences(project.Id, analyzerFileReferences);
}
+ private void UpdateProjectProperties(Project project, ProjectFileInfo projectFileInfo)
+ {
+ if (projectFileInfo.DefaultNamespace != project.DefaultNamespace)
+ {
+ var newSolution = _workspace.CurrentSolution.WithProjectDefaultNamespace(project.Id, projectFileInfo.DefaultNamespace);
+ if (_workspace.TryApplyChanges(newSolution))
+ {
+ _logger.LogDebug($"Updated default namespace from {project.DefaultNamespace} to {projectFileInfo.DefaultNamespace} on {project.FilePath} project.");
+ }
+ else
+ {
+ _logger.LogWarning($"Couldn't update default namespace from {project.DefaultNamespace} to {projectFileInfo.DefaultNamespace} on {project.FilePath} project.");
+ }
+ }
+ }
+
private void UpdateAdditionalFiles(Project project, IList additionalFiles)
{
var currentAdditionalDocuments = project.AdditionalDocuments;
@@ -490,7 +507,7 @@ private void UpdateSourceFiles(Project project, IList sourceFiles)
continue;
}
- _workspace.AddDocument(project.Id, sourceFile);
+ _workspace.AddDocument(project, sourceFile);
}
// Removing any remaining documents from the project.
diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Refactoring/V2/RunCodeActionService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Refactoring/V2/RunCodeActionService.cs
index af1d9aefa2..c7dc00d9a0 100644
--- a/src/OmniSharp.Roslyn.CSharp/Services/Refactoring/V2/RunCodeActionService.cs
+++ b/src/OmniSharp.Roslyn.CSharp/Services/Refactoring/V2/RunCodeActionService.cs
@@ -148,7 +148,7 @@ public override async Task Handle(RunCodeActionRequest re
}
}
- this.Workspace.AddDocument(documentId, projectChange.ProjectId, newFilePath, newDocument.SourceCodeKind);
+ this.Workspace.AddDocument(documentId, projectChange.NewProject, newFilePath, newDocument.SourceCodeKind);
solution = this.Workspace.CurrentSolution;
}
else
diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Signatures/SignatureHelpService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Signatures/SignatureHelpService.cs
index 03a8137d57..ad776a896f 100644
--- a/src/OmniSharp.Roslyn.CSharp/Services/Signatures/SignatureHelpService.cs
+++ b/src/OmniSharp.Roslyn.CSharp/Services/Signatures/SignatureHelpService.cs
@@ -77,7 +77,7 @@ throughExpression is LiteralExpressionSyntax ||
}
else if (invocation.Receiver is SimpleNameSyntax && invocation.IsInStaticContext)
{
- methodGroup = methodGroup.Where(m => m.IsStatic);
+ methodGroup = methodGroup.Where(m => m.IsStatic || m.MethodKind == MethodKind.LocalFunction);
}
foreach (var methodOverload in methodGroup)
diff --git a/src/OmniSharp.Roslyn/BufferManager.cs b/src/OmniSharp.Roslyn/BufferManager.cs
index c40b5deaa1..c53c821387 100644
--- a/src/OmniSharp.Roslyn/BufferManager.cs
+++ b/src/OmniSharp.Roslyn/BufferManager.cs
@@ -151,29 +151,26 @@ private bool TryAddTransientDocument(string fileName, string fileContent)
}
else
{
+ var projectAndDocumentIds = new List<(ProjectId ProjectId, DocumentId DocumentId)>();
var sourceText = SourceText.From(fileContent);
- var documentInfos = new List();
+
foreach (var project in projects)
{
- var id = DocumentId.CreateNewId(project.Id);
- var version = VersionStamp.Create();
- var documentInfo = DocumentInfo.Create(
- id, fileName, filePath: fileName,
- loader: TextLoader.From(TextAndVersion.Create(sourceText, version)));
-
- documentInfos.Add(documentInfo);
+ var documentId = DocumentId.CreateNewId(project.Id);
+ projectAndDocumentIds.Add((project.Id, documentId));
}
lock (_lock)
{
- var documentIds = documentInfos.Select(document => document.Id);
+ var documentIds = projectAndDocumentIds.Select(x => x.DocumentId);
_transientDocuments[fileName] = documentIds;
_transientDocumentIds.UnionWith(documentIds);
}
- foreach (var documentInfo in documentInfos)
+ foreach (var projectAndDocumentId in projectAndDocumentIds)
{
- _workspace.AddDocument(documentInfo);
+ var version = VersionStamp.Create();
+ _workspace.AddDocument(projectAndDocumentId.DocumentId, projectAndDocumentId.ProjectId, fileName, TextLoader.From(TextAndVersion.Create(sourceText, version)));
}
}
diff --git a/src/OmniSharp.Roslyn/MetadataHelper.cs b/src/OmniSharp.Roslyn/MetadataHelper.cs
index d1bbb81d92..e8f03f03a7 100644
--- a/src/OmniSharp.Roslyn/MetadataHelper.cs
+++ b/src/OmniSharp.Roslyn/MetadataHelper.cs
@@ -106,7 +106,7 @@ public string GetSymbolName(ISymbol symbol)
public async Task GetSymbolLocationFromMetadata(ISymbol symbol, Document metadataDocument, CancellationToken cancellationToken = new CancellationToken())
{
- var symbolKeyCreateMethod = _symbolKey.GetMethod(Create, BindingFlags.Static | BindingFlags.Public);
+ var symbolKeyCreateMethod = _symbolKey.GetMethod(Create, BindingFlags.Static | BindingFlags.NonPublic);
var symboldId = symbolKeyCreateMethod.InvokeStatic(new object[] { symbol, cancellationToken });
return await _getLocationInGeneratedSourceAsync.InvokeStatic>(new object[] { symboldId, metadataDocument, cancellationToken });
diff --git a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs
index b31560ff7e..d8213e92a6 100644
--- a/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs
+++ b/src/OmniSharp.Roslyn/OmniSharpWorkspace.cs
@@ -5,6 +5,7 @@
using System.Composition;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -12,6 +13,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Logging;
+using OmniSharp.FileSystem;
using OmniSharp.FileWatching;
using OmniSharp.Roslyn;
using OmniSharp.Roslyn.Utilities;
@@ -93,16 +95,6 @@ public void RemoveMetadataReference(ProjectId projectId, MetadataReference metad
OnMetadataReferenceRemoved(projectId, metadataReference);
}
- public void AddDocument(DocumentInfo documentInfo)
- {
- // if the file has already been added as a misc file,
- // because of a possible race condition between the updates of the project systems,
- // remove the misc file and add the document as required
- TryRemoveMiscellaneousDocument(documentInfo.FilePath);
-
- OnDocumentAdded(documentInfo);
- }
-
public DocumentId TryAddMiscellaneousDocument(string filePath, string language)
{
if (GetDocument(filePath) != null)
@@ -180,19 +172,74 @@ private ProjectInfo CreateMiscFilesProject(string language)
return projectInfo;
}
+ public void AddDocument(DocumentInfo documentInfo)
+ {
+ // if the file has already been added as a misc file,
+ // because of a possible race condition between the updates of the project systems,
+ // remove the misc file and add the document as required
+ TryRemoveMiscellaneousDocument(documentInfo.FilePath);
+
+ OnDocumentAdded(documentInfo);
+ }
+
public DocumentId AddDocument(ProjectId projectId, string filePath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
+ {
+ var project = this.CurrentSolution.GetProject(projectId);
+ return AddDocument(project, filePath, sourceCodeKind);
+ }
+
+ public DocumentId AddDocument(ProjectId projectId, string filePath, TextLoader loader, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
{
var documentId = DocumentId.CreateNewId(projectId);
- this.AddDocument(documentId, projectId, filePath, sourceCodeKind);
- return documentId;
+ var project = this.CurrentSolution.GetProject(projectId);
+ return AddDocument(documentId, project, filePath, loader, sourceCodeKind);
}
- public DocumentId AddDocument(DocumentId documentId, ProjectId projectId, string filePath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
+ public DocumentId AddDocument(Project project, string filePath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
{
- var loader = new OmniSharpTextLoader(filePath);
- var documentInfo = DocumentInfo.Create(documentId, Path.GetFileName(filePath), filePath: filePath, loader: loader, sourceCodeKind: sourceCodeKind);
+ var documentId = DocumentId.CreateNewId(project.Id);
+ return AddDocument(documentId, project, filePath, sourceCodeKind);
+ }
- this.AddDocument(documentInfo);
+ public DocumentId AddDocument(DocumentId documentId, Project project, string filePath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
+ {
+ return AddDocument(documentId, project, filePath, new OmniSharpTextLoader(filePath), sourceCodeKind);
+ }
+
+ internal DocumentId AddDocument(DocumentId documentId, ProjectId projectId, string filePath, TextLoader loader, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
+ {
+ var project = this.CurrentSolution.GetProject(projectId);
+ return AddDocument(documentId, project, filePath, loader, sourceCodeKind);
+ }
+
+ internal DocumentId AddDocument(DocumentId documentId, Project project, string filePath, TextLoader loader, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
+ {
+ var basePath = Path.GetDirectoryName(project.FilePath);
+ var fullPath = Path.GetDirectoryName(filePath);
+
+ IEnumerable folders = null;
+
+ // folder computation is best effort. in case of exceptions, we back out because it's not essential for core features
+ try
+ {
+ // find the relative path from project file to our document
+ var relativeDocumentPath = FileSystemHelper.GetRelativePath(fullPath, basePath);
+
+ // only set document's folders if
+ // 1. relative path was computed
+ // 2. path is not pointing any level up
+ if (relativeDocumentPath != null && !relativeDocumentPath.StartsWith(".."))
+ {
+ folders = relativeDocumentPath?.Split(new[] { Path.DirectorySeparatorChar });
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, $"An error occurred when computing a relative path from {basePath} to {fullPath}. Document at {filePath} will be processed without folder structure.");
+ }
+
+ var documentInfo = DocumentInfo.Create(documentId, Path.GetFileName(filePath), folders: folders, filePath: filePath, loader: loader, sourceCodeKind: sourceCodeKind);
+ AddDocument(documentInfo);
return documentId;
}
@@ -427,5 +474,21 @@ public void RemoveAdditionalDocument(DocumentId documentId)
{
OnAdditionalDocumentRemoved(documentId);
}
+
+ protected override void ApplyProjectChanges(ProjectChanges projectChanges)
+ {
+ // since Roslyn currently doesn't handle DefaultNamespace changes via ApplyProjectChanges
+ // and OnDefaultNamespaceChanged is internal, we use reflection for now
+ if (projectChanges.NewProject.DefaultNamespace != projectChanges.OldProject.DefaultNamespace)
+ {
+ var onDefaultNamespaceChanged = this.GetType().GetMethod("OnDefaultNamespaceChanged", BindingFlags.Instance | BindingFlags.NonPublic);
+ if (onDefaultNamespaceChanged != null)
+ {
+ onDefaultNamespaceChanged.Invoke(this, new object[] { projectChanges.ProjectId, projectChanges.NewProject.DefaultNamespace });
+ }
+ }
+
+ base.ApplyProjectChanges(projectChanges);
+ }
}
}
diff --git a/src/OmniSharp.Shared/FileSystem/FileSystemHelper.cs b/src/OmniSharp.Shared/FileSystem/FileSystemHelper.cs
index e52a0444b8..d0aabcf1db 100644
--- a/src/OmniSharp.Shared/FileSystem/FileSystemHelper.cs
+++ b/src/OmniSharp.Shared/FileSystem/FileSystemHelper.cs
@@ -1,5 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Composition;
+using System.IO;
using System.Linq;
using Microsoft.Extensions.FileSystemGlobbing;
using OmniSharp.Options;
@@ -9,6 +11,7 @@ namespace OmniSharp.FileSystem
[Export, Shared]
public class FileSystemHelper
{
+ private static string s_directorySeparatorChar = Path.DirectorySeparatorChar.ToString();
private readonly OmniSharpOptions _omniSharpOptions;
private readonly IOmniSharpEnvironment _omniSharpEnvironment;
@@ -38,5 +41,28 @@ public IEnumerable GetFiles(string includePattern, string targetDirector
return matcher.GetResultsInFullPath(targetDirectory);
}
+
+ public static string GetRelativePath(string fullPath, string basePath)
+ {
+ // if any of them is not set, abort
+ if (string.IsNullOrWhiteSpace(basePath) || string.IsNullOrWhiteSpace(fullPath)) return null;
+
+ // paths must be rooted
+ if (!Path.IsPathRooted(basePath) || !Path.IsPathRooted(fullPath)) return null;
+
+ // if they are the same, abort
+ if (fullPath.Equals(basePath, StringComparison.Ordinal)) return null;
+
+ if (!Path.HasExtension(basePath) && !basePath.EndsWith(s_directorySeparatorChar))
+ {
+ basePath += Path.DirectorySeparatorChar;
+ }
+
+ var baseUri = new Uri(basePath);
+ var fullUri = new Uri(fullPath);
+ var relativeUri = baseUri.MakeRelativeUri(fullUri);
+ var relativePath = Uri.UnescapeDataString(relativeUri.ToString()).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
+ return relativePath;
+ }
}
}
diff --git a/src/OmniSharp.Stdio.Driver/app.config b/src/OmniSharp.Stdio.Driver/app.config
index ff336a2a60..aedd66b2a7 100644
--- a/src/OmniSharp.Stdio.Driver/app.config
+++ b/src/OmniSharp.Stdio.Driver/app.config
@@ -7,15 +7,15 @@
-
+
-
+
-
+
diff --git a/tests/OmniSharp.Cake.Tests/CodeActionsV2Facts.cs b/tests/OmniSharp.Cake.Tests/CodeActionsV2Facts.cs
index 6a8987e24e..6f8bd0a1e8 100644
--- a/tests/OmniSharp.Cake.Tests/CodeActionsV2Facts.cs
+++ b/tests/OmniSharp.Cake.Tests/CodeActionsV2Facts.cs
@@ -64,7 +64,8 @@ public void Whatever()
{
"using System.Text.RegularExpressions;",
"System.Text.RegularExpressions.Regex",
- "Extract Method"
+ "Extract Method",
+ "Introduce local for 'Regex.Match(\"foo\", \"bar\")'"
};
Assert.Equal(expected, refactorings);
}
diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/CodeActionsV2Facts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/CodeActionsV2Facts.cs
index 922e5ad716..d1d117784d 100644
--- a/tests/OmniSharp.Roslyn.CSharp.Tests/CodeActionsV2Facts.cs
+++ b/tests/OmniSharp.Roslyn.CSharp.Tests/CodeActionsV2Facts.cs
@@ -137,7 +137,8 @@ public void Whatever()
"Generate type 'Console' -> Generate class 'Console' in new file",
"Generate type 'Console' -> Generate class 'Console'",
"Generate type 'Console' -> Generate nested class 'Console'",
- "Extract Method"
+ "Extract Method",
+ "Introduce local for 'Console.Write(\"should be using System;\")'"
} : new List
{
"using System;",
@@ -150,7 +151,8 @@ public void Whatever()
"Generate type 'Console' -> Generate class 'Console' in new file",
"Generate type 'Console' -> Generate class 'Console'",
"Generate type 'Console' -> Generate nested class 'Console'",
- "Extract Method"
+ "Extract Method",
+ "Introduce local for 'Console.Write(\"should be using System;\")'"
};
Assert.Equal(expected.OrderBy(x => x), refactorings.OrderBy(x => x));
}
diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/FilesChangedFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/FilesChangedFacts.cs
index 0f7fb8a351..ace7d9d098 100644
--- a/tests/OmniSharp.Roslyn.CSharp.Tests/FilesChangedFacts.cs
+++ b/tests/OmniSharp.Roslyn.CSharp.Tests/FilesChangedFacts.cs
@@ -32,7 +32,7 @@ public async Task TestFileAddedToMSBuildWorkspaceOnCreation()
var handler = GetRequestHandler(host);
await handler.Handle(new[] { new FilesChangedRequest() { FileName = filePath, ChangeType = FileChangeType.Create } });
- Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.Name == filePath);
+ Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.FilePath == filePath && d.Name == "FileName.cs");
}
}
@@ -51,7 +51,7 @@ public async Task TestFileMovedToPreviouslyEmptyDirectory()
var handler = GetRequestHandler(host);
await handler.Handle(new[] { new FilesChangedRequest() { FileName = filePath, ChangeType = FileChangeType.Create } });
- Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.Name == filePath);
+ Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.FilePath == filePath && d.Name == "FileName.cs");
var nestedDirectory = Path.Combine(projectDirectory, "Nested");
Directory.CreateDirectory(nestedDirectory);
@@ -62,8 +62,8 @@ public async Task TestFileMovedToPreviouslyEmptyDirectory()
await handler.Handle(new[] { new FilesChangedRequest() { FileName = filePath, ChangeType = FileChangeType.Delete } });
await handler.Handle(new[] { new FilesChangedRequest() { FileName = destinationPath, ChangeType = FileChangeType.Create } });
- Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.Name == destinationPath);
- Assert.DoesNotContain(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.Name == filePath);
+ Assert.Contains(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.FilePath == destinationPath && d.Name == "FileName.cs");
+ Assert.DoesNotContain(host.Workspace.CurrentSolution.Projects.First().Documents, d => d.FilePath == filePath && d.Name == "FileName.cs");
}
}
diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs
index 9d00fcdd57..a6e5e682fe 100644
--- a/tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs
+++ b/tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs
@@ -880,7 +880,7 @@ public static void Main()
[Theory]
[InlineData("dummy.cs")]
[InlineData("dummy.csx")]
- public async Task GivesHelpForLocalFunctions(string filename)
+ public async Task GivesHelpForLocalFunctionsInStaticContext(string filename)
{
const string source =
@"class Program
@@ -903,6 +903,32 @@ bool LocalFunction(int i)
Assert.Equal("int i", signature.Parameters.ElementAt(0).Label);
}
+ [Theory]
+ [InlineData("dummy.cs")]
+ [InlineData("dummy.csx")]
+ public async Task GivesHelpForLocalFunctionsInNonStaticContext(string filename)
+ {
+ const string source =
+@"class Program
+{
+ public void Main()
+ {
+ var flag = LocalFunction($$);
+ bool LocalFunction(int i)
+ {
+ return i > 0;
+ }
+ }
+}";
+ var actual = await GetSignatureHelp(filename, source);
+ Assert.Single(actual.Signatures);
+
+ var signature = actual.Signatures.ElementAt(0);
+ Assert.Single(signature.Parameters);
+ Assert.Equal("i", signature.Parameters.ElementAt(0).Name);
+ Assert.Equal("int i", signature.Parameters.ElementAt(0).Label);
+ }
+
[Theory]
[InlineData("dummy.cs")]
[InlineData("dummy.csx")]
diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/SyncNamespaceFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/SyncNamespaceFacts.cs
new file mode 100644
index 0000000000..43460cf9b8
--- /dev/null
+++ b/tests/OmniSharp.Roslyn.CSharp.Tests/SyncNamespaceFacts.cs
@@ -0,0 +1,165 @@
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using OmniSharp.Models;
+using OmniSharp.Models.V2.CodeActions;
+using OmniSharp.Roslyn.CSharp.Services.Refactoring.V2;
+using TestUtility;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace OmniSharp.Roslyn.CSharp.Tests
+{
+ public class SyncNamespaceFacts : AbstractTestFixture
+ {
+ public SyncNamespaceFacts(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Theory]
+ [InlineData("OmniSharpTest", "Bar.cs")]
+ [InlineData("OmniSharpTest.Foo", "Foo", "Bar.cs")]
+ [InlineData("OmniSharpTest.Foo.Bar", "Foo", "Bar", "Baz.cs")]
+ public async Task RespectFolderName_InOfferedRefactorings(string expectedNamespace, params string[] relativePath)
+ {
+ var testFile = new TestFile(Path.Combine(TestAssets.Instance.TestFilesFolder, Path.Combine(relativePath)), @"namespace Xx$$x { }");
+
+ using (var host = CreateOmniSharpHost(new[] { testFile }, null, path: TestAssets.Instance.TestFilesFolder))
+ {
+ var point = testFile.Content.GetPointFromPosition();
+ var getRequestHandler = host.GetRequestHandler(OmniSharpEndpoints.V2.GetCodeActions);
+ var getRequest = new GetCodeActionsRequest
+ {
+ Line = point.Line,
+ Column = point.Offset,
+ FileName = testFile.FileName
+ };
+
+ var getResponse = await getRequestHandler.Handle(getRequest);
+ Assert.NotNull(getResponse.CodeActions);
+ Assert.Contains(getResponse.CodeActions, f => f.Name == $"Change namespace to '{expectedNamespace}'");
+ }
+ }
+
+ [Theory]
+ [InlineData("LiveChanged", "Bar.cs")]
+ [InlineData("LiveChanged.Foo", "Foo", "Bar.cs")]
+ [InlineData("LiveChanged.Foo.Bar", "Foo", "Bar", "Baz.cs")]
+ public async Task RespectFolderName_InOfferedRefactorings_AfterLiveChange(string expectedNamespace, params string[] relativePath)
+ {
+ var testFile = new TestFile(Path.Combine(TestAssets.Instance.TestFilesFolder, Path.Combine(relativePath)), @"namespace Xx$$x { }");
+
+ using (var host = CreateOmniSharpHost(new[] { testFile }, null, path: TestAssets.Instance.TestFilesFolder))
+ {
+ var point = testFile.Content.GetPointFromPosition();
+ var getRequestHandler = host.GetRequestHandler(OmniSharpEndpoints.V2.GetCodeActions);
+
+ var changedSolution = host.Workspace.CurrentSolution.WithProjectDefaultNamespace(host.Workspace.CurrentSolution.Projects.ElementAt(0).Id, "LiveChanged");
+ host.Workspace.TryApplyChanges(changedSolution);
+
+ var getRequest = new GetCodeActionsRequest
+ {
+ Line = point.Line,
+ Column = point.Offset,
+ FileName = testFile.FileName
+ };
+
+ var getResponse = await getRequestHandler.Handle(getRequest);
+ Assert.NotNull(getResponse.CodeActions);
+ Assert.Contains(getResponse.CodeActions, f => f.Name == $"Change namespace to '{expectedNamespace}'");
+ }
+ }
+
+ [Theory]
+ [InlineData("OmniSharpTest", "Bar.cs")]
+ [InlineData("OmniSharpTest.Foo", "Foo", "Bar.cs")]
+ [InlineData("OmniSharpTest.Foo.Bar", "Foo", "Bar", "Baz.cs")]
+ public async Task RespectFolderName_InExecutedCodeActions(string expectedNamespace, params string[] relativePath)
+ {
+ var expected = "namespace " + expectedNamespace + " { }";
+ var testFile = new TestFile(Path.Combine(TestAssets.Instance.TestFilesFolder, Path.Combine(relativePath)), @"namespace Xx$$x { }");
+
+ using (var host = CreateOmniSharpHost(new[] { testFile }, null, TestAssets.Instance.TestFilesFolder))
+ {
+ var point = testFile.Content.GetPointFromPosition();
+ var runRequestHandler = host.GetRequestHandler(OmniSharpEndpoints.V2.RunCodeAction);
+ var runRequest = new RunCodeActionRequest
+ {
+ Line = point.Line,
+ Column = point.Offset,
+ FileName = testFile.FileName,
+ Identifier = $"Change namespace to '{expectedNamespace}'",
+ WantsTextChanges = false,
+ WantsAllCodeActionOperations = true,
+ Buffer = testFile.Content.Code
+ };
+ var runResponse = await runRequestHandler.Handle(runRequest);
+
+ AssertIgnoringIndent(expected, ((ModifiedFileResponse)runResponse.Changes.First()).Buffer);
+ }
+ }
+
+ [Theory]
+ [InlineData("LiveChanged", "Bar.cs")]
+ [InlineData("LiveChanged.Foo", "Foo", "Bar.cs")]
+ [InlineData("LiveChanged.Foo.Bar", "Foo", "Bar", "Baz.cs")]
+ public async Task RespectFolderName_InExecutedCodeActions_AfterLiveChange(string expectedNamespace, params string[] relativePath)
+ {
+ var expected = "namespace " + expectedNamespace + " { }";
+ var testFile = new TestFile(Path.Combine(TestAssets.Instance.TestFilesFolder, Path.Combine(relativePath)), @"namespace Xx$$x { }");
+
+ using (var host = CreateOmniSharpHost(new[] { testFile }, null, TestAssets.Instance.TestFilesFolder))
+ {
+ var point = testFile.Content.GetPointFromPosition();
+ var runRequestHandler = host.GetRequestHandler(OmniSharpEndpoints.V2.RunCodeAction);
+
+ var changedSolution = host.Workspace.CurrentSolution.WithProjectDefaultNamespace(host.Workspace.CurrentSolution.Projects.ElementAt(0).Id, "LiveChanged");
+ host.Workspace.TryApplyChanges(changedSolution);
+
+ var runRequest = new RunCodeActionRequest
+ {
+ Line = point.Line,
+ Column = point.Offset,
+ FileName = testFile.FileName,
+ Identifier = $"Change namespace to '{expectedNamespace}'",
+ WantsTextChanges = false,
+ WantsAllCodeActionOperations = true,
+ Buffer = testFile.Content.Code
+ };
+ var runResponse = await runRequestHandler.Handle(runRequest);
+
+ AssertIgnoringIndent(expected, ((ModifiedFileResponse)runResponse.Changes.First()).Buffer);
+ }
+ }
+
+ [Fact]
+ public void CheckIfOnDefaultNamespaceChangedIsAvailableInRoslyn()
+ {
+ // This tracks the availability of OnDefaultNamespaceChanged on the Workspace
+ // at the moment it's not and we need to manually sync default namespace after it changes
+ // when OmniSharp is running by having reflection in
+ // protected override void ApplyProjectChanges(ProjectChanges projectChanges)
+ // once it's fixed in Roslyn we can get rid of this test
+ var onDefaultNamespaceChanged = typeof(OmniSharpWorkspace).GetMethod("OnDefaultNamespaceChanged", BindingFlags.Instance | BindingFlags.NonPublic);
+ Assert.NotNull(onDefaultNamespaceChanged);
+
+ var parameters = onDefaultNamespaceChanged.GetParameters();
+ Assert.Equal(2, parameters.Count());
+ Assert.Equal(typeof(ProjectId), parameters[0].ParameterType);
+ Assert.Equal(typeof(string), parameters[1].ParameterType);
+ }
+
+ private static void AssertIgnoringIndent(string expected, string actual)
+ {
+ Assert.Equal(TrimLines(expected), TrimLines(actual), false, true, true);
+ }
+
+ private static string TrimLines(string source)
+ {
+ return string.Join("\n", source.Split('\n').Select(s => s.Trim()));
+ }
+ }
+}
diff --git a/tests/TestUtility/AbstractCodeActionsTestFixture.cs b/tests/TestUtility/AbstractCodeActionsTestFixture.cs
index 777fa5e140..57cef8f739 100644
--- a/tests/TestUtility/AbstractCodeActionsTestFixture.cs
+++ b/tests/TestUtility/AbstractCodeActionsTestFixture.cs
@@ -20,7 +20,7 @@ public abstract class AbstractCodeActionsTestFixture
protected ITestOutputHelper TestOutput { get; }
- private string BufferPath => $"{Path.DirectorySeparatorChar}somepath{Path.DirectorySeparatorChar}buffer{_fileTypeExtension}";
+ private string BufferPath => $"{Directory.GetCurrentDirectory()}{Path.DirectorySeparatorChar}somepath{Path.DirectorySeparatorChar}buffer{_fileTypeExtension}";
protected AbstractCodeActionsTestFixture(ITestOutputHelper output, string fileTypeExtension = ".cs")
{
diff --git a/tests/TestUtility/AbstractTestFixture.cs b/tests/TestUtility/AbstractTestFixture.cs
index 3b584599e8..5b48a718e1 100644
--- a/tests/TestUtility/AbstractTestFixture.cs
+++ b/tests/TestUtility/AbstractTestFixture.cs
@@ -65,7 +65,7 @@ protected OmniSharpTestHost CreateOmniSharpHost(TestFile[] testFiles, IEnumerabl
if (testFiles.Length > 0)
{
- host.AddFilesToWorkspace(testFiles);
+ host.AddFilesToWorkspace(path, testFiles);
}
return host;
diff --git a/tests/TestUtility/OmniSharpTestHost.cs b/tests/TestUtility/OmniSharpTestHost.cs
index e16c5c6a54..476f1bdc17 100644
--- a/tests/TestUtility/OmniSharpTestHost.cs
+++ b/tests/TestUtility/OmniSharpTestHost.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Composition.Hosting;
using System.Composition.Hosting.Core;
+using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -128,10 +129,14 @@ public THandler GetRequestHandler(string name, string languageName = L
}
public IEnumerable AddFilesToWorkspace(params TestFile[] testFiles)
+ => AddFilesToWorkspace(Directory.GetCurrentDirectory(), testFiles);
+
+ public IEnumerable AddFilesToWorkspace(string folderPath, params TestFile[] testFiles)
{
+ folderPath = folderPath ?? Directory.GetCurrentDirectory();
var projects = TestHelpers.AddProjectToWorkspace(
- this.Workspace,
- "project.csproj",
+ Workspace,
+ Path.Combine(folderPath, "project.csproj"),
new[] { "net472" },
testFiles.Where(f => f.FileName.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)).ToArray());
diff --git a/tests/TestUtility/TestHelpers.cs b/tests/TestUtility/TestHelpers.cs
index 95faa605f1..4217ff5203 100644
--- a/tests/TestUtility/TestHelpers.cs
+++ b/tests/TestUtility/TestHelpers.cs
@@ -60,20 +60,13 @@ public static IEnumerable AddProjectToWorkspace(OmniSharpWorkspace wo
language: LanguageNames.CSharp,
filePath: filePath,
metadataReferences: references,
- analyzerReferences: analyzerRefs);
+ analyzerReferences: analyzerRefs).WithDefaultNamespace("OmniSharpTest");
workspace.AddProject(projectInfo);
foreach (var testFile in testFiles)
{
- var documentInfo = DocumentInfo.Create(
- id: DocumentId.CreateNewId(projectInfo.Id),
- name: testFile.FileName,
- sourceCodeKind: SourceCodeKind.Regular,
- loader: TextLoader.From(TextAndVersion.Create(testFile.Content.Text, versionStamp)),
- filePath: testFile.FileName);
-
- workspace.AddDocument(documentInfo);
+ workspace.AddDocument(projectInfo.Id, testFile.FileName, TextLoader.From(TextAndVersion.Create(testFile.Content.Text, versionStamp)), SourceCodeKind.Regular);
}
projectsIds.Add(projectInfo.Id);
diff --git a/tests/app.config b/tests/app.config
index 445a0e201a..cc24387b07 100644
--- a/tests/app.config
+++ b/tests/app.config
@@ -7,15 +7,15 @@
-
+
-
+
-
+