Skip to content

Commit

Permalink
Try to use project references to avoid reference conversion
Browse files Browse the repository at this point in the history
The previous issue was that copying metadata references directly between compilations wasn't working for `CompilationReference`s.
Originally I thought it was only possible to reference a compilation of the same type, and hence copying references wouldn't work, but now I suspect it just needs an accompanying project reference
  • Loading branch information
GrahamTheCoder committed Aug 18, 2018
1 parent 509da77 commit aca11a2
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 47 deletions.
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);
}
}
28 changes: 23 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,24 +58,38 @@ 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();
codeResult.Exceptions = conversionResults.SelectMany(x => x.Exceptions).ToArray();
return codeResult;
}

private static Compilation GetConvertedCompilation(Compilation compilation, ILanguageConversion languageConversion)
{
return languageConversion is VBToCSConversion ? CSToVBConversion.CreateCSharpCompilation(compilation.References) : (Compilation) VBToCSConversion.CreateVisualBasicCompilation(compilation.References);
}

public static IEnumerable<ConversionResult> ConvertProjectContents(Project project,
ILanguageConversion languageConversion)
{
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, GetConvertedProjectCompilation(project, languageConversion));
foreach (var conversionResult in ConvertProjectContents(projectConversion)) yield return conversionResult;
}

private static Compilation GetConvertedProjectCompilation(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
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));
}
}
}

0 comments on commit aca11a2

Please sign in to comment.