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

Fix test compile errors #539

Merged
merged 19 commits into from
Mar 11, 2020
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
10 changes: 0 additions & 10 deletions CodeConverter/CSharp/CachedReflectedDelegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ namespace ICSharpCode.CodeConverter.CSharp
/// </remarks>
internal static class CachedReflectedDelegates
{
/// <summary>
/// This method becomes public in CodeAnalysis 3.1 and hence we can be confident it won't disappear.
/// Need to use reflection for now until that version is widely enough deployed as taking a dependency would mean everyone needs latest VS version.
/// </summary>
public static readonly Lazy<Func<CompilationOptions, byte, CompilationOptions>> LazyWithMetadataImportOptions =
new Lazy<Func<CompilationOptions, byte, CompilationOptions>>(() => typeof(CompilationOptions)
.GetMethod("WithMetadataImportOptions",
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.CreateOpenInstanceDelegateForcingType<CompilationOptions, byte, CompilationOptions>());

public static bool IsMyGroupCollectionProperty(this IPropertySymbol declaredSymbol) =>
GetCachedReflectedPropertyDelegate(declaredSymbol, "IsMyGroupCollectionProperty", ref _isMyGroupCollectionProperty);
private static Func<ISymbol, bool> _isMyGroupCollectionProperty;
Expand Down
23 changes: 15 additions & 8 deletions CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,13 @@ public override async Task<CSharpSyntaxNode> VisitSimpleArgument(VBasic.Syntax.S

public override async Task<CSharpSyntaxNode> VisitNameOfExpression(VBasic.Syntax.NameOfExpressionSyntax node)
{
return SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName("nameof"), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument((ExpressionSyntax) await node.Argument.AcceptAsync(TriviaConvertingExpressionVisitor)))));
return SyntaxFactory.InvocationExpression(NameOf(), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList<ArgumentSyntax>(SyntaxFactory.Argument((ExpressionSyntax)await node.Argument.AcceptAsync(TriviaConvertingExpressionVisitor)))));
}

private static ExpressionSyntax NameOf()
{
// Usually it'd be preferable to just construct the Identifier ourselves, but the opportunity to inject parse options lets us control the LanguageVersion which needs to be high enough not to consider nameof an error
return SyntaxFactory.ParseExpression("nameof", options: CSharpCompiler.ParseOptions);
}

public override async Task<CSharpSyntaxNode> VisitEqualsValue(VBasic.Syntax.EqualsValueSyntax node)
Expand Down Expand Up @@ -486,10 +492,8 @@ public override async Task<CSharpSyntaxNode> VisitArrayCreationExpression(VBasic
{
var bounds = await CommonConversions.ConvertArrayRankSpecifierSyntaxes(node.RankSpecifiers, node.ArrayBounds);

var allowInitializer = node.Initializer.Initializers.Any()
|| node.RankSpecifiers.Any()
|| node.ArrayBounds == null
|| (node.Initializer.Initializers.Any() && node.ArrayBounds.Arguments.All(b => b.IsOmitted || _semanticModel.GetConstantValue(b.GetExpression()).HasValue));
var allowInitializer = node.ArrayBounds?.Arguments.Any() != true ||
node.Initializer.Initializers.Any() && node.ArrayBounds.Arguments.All(b => b.IsOmitted || _semanticModel.GetConstantValue(b.GetExpression()).HasValue);

var initializerToConvert = allowInitializer ? node.Initializer : null;
return SyntaxFactory.ArrayCreationExpression(
Expand All @@ -507,15 +511,18 @@ public override async Task<CSharpSyntaxNode> VisitCollectionInitializer(VBasic.S
var initializers = (await node.Initializers.SelectAsync(i => i.AcceptAsync(TriviaConvertingExpressionVisitor))).Cast<ExpressionSyntax>();
var initializer = SyntaxFactory.InitializerExpression(initializerKind, SyntaxFactory.SeparatedList(initializers));
if (isExplicitCollectionInitializer) return initializer;

if (!initializers.Any() && _semanticModel.GetTypeInfo(node).ConvertedType is IArrayTypeSymbol arrayType) {

if (!(_semanticModel.GetTypeInfo(node).ConvertedType is IArrayTypeSymbol arrayType)) return SyntaxFactory.ImplicitArrayCreationExpression(initializer);

if (!initializers.Any()) {

var arrayTypeArgs = SyntaxFactory.TypeArgumentList(SyntaxFactory.SingletonSeparatedList(CommonConversions.GetTypeSyntax(arrayType.ElementType)));
var arrayEmpty = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.IdentifierName(nameof(Array)), SyntaxFactory.GenericName(nameof(Array.Empty)).WithTypeArgumentList(arrayTypeArgs));
return SyntaxFactory.InvocationExpression(arrayEmpty);
}
return SyntaxFactory.ImplicitArrayCreationExpression(initializer);
var commas = Enumerable.Repeat(SyntaxFactory.Token(SyntaxKind.CommaToken), arrayType.Rank - 1);
return SyntaxFactory.ImplicitArrayCreationExpression(SyntaxFactory.TokenList(commas), initializer);
}

public override async Task<CSharpSyntaxNode> VisitQueryExpression(VBasic.Syntax.QueryExpressionSyntax node)
Expand Down
12 changes: 6 additions & 6 deletions CodeConverter/CSharp/ProjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ internal static class ProjectExtensions
{
private static char[] DirSeparators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };

public static Project CreateReferenceOnlyProjectFromAnyOptions(this Project project, CompilationOptions baseOptions)
public static Project CreateReferenceOnlyProjectFromAnyOptions(this Project project, CompilationOptions baseOptions, ParseOptions parseOptions)
{
var options = baseOptions.WithMetadataImportOptionsAll();
var options = baseOptions.WithMetadataImportOptions(MetadataImportOptions.All);
var viewerId = ProjectId.CreateNewId();
var projectReferences = project.ProjectReferences.Concat(new[] {new ProjectReference(project.Id)});
var viewerProjectInfo = project.ToProjectInfo(viewerId, project.Name + viewerId, options,
projectReferences);
projectReferences, parseOptions);
var csharpViewOfVbProject = project.Solution.AddProject(viewerProjectInfo).GetProject(viewerId);
return csharpViewOfVbProject;
}
Expand Down Expand Up @@ -70,10 +70,10 @@ public static (Project project, List<WipFileConversion<DocumentId>> firstPassDoc
DocumentId docId = null;
if (firstPassResult.Wip != null)
{
var document = project.AddDocument(firstPassResult.Path, firstPassResult.Wip,
docId = DocumentId.CreateNewId(project.Id);
var solution = project.Solution.AddDocument(docId, firstPassResult.Path, firstPassResult.Wip,
filePath: firstPassResult.Path);
project = document.Project;
docId = document.Id;
project = solution.GetProject(project.Id);
}

return WipFileConversion.Create(firstPassResult.Path, docId, firstPassResult.Errors);
Expand Down
18 changes: 9 additions & 9 deletions CodeConverter/CSharp/ProjectMergedDeclarationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.VisualBasic;
using System.Threading;
using System.Collections.Generic;

namespace ICSharpCode.CodeConverter.CSharp
{
Expand All @@ -26,11 +27,12 @@ public static async Task<Project> WithRenamedMergedMyNamespace(this Project vbPr
var projectDir = Path.Combine(vbProject.GetDirectoryPath(), "My Project");

var compilation = await vbProject.GetCompilationAsync(cancellationToken);
string embeddedSourceText = (await GetAllEmbeddedSourceText(compilation));
string generatedSourceText = (await GetDynamicallyGeneratedSourceText(compilation));
var embeddedSourceTexts = await GetAllEmbeddedSourceText(compilation).Select((r, i) => (Text: r, Suffix: $".Static.{i+1}")).ToArrayAsync();
var generatedSourceTexts = (Text: await GetDynamicallyGeneratedSourceText(compilation), Suffix: ".Dynamic").Yield();

vbProject = WithRenamespacedDocument(name + ".Static", vbProject, embeddedSourceText, projectDir);
vbProject = WithRenamespacedDocument(name + ".Dynamic", vbProject, generatedSourceText, projectDir);
foreach (var (text, suffix) in embeddedSourceTexts.Concat(generatedSourceTexts)) {
vbProject = WithRenamespacedDocument(name + suffix, vbProject, text, projectDir);
}

return vbProject;
}
Expand All @@ -41,15 +43,12 @@ private static Project WithRenamespacedDocument(string baseName, Project vbProje
return vbProject.AddDocument(baseName, sourceText.Renamespace(), filePath: Path.Combine(myProjectDirPath, baseName + ".Designer.vb")).Project;
}

private static async Task<string> GetAllEmbeddedSourceText(Compilation compilation)
private static async IAsyncEnumerable<string> GetAllEmbeddedSourceText(Compilation compilation)
{
var roots = await compilation.SourceModule.GlobalNamespace.Locations.
Where(l => !l.IsInSource).Select(CachedReflectedDelegates.GetEmbeddedSyntaxTree)
.SelectAsync(t => t.GetTextAsync());
var renamespacesRootTexts =
roots.Select(r => r.ToString());
var combined = string.Join(Environment.NewLine, renamespacesRootTexts);
return combined;
foreach (var r in roots) yield return r.ToString();
}

private static async Task<string> GetDynamicallyGeneratedSourceText(Compilation compilation)
Expand Down Expand Up @@ -109,6 +108,7 @@ private static string Renamespace(this string sourceText)
{
return sourceText
.Replace("Namespace Global.Microsoft.VisualBasic", $"Namespace Global.Microsoft.{Constants.MergedMsVbNamespace}")
.Replace("Global.Microsoft.VisualBasic.Embedded", $"Global.Microsoft.{Constants.MergedMsVbNamespace}.Embedded")
.Replace("Namespace My", $"Namespace {Constants.MergedMyNamespace}");
}

Expand Down
12 changes: 2 additions & 10 deletions CodeConverter/CSharp/VBToCSProjectContentsConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,6 @@ internal class VBToCSProjectContentsConverter : IProjectContentsConverter
private CSharpCompilation _csharpViewOfVbSymbols;
private Project _convertedCsProject;

/// <summary>
/// It's really hard to change simplifier options since everything is done on the Object hashcode of internal fields.
/// I wanted to avoid saying "default" instead of "default(string)" because I don't want to force a later language version on people in such a common case.
/// This will have that effect, but also has the possibility of failing to interpret code output by this converter.
/// If this has such unintended effects in future, investigate the code that loads options from an editorconfig file
/// </summary>
private static readonly CSharpParseOptions DoNotAllowImplicitDefault = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7);

private Project _csharpReferenceProject;
private readonly IProgress<ConversionProgress> _progress;
private readonly CancellationToken _cancellationToken;
Expand All @@ -45,8 +37,8 @@ public VBToCSProjectContentsConverter(ConversionOptions conversionOptions, IProg
public async Task InitializeSourceAsync(Project project)
{
var cSharpCompilationOptions = CSharpCompiler.CreateCompilationOptions();
_convertedCsProject = project.ToProjectFromAnyOptions(cSharpCompilationOptions, DoNotAllowImplicitDefault);
_csharpReferenceProject = project.CreateReferenceOnlyProjectFromAnyOptions(cSharpCompilationOptions);
_convertedCsProject = project.ToProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);
_csharpReferenceProject = project.CreateReferenceOnlyProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);
_csharpViewOfVbSymbols = (CSharpCompilation) await _csharpReferenceProject.GetCompilationAsync(_cancellationToken);
Project = await project.WithRenamedMergedMyNamespace(_cancellationToken);
}
Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/ConversionResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public string GetExceptionsAsString()
public void WriteToFile()
{
Directory.CreateDirectory(Path.GetDirectoryName(TargetPathOrNull));
File.WriteAllText(TargetPathOrNull, ConvertedCode, Encoding.UTF8);
File.WriteAllText(TargetPathOrNull, ConvertedCode ?? GetExceptionsAsString(), Encoding.UTF8);
}
}
}
5 changes: 0 additions & 5 deletions CodeConverter/Shared/CompilationOptionsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,5 @@ public static Document CreateProjectDocumentFromTree(this CompilationOptions opt
.WithMetadataReferences(references);
return project.AddDocument("CodeToConvert", tree.GetRoot(), filePath: Path.Combine(Directory.GetCurrentDirectory(), "TempCodeToConvert.txt"));
}

public static CompilationOptions WithMetadataImportOptionsAll(this CompilationOptions baseOptions)
{
return CachedReflectedDelegates.LazyWithMetadataImportOptions.Value(baseOptions, 2 /*MetadataImportOptions.All*/);
}
}
}
18 changes: 7 additions & 11 deletions CodeConverter/Shared/ProjectConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,19 @@ public class ProjectConversion
{
private readonly IReadOnlyCollection<Document> _documentsToConvert;
private readonly ILanguageConversion _languageConversion;
private readonly bool _showCompilationErrors =
#if DEBUG && ShowCompilationErrors
true;
#else
false;
#endif
private readonly bool _showCompilationErrors;
private readonly bool _returnSelectedNode;
private static readonly string[] BannedPaths = new[] { ".AssemblyAttributes.", "\\bin\\", "\\obj\\" };
private readonly IProjectContentsConverter _projectContentsConverter;
private readonly CancellationToken _cancellationToken;

private ProjectConversion(IProjectContentsConverter projectContentsConverter, IEnumerable<Document> documentsToConvert,
ILanguageConversion languageConversion, CancellationToken cancellationToken, bool returnSelectedNode = false)
ILanguageConversion languageConversion, CancellationToken cancellationToken, bool showCompilationErrors, bool returnSelectedNode = false)
{
_projectContentsConverter = projectContentsConverter;
_languageConversion = languageConversion;
_documentsToConvert = documentsToConvert.ToList();
_showCompilationErrors = showCompilationErrors;
_returnSelectedNode = returnSelectedNode;
_cancellationToken = cancellationToken;
}
Expand Down Expand Up @@ -69,7 +65,7 @@ private ProjectConversion(IProjectContentsConverter projectContentsConverter, IE

document = projectContentsConverter.Project.GetDocument(document.Id);

var conversion = new ProjectConversion(projectContentsConverter, new[] { document }, languageConversion, cancellationToken, returnSelectedNode);
var conversion = new ProjectConversion(projectContentsConverter, new[] { document }, languageConversion, cancellationToken, conversionOptions.ShowCompilationErrors, returnSelectedNode);
var conversionResults = await conversion.Convert(progress).ToArrayAsync();
var codeResult = conversionResults.SingleOrDefault(x => !string.IsNullOrWhiteSpace(x.ConvertedCode))
?? conversionResults.First();
Expand Down Expand Up @@ -154,7 +150,7 @@ private static async IAsyncEnumerable<ConversionResult> ConvertProjectContents(
//Perf heuristic: Decrease memory pressure on the simplification phase by converting large files first https://github.com/icsharpcode/CodeConverter/issues/524#issuecomment-590301594
var documentsToConvert = documentsWithLengths.OrderByDescending(d => d.Length).Select(d => d.Doc);

var projectConversion = new ProjectConversion(projectContentsConverter, documentsToConvert, languageConversion, cancellationToken);
var projectConversion = new ProjectConversion(projectContentsConverter, documentsToConvert, languageConversion, cancellationToken, false);

var results = projectConversion.Convert(progress);
await foreach (var result in results) yield return result;
Expand All @@ -168,8 +164,8 @@ private async IAsyncEnumerable<ConversionResult> Convert(IProgress<ConversionPro
var (proj1, docs1) = await _projectContentsConverter.GetConvertedProject(await firstPassResults.ToArrayAsync());

var warnings = await GetProjectWarnings(_projectContentsConverter.Project, proj1);
if (warnings != null) {
var warningPath = Path.Combine(proj1.GetDirectoryPath(), "ConversionWarnings.txt");
if (!string.IsNullOrWhiteSpace(warnings)) {
var warningPath = Path.Combine(_projectContentsConverter.Project.GetDirectoryPath(), "ConversionWarnings.txt");
yield return new ConversionResult() { SourcePathOrNull = warningPath, Exceptions = new[] { warnings } };
}

Expand Down
1 change: 1 addition & 0 deletions CodeConverter/Shared/SingleConversionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ namespace ICSharpCode.CodeConverter.Shared
public class SingleConversionOptions : ConversionOptions
{
public TextSpan SelectedTextSpan { get; set; } = new TextSpan();
internal bool ShowCompilationErrors { get; set; }
}
}
6 changes: 4 additions & 2 deletions CodeConverter/Util/CSharpCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class CSharpCompiler : ICompiler

public SyntaxTree CreateTree(string text)
{
return SyntaxFactory.ParseSyntaxTree(text, encoding: Encoding.UTF8);
return SyntaxFactory.ParseSyntaxTree(text, ParseOptions, encoding: Encoding.UTF8);
}

public Compilation CreateCompilationFromTree(SyntaxTree tree, IEnumerable<MetadataReference> references)
Expand All @@ -34,7 +34,9 @@ private static CSharpCompilation CreateCSharpCompilation()

public static CSharpCompilationOptions CreateCompilationOptions()
{
return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true);
}

public static CSharpParseOptions ParseOptions { get; } = new CSharpParseOptions(LanguageVersion.Latest);
}
}
3 changes: 2 additions & 1 deletion CodeConverter/Util/CompilationWarnings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static string WarningsForCompilation(Compilation finalCompilation, string
{
var targetErrors = GetDiagnostics(finalCompilation);
return targetErrors.Any()
? $"{targetErrors.Count} {compilationDescription} compilation errors:{Environment.NewLine}{String.Join(Environment.NewLine, targetErrors)}"
? $"{Environment.NewLine}{targetErrors.Count} {compilationDescription} compilation errors:{Environment.NewLine}{String.Join(Environment.NewLine, targetErrors)}"
: null;
}

Expand All @@ -20,6 +20,7 @@ private static List<string> GetDiagnostics(Compilation compilation)
var diagnostics = compilation.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
.Select(d => $"{d.Id}: {d.GetMessage()}")
.Distinct()
.ToList();
return diagnostics;
}
Expand Down
4 changes: 3 additions & 1 deletion CodeConverter/Util/VisualBasicCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public VisualBasicCompiler(string rootNamespace)

public SyntaxTree CreateTree(string text)
{
return SyntaxFactory.ParseSyntaxTree(text, encoding: Encoding.UTF8);
return SyntaxFactory.ParseSyntaxTree(text, ParseOptions, encoding: Encoding.UTF8);
}

public Compilation CreateCompilationFromTree(SyntaxTree tree, IEnumerable<MetadataReference> references)
Expand Down Expand Up @@ -75,5 +75,7 @@ public static VisualBasicCompilationOptions CreateCompilationOptions(string root
.WithRootNamespace(rootNamespace);
return compilationOptions;
}

public static VisualBasicParseOptions ParseOptions { get; } = new VisualBasicParseOptions(LanguageVersion.Latest);
}
}
Loading