提交 e199c861 编写于 作者: B Basoundr_ms

User Story 860085 Get and use MSBuild API for solution parsing in MSBuildWorkspace

This change replaces the solution parser which was long written by JasonMal with the solution parser from MsBuild (changeset 1324466)
上级 b9ce41b3
......@@ -8,10 +8,13 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
#if !MSBUILD12
using Microsoft.Build.Construction;
#endif
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
......@@ -366,6 +369,60 @@ public async Task<Solution> OpenSolutionAsync(string solutionFilePath, Cancellat
}
VersionStamp version = default(VersionStamp);
#if !MSBUILD12
Microsoft.Build.Construction.SolutionFile solutionFile = Microsoft.Build.Construction.SolutionFile.Parse(absoluteSolutionPath);
var reportMode = this.SkipUnrecognizedProjects ? ReportMode.Log : ReportMode.Throw;
var invalidProjects = new List<ProjectInSolution>();
// seed loaders from known project types
using (this.dataGuard.DisposableWait())
{
foreach (var project in solutionFile.ProjectsInOrder)
{
var projectAbsolutePath = TryGetAbsolutePath(project.AbsolutePath, reportMode);
if (projectAbsolutePath != null)
{
var extension = Path.GetExtension(projectAbsolutePath);
extension = extension.StartsWith(".") ? extension.Substring(1) : extension;
var loader = ProjectFileLoader.GetLoaderForProjectFileExtension(this, extension);
if (loader != null)
{
this.projectPathToLoaderMap[projectAbsolutePath] = loader;
}
}
else
{
invalidProjects.Add(project);
}
}
}
// a list to accumulate all the loaded projects
var loadedProjects = new List<ProjectInfo>();
// load all the projects
foreach (var project in solutionFile.ProjectsInOrder)
{
cancellationToken.ThrowIfCancellationRequested();
if (!invalidProjects.Contains(project))
{
var projectAbsolutePath = TryGetAbsolutePath(project.AbsolutePath, reportMode);
if (projectAbsolutePath != null)
{
IProjectFileLoader loader;
if (TryGetLoaderFromProjectPath(projectAbsolutePath, reportMode, out loader))
{
// projects get added to 'loadedProjects' as side-effect
// never perfer metadata when loading solution, all projects get loaded if they can.
var tmp = await GetOrLoadProjectAsync(projectAbsolutePath, loader, preferMetadata: false, loadedProjects: loadedProjects, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
}
#else
SolutionFile solutionFile = null;
using (var reader = new StreamReader(absoluteSolutionPath))
......@@ -416,6 +473,7 @@ public async Task<Solution> OpenSolutionAsync(string solutionFilePath, Cancellat
}
}
}
#endif
// construct workspace from loaded project infos
this.OnSolutionAdded(SolutionInfo.Create(SolutionId.CreateNewId(debugName: absoluteSolutionPath), version, absoluteSolutionPath, loadedProjects));
......@@ -460,6 +518,30 @@ public async Task<Project> OpenProjectAsync(string projectFilePath, Cancellation
return null;
}
private string TryGetAbsolutePath(string path, ReportMode mode)
{
try
{
path = Path.GetFullPath(path);
}
catch (Exception)
{
ReportFailure(mode, string.Format(WorkspacesResources.InvalidProjectFilePath, path));
return null;
}
if (!File.Exists(path))
{
ReportFailure(
mode,
string.Format(WorkspacesResources.ProjectFileNotFound, path),
msg => new FileNotFoundException(msg));
return null;
}
return path;
}
private void UpdateReferencesAfterAdd()
{
using (this.serializationLock.DisposableWait())
......@@ -763,9 +845,9 @@ private async Task<MetadataReference> GetProjectMetadata(string projectFilePath,
return null;
}
#endregion
#endregion
#region Apply Changes
#region Apply Changes
public override bool CanApplyChange(ApplyChangesKind feature)
{
switch (feature)
......@@ -970,5 +1052,5 @@ private void DeleteDocumentFile(DocumentId documentId, string fullPath)
}
}
}
#endregion
#endregion
}
\ No newline at end of file
......@@ -666,6 +666,19 @@ public void TestOpenSolution_WithNonExistentProject_SkipFalse_Fails()
});
}
#if !MSBUILD12
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public void TestOpenSolution_WithUnrecognizedProjectFileExtension_Fails()
{
// proves that for solution open, project type guid and extension are both necessary
CreateFiles(GetSimpleCSharpSolutionFiles()
.WithFile(@"TestSolution.sln", GetResourceText("TestSolution_CSharp_UnknownProjectExtension.sln"))
.WithFile(@"CSharpProject\CSharpProject.noproj", GetResourceText("CSharpProject_CSharpProject.csproj")));
var solution = MSBuildWorkspace.Create().OpenSolutionAsync(GetSolutionFileName(@"TestSolution.sln")).Result;
Assert.Equal(0, solution.ProjectIds.Count);
}
#else
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public void TestOpenSolution_WithUnrecognizedProjectFileExtension_Succeeds()
{
......@@ -677,6 +690,7 @@ public void TestOpenSolution_WithUnrecognizedProjectFileExtension_Succeeds()
var solution = MSBuildWorkspace.Create().OpenSolutionAsync(GetSolutionFileName(@"TestSolution.sln")).Result;
Assert.Equal(1, solution.ProjectIds.Count);
}
#endif
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public void TestOpenSolution_WithUnrecognizedProjectTypeGuidButRecognizedExtension_Succeeds()
......@@ -2122,7 +2136,7 @@ public void TestOpenSolution_SolutionFileHasEmptyLineBetweenProjectBlock()
var solution = MSBuildWorkspace.Create().OpenSolutionAsync(GetSolutionFileName("TestSolution.sln")).Result;
}
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
[Fact(Skip = "531283"), Trait(Traits.Feature, Traits.Features.Workspace)]
[WorkItem(531283, "DevDiv")]
public void TestOpenSolution_SolutionFileHasMissingEndProject()
{
......
......@@ -11,6 +11,9 @@ namespace Roslyn.Editor.UnitTests.SolutionParsing
{
public class SolutionParsingTests
{
private static string visualStudio2010 = @"# Visual Studio 2010";
private static string visualStudio2012 = @"# Visual Studio 2012";
#if MSBUILD12
[Fact]
public void ParseEmptyFile()
{
......@@ -27,7 +30,7 @@ public void ParseEmptySolution()
{
var emptySolution = @"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
" + visualStudio2010 + @"
Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -57,7 +60,7 @@ public void ParseVisualBasicConsoleApplicationSolution()
{
var vbConsoleApplicationSolution = @"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
" + visualStudio2010 + @"
Project(""{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"") = ""ConsoleApplication1"", ""ConsoleApplication1\ConsoleApplication1.vbproj"", ""{09BC9F5A-FBFA-4BEE-A13C-77A99C95D06B}""
EndProject
Global
......@@ -110,7 +113,7 @@ public void ParseSolutionWithMissingWhiteSpaces()
{
var vbConsoleApplicationSolution = @"
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
" + visualStudio2010 + @"
Project(""{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"") =""ConsoleApplication1"" , ""Console Application1\ConsoleApplication1.vbproj"",""{09BC9F5A-FBFA-4BEE-A13C-77A99C95D06B}""
EndProject
Global
......@@ -146,7 +149,7 @@ public void ParseSolutionFileWithVisualStudioVersion()
{
var vbConsoleApplicationSolution = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 12
" + visualStudio2012 + @"
VisualStudioVersion = 12.0.20430.1 PREVIEW
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"") =""ConsoleApplication1"" , ""Console Application1\ConsoleApplication1.vbproj"",""{09BC9F5A-FBFA-4BEE-A13C-77A99C95D06B}""
......@@ -187,5 +190,6 @@ private Microsoft.CodeAnalysis.MSBuild.SolutionFile Parse(StringReader stringRea
{
return Microsoft.CodeAnalysis.MSBuild.SolutionFile.Parse(stringReader);
}
#endif
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册