Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to use project references to avoid reference conversion #165

Merged
merged 5 commits into from
Aug 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions ICSharpCode.CodeConverter/CSharp/VBToCSConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using ICSharpCode.CodeConverter.Shared;
using ICSharpCode.CodeConverter.Util;
using ICSharpCode.CodeConverter.VB;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -17,24 +18,21 @@ namespace ICSharpCode.CodeConverter.CSharp
public class VBToCSConversion : ILanguageConversion
{
private Compilation _sourceCompilation;
private readonly List<SyntaxTree> _firstPassResults = new List<SyntaxTree>();
private readonly List<SyntaxTree> _secondPassResults = new List<SyntaxTree>();
private Lazy<CSharpCompilation> _targetCompilation;

private CSharpCompilation CreateCompilation(List<SyntaxTree> csTrees)
private CSharpCompilation _convertedCompilation;


public void Initialize(Compilation convertedCompilation)
{
var references = _sourceCompilation.References.Select(ReferenceConverter.ConvertReference);
return CSharpCompilation.Create("Conversion", csTrees, references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
_convertedCompilation = (CSharpCompilation) convertedCompilation;
}

public SyntaxTree SingleFirstPass(Compilation sourceCompilation, SyntaxTree tree)
{
_sourceCompilation = sourceCompilation;
var converted = VisualBasicConverter.ConvertCompilationTree((VisualBasicCompilation)sourceCompilation, (VisualBasicSyntaxTree)tree);
var convertedTree = SyntaxFactory.SyntaxTree(converted);
_firstPassResults.Add(convertedTree);
_targetCompilation = new Lazy<CSharpCompilation>(() => CreateCompilation(_firstPassResults));
_convertedCompilation = _convertedCompilation.AddSyntaxTrees(convertedTree);
return convertedTree;
}

Expand All @@ -60,6 +58,8 @@ public SyntaxNode GetSurroundedNode(IEnumerable<SyntaxNode> descendantNodes,
};
}

public string TargetLanguage { get; } = LanguageNames.CSharp;

public bool CanBeContainedByMethod(SyntaxNode node)
{
return node is VBSyntax.IncompleteMemberSyntax ||
Expand Down Expand Up @@ -116,15 +116,14 @@ public List<SyntaxNode> FindSingleImportantChild(SyntaxNode annotatedNode)

public SyntaxNode SingleSecondPass(KeyValuePair<string, SyntaxTree> cs)
{
var cSharpSyntaxNode = new CompilationErrorFixer(_targetCompilation.Value, (CSharpSyntaxTree)cs.Value).Fix();
var cSharpSyntaxNode = new CompilationErrorFixer(_convertedCompilation, (CSharpSyntaxTree)cs.Value).Fix();
_secondPassResults.Add(cSharpSyntaxNode.SyntaxTree);
return cSharpSyntaxNode;
}

public string GetWarningsOrNull()
{
var finalCompilation = CreateCompilation(_firstPassResults);
return CompilationWarnings.WarningsForCompilation(_sourceCompilation, "source") + CompilationWarnings.WarningsForCompilation(finalCompilation, "target");
return CompilationWarnings.WarningsForCompilation(_sourceCompilation, "source") + CompilationWarnings.WarningsForCompilation(_convertedCompilation, "target");
}

public SyntaxTree CreateTree(string text)
Expand All @@ -133,6 +132,12 @@ public SyntaxTree CreateTree(string text)
}

public Compilation CreateCompilationFromTree(SyntaxTree tree, IEnumerable<MetadataReference> references)
{
var compilation = CreateVisualBasicCompilation(references);
return compilation.AddSyntaxTrees(tree);
}

public static VisualBasicCompilation CreateVisualBasicCompilation(IEnumerable<MetadataReference> references)
{
var compilationOptions = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithGlobalImports(GlobalImport.Parse(
Expand All @@ -148,7 +153,7 @@ public Compilation CreateCompilationFromTree(SyntaxTree tree, IEnumerable<Metada
"System.Text",
"System.Threading.Tasks",
"Microsoft.VisualBasic"));
var compilation = VisualBasicCompilation.Create("Conversion", new[] {tree}, references)
var compilation = VisualBasicCompilation.Create("Conversion", references: references)
.WithOptions(compilationOptions);
return compilation;
}
Expand Down
5 changes: 4 additions & 1 deletion ICSharpCode.CodeConverter/ILanguageConversion.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;

namespace ICSharpCode.CodeConverter.CSharp
Expand All @@ -20,5 +21,7 @@ SyntaxNode GetSurroundedNode(IEnumerable<SyntaxNode> descendantNodes,
bool surroundedWithMethod);
IReadOnlyCollection<(string, string)> GetProjectTypeGuidMappings();
IEnumerable<(string, string)> GetProjectFileReplacementRegexes();
string TargetLanguage { get; }
void Initialize(Compilation convertedCompilation);
}
}
32 changes: 27 additions & 5 deletions ICSharpCode.CodeConverter/Shared/ProjectConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
using System.Threading.Tasks;
using ICSharpCode.CodeConverter.CSharp;
using ICSharpCode.CodeConverter.Util;
using ICSharpCode.CodeConverter.VB;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.VisualBasic;

namespace ICSharpCode.CodeConverter.Shared
{
Expand All @@ -24,18 +27,19 @@ public class ProjectConversion
private readonly ILanguageConversion _languageConversion;
private readonly bool _handlePartialConversion;

private ProjectConversion(Compilation sourceCompilation, string solutionDir, ILanguageConversion languageConversion)
: this(sourceCompilation, sourceCompilation.SyntaxTrees.Where(t => t.FilePath.StartsWith(solutionDir)), languageConversion)
private ProjectConversion(Compilation sourceCompilation, string solutionDir, ILanguageConversion languageConversion, Compilation convertedCompilation)
: this(sourceCompilation, sourceCompilation.SyntaxTrees.Where(t => t.FilePath.StartsWith(solutionDir)), languageConversion, convertedCompilation)
{
_solutionDir = solutionDir;
}

private ProjectConversion(Compilation sourceCompilation, IEnumerable<SyntaxTree> syntaxTreesToConvert, ILanguageConversion languageConversion)
private ProjectConversion(Compilation sourceCompilation, IEnumerable<SyntaxTree> syntaxTreesToConvert, ILanguageConversion languageConversion, Compilation convertedCompilation)
{
_languageConversion = languageConversion;
this._sourceCompilation = sourceCompilation;
_syntaxTreesToConvert = syntaxTreesToConvert.ToList();
_handlePartialConversion = _syntaxTreesToConvert.Count() == 1;
languageConversion.Initialize(convertedCompilation.RemoveAllSyntaxTrees());
}

public static ConversionResult ConvertText<TLanguageConversion>(string text, IReadOnlyCollection<MetadataReference> references) where TLanguageConversion : ILanguageConversion, new()
Expand All @@ -54,7 +58,7 @@ public static async Task<ConversionResult> ConvertSingle(Compilation compilation
syntaxTree = annotatedSyntaxTree;
}

var conversion = new ProjectConversion(compilation, new [] {syntaxTree}, languageConversion);
var conversion = new ProjectConversion(compilation, new [] {syntaxTree}, languageConversion, GetConvertedCompilation(compilation, languageConversion));
var conversionResults = ConvertProjectContents(conversion).ToList();
var codeResult = conversionResults.SingleOrDefault(x => !string.IsNullOrWhiteSpace(x.ConvertedCode))
?? conversionResults.First();
Expand All @@ -68,10 +72,28 @@ public static IEnumerable<ConversionResult> ConvertProjectContents(Project proje
var solutionFilePath = project.Solution.FilePath;
var solutionDir = Path.GetDirectoryName(solutionFilePath);
var compilation = project.GetCompilationAsync().GetAwaiter().GetResult();
var projectConversion = new ProjectConversion(compilation, solutionDir, languageConversion);
var projectConversion = new ProjectConversion(compilation, solutionDir, languageConversion, GetConvertedCompilationWithProjectReferences(project, languageConversion));
foreach (var conversionResult in ConvertProjectContents(projectConversion)) yield return conversionResult;
}

/// <summary>
/// If the source compilation has project references to a compilation of the same language, this will fail with an argument exception.
/// Use <see cref="GetConvertedCompilationWithProjectReferences"/> wherever this is possible.
/// </summary>
private static Compilation GetConvertedCompilation(Compilation compilation, ILanguageConversion languageConversion)
{
return languageConversion is VBToCSConversion ? CSToVBConversion.CreateCSharpCompilation(compilation.References) : (Compilation) VBToCSConversion.CreateVisualBasicCompilation(compilation.References);
}

private static Compilation GetConvertedCompilationWithProjectReferences(Project project, ILanguageConversion languageConversion)
{
return project.Solution.RemoveProject(project.Id)
.AddProject(project.Id, project.Name, project.AssemblyName, languageConversion.TargetLanguage)
.GetProject(project.Id)
.WithProjectReferences(project.AllProjectReferences).WithMetadataReferences(project.MetadataReferences)
.GetCompilationAsync().GetAwaiter().GetResult();
}

private static IEnumerable<ConversionResult> ConvertProjectContents(ProjectConversion projectConversion)
{
foreach (var pathNodePair in projectConversion.Convert())
Expand Down
15 changes: 10 additions & 5 deletions ICSharpCode.CodeConverter/Shared/SolutionConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ public class SolutionConverter
private readonly string _sourceSolutionContents;
private readonly IReadOnlyCollection<Project> _projectsToConvert;
private readonly List<(string, string)> _projectReferenceReplacements;
private readonly Action<string> _showProgressMessage;
private readonly ILanguageConversion _languageConversion;

public static SolutionConverter CreateFor<TLanguageConversion>(IReadOnlyCollection<Project> projectsToConvert) where TLanguageConversion : ILanguageConversion, new()
public static SolutionConverter CreateFor<TLanguageConversion>(IReadOnlyCollection<Project> projectsToConvert, Action<string> showProgressMessage = null) where TLanguageConversion : ILanguageConversion, new()
{
var solutionFilePath = projectsToConvert.First().Solution.FilePath;
var sourceSolutionContents = File.ReadAllText(solutionFilePath);
var projectReferenceReplacements = GetProjectReferenceReplacements(projectsToConvert, sourceSolutionContents);
return new SolutionConverter(solutionFilePath, sourceSolutionContents, projectsToConvert, projectReferenceReplacements, new TLanguageConversion());
return new SolutionConverter(solutionFilePath, sourceSolutionContents, projectsToConvert, projectReferenceReplacements, showProgressMessage, new TLanguageConversion());
}

private SolutionConverter(string solutionFilePath,
string sourceSolutionContents, IReadOnlyCollection<Project> projectsToConvert,
List<(string, string)> projectReferenceReplacements, ILanguageConversion languageConversion)
List<(string, string)> projectReferenceReplacements, Action<string> showProgressMessage,
ILanguageConversion languageConversion)
{
_solutionFilePath = solutionFilePath;
_sourceSolutionContents = sourceSolutionContents;
_projectsToConvert = projectsToConvert;
_projectReferenceReplacements = projectReferenceReplacements;
_showProgressMessage = showProgressMessage ?? (_ => {});
_languageConversion = languageConversion;
}

Expand All @@ -53,8 +56,10 @@ private IEnumerable<ConversionResult> ConvertProjects()
private IEnumerable<ConversionResult> ConvertProject(IEnumerable<(string, string)> projectFileReplacementRegexes, Project project)
{
var replacements = _projectReferenceReplacements.Concat(projectFileReplacementRegexes).ToArray();
return new[] {ConversionResultFromReplacements(project.FilePath, replacements)}
.Concat(ProjectConversion.ConvertProjectContents(project, _languageConversion));
_showProgressMessage($"Converting {project.Name}, this may take a some time...");
return ProjectConversion.ConvertProjectContents(project, _languageConversion).Concat(new[]
{ConversionResultFromReplacements(project.FilePath, replacements)}
);
}

private IEnumerable<ConversionResult> UpdateProjectReferences(IEnumerable<Project> projectsToUpdateReferencesOnly)
Expand Down
19 changes: 0 additions & 19 deletions ICSharpCode.CodeConverter/Util/ReferenceConverter.cs

This file was deleted.

22 changes: 13 additions & 9 deletions ICSharpCode.CodeConverter/VB/CSToVBConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,20 @@ namespace ICSharpCode.CodeConverter.VB
{
public class CSToVBConversion : ILanguageConversion
{
private readonly List<SyntaxTree> _firstPassResults = new List<SyntaxTree>();
private Compilation _sourceCompilation;
private VisualBasicCompilation _convertedCompilation;

private VisualBasicCompilation CreateCompilation(List<SyntaxTree> vbTrees)
public void Initialize(Compilation convertedCompilation)
{
var references = _sourceCompilation.References.Select(ReferenceConverter.ConvertReference);
return VisualBasicCompilation.Create("Conversion", vbTrees, references,
new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
_convertedCompilation = (VisualBasicCompilation) convertedCompilation;
}

public SyntaxTree SingleFirstPass(Compilation sourceCompilation, SyntaxTree tree)
{
_sourceCompilation = sourceCompilation;
var converted = CSharpConverter.ConvertCompilationTree((CSharpCompilation)sourceCompilation, (CSharpSyntaxTree)tree);
var convertedTree = VBSyntaxFactory.SyntaxTree(converted);
_firstPassResults.Add(convertedTree);
_convertedCompilation = _convertedCompilation.AddSyntaxTrees(convertedTree);
return convertedTree;
}

Expand All @@ -60,6 +58,8 @@ public SyntaxNode GetSurroundedNode(IEnumerable<SyntaxNode> descendantNodes,
};
}

public string TargetLanguage { get; } = LanguageNames.VisualBasic;

public bool CanBeContainedByMethod(SyntaxNode node)
{
return node is CSSyntax.IncompleteMemberSyntax ||
Expand Down Expand Up @@ -115,8 +115,7 @@ public SyntaxNode SingleSecondPass(KeyValuePair<string, SyntaxTree> cs)

public string GetWarningsOrNull()
{
var finalCompilation = CreateCompilation(_firstPassResults);
return CompilationWarnings.WarningsForCompilation(_sourceCompilation, "source") + CompilationWarnings.WarningsForCompilation(finalCompilation, "target");
return CompilationWarnings.WarningsForCompilation(_sourceCompilation, "source") + CompilationWarnings.WarningsForCompilation(_convertedCompilation, "target");
}

public SyntaxTree CreateTree(string text)
Expand All @@ -126,7 +125,12 @@ public SyntaxTree CreateTree(string text)

public Compilation CreateCompilationFromTree(SyntaxTree tree, IEnumerable<MetadataReference> references)
{
return CSharpCompilation.Create("Conversion", new[] { tree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
return CreateCSharpCompilation(references).AddSyntaxTrees(tree);
}

public static CSharpCompilation CreateCSharpCompilation(IEnumerable<MetadataReference> references)
{
return CSharpCompilation.Create("Conversion", references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
}
}
}
Loading