|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
public class ImportsTest : CSharpTestBase
{
[Fact]
public void ConcatEmpty()
{
var empty = Imports.Empty;
var nonEmpty = GetImports("using System;").Single();
Assert.Same(empty, empty.Concat(empty));
Assert.Same(nonEmpty, nonEmpty.Concat(empty));
Assert.Same(nonEmpty, empty.Concat(nonEmpty));
}
[Fact]
public void ConcatDistinct()
{
var imports = GetImports(@"
extern alias A;
using System;
using C = System;
", @"
extern alias B;
using System.IO;
using D = System.IO;
");
var concat1 = imports[0].Concat(imports[1]);
Assert.Equal(new[] { "A", "B" }, concat1.ExternAliases.Select(e => e.Alias.Name));
Assert.Equal(new[] { "System", "System.IO" }, concat1.Usings.Select(u => u.NamespaceOrType.ToTestDisplayString()));
var usingAliases1 = concat1.UsingAliases;
AssertEx.SetEqual(new[] { "C", "D" }, usingAliases1.Select(a => a.Key));
Assert.Equal("System", usingAliases1["C"].Alias.Target.ToTestDisplayString());
Assert.Equal("System.IO", usingAliases1["D"].Alias.Target.ToTestDisplayString());
var concat2 = imports[1].Concat(imports[0]);
Assert.Equal(new[] { "B", "A" }, concat2.ExternAliases.Select(e => e.Alias.Name));
Assert.Equal(new[] { "System.IO", "System" }, concat2.Usings.Select(u => u.NamespaceOrType.ToTestDisplayString()));
var usingAliases2 = concat2.UsingAliases;
AssertEx.SetEqual(new[] { "C", "D" }, usingAliases2.Select(a => a.Key));
Assert.Equal("System", usingAliases2["C"].Alias.Target.ToTestDisplayString());
Assert.Equal("System.IO", usingAliases2["D"].Alias.Target.ToTestDisplayString());
}
[Fact]
public void ConcatColliding()
{
var imports = GetImports(@"
extern alias A;
extern alias B;
using System;
using System.Collections;
using D = System;
using E = System;
", @"
extern alias A;
extern alias C;
using System;
using System.IO;
using D = System.IO;
using F = System.IO;
");
var concat1 = imports[0].Concat(imports[1]);
Assert.Equal(new[] { "B", "A", "C" }, concat1.ExternAliases.Select(e => e.Alias.Name));
Assert.Equal(new[] { "System", "System.Collections", "System.IO" }, concat1.Usings.Select(u => u.NamespaceOrType.ToTestDisplayString()));
var usingAliases1 = concat1.UsingAliases;
AssertEx.SetEqual(new[] { "D", "E", "F" }, usingAliases1.Select(a => a.Key));
Assert.Equal("System.IO", usingAliases1["D"].Alias.Target.ToTestDisplayString()); // Last one wins
Assert.Equal("System", usingAliases1["E"].Alias.Target.ToTestDisplayString());
Assert.Equal("System.IO", usingAliases1["F"].Alias.Target.ToTestDisplayString());
var concat2 = imports[1].Concat(imports[0]);
Assert.Equal(new[] { "C", "A", "B" }, concat2.ExternAliases.Select(e => e.Alias.Name));
Assert.Equal(new[] { "System", "System.IO", "System.Collections" }, concat2.Usings.Select(u => u.NamespaceOrType.ToTestDisplayString()));
var usingAliases2 = concat2.UsingAliases;
AssertEx.SetEqual(new[] { "D", "E", "F" }, usingAliases2.Select(a => a.Key));
Assert.Equal("System", usingAliases2["D"].Alias.Target.ToTestDisplayString()); // Last one wins
Assert.Equal("System", usingAliases2["E"].Alias.Target.ToTestDisplayString());
Assert.Equal("System.IO", usingAliases2["F"].Alias.Target.ToTestDisplayString());
}
[Fact]
public void ConcatCollidingExternAliases()
{
var comp = CreateCompilation(
"extern alias A; extern alias B;",
targetFramework: TargetFramework.Mscorlib40,
references: new[]
{
SystemCoreRef.WithAliases(new[] { "A" }),
SystemDataRef.WithAliases(new[] { "B" }),
});
var tree = comp.SyntaxTrees.Single();
var binder = comp.GetBinderFactory(tree).GetInNamespaceBinder((CSharpSyntaxNode)tree.GetRoot());
var scratchImports = binder.ImportChain.Imports;
var scratchExternAliases = scratchImports.ExternAliases;
Assert.Equal(2, scratchExternAliases.Length);
var externAlias1 = scratchExternAliases[0];
var externAlias2 = new AliasAndExternAliasDirective(
AliasSymbol.CreateCustomDebugInfoAlias(scratchExternAliases[1].Alias.Target, externAlias1.ExternAliasDirective.Identifier, binder.ContainingMemberOrLambda, isExtern: true),
externAlias1.ExternAliasDirective, skipInLookup: false);
var imports1 = Imports.Create(
ImmutableDictionary<string, AliasAndUsingDirective>.Empty,
ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty,
ImmutableArray.Create(externAlias1));
var imports2 = Imports.Create(
ImmutableDictionary<string, AliasAndUsingDirective>.Empty,
ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty,
ImmutableArray.Create(externAlias2));
var concat1 = imports1.Concat(imports2);
Assert.Equal(externAlias2.Alias.Target, concat1.ExternAliases.Single().Alias.Target);
var concat2 = imports2.Concat(imports1);
Assert.Equal(externAlias1.Alias.Target, concat2.ExternAliases.Single().Alias.Target);
}
private static Imports[] GetImports(params string[] sources)
{
var trees = sources.Select(source => Parse(source)).ToArray();
var compilationUnits = trees.Select(tree => (CompilationUnitSyntax)tree.GetRoot());
var externAliases = compilationUnits.SelectMany(cu => cu.Externs).Select(e => e.Identifier.ValueText).Distinct();
var comp = CreateCompilation(trees, targetFramework: TargetFramework.Mscorlib40, references: new[] { SystemCoreRef.WithAliases(externAliases) });
comp.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Verify();
var factories = trees.Select(tree => comp.GetBinderFactory(tree));
var binders = factories.Select(factory => factory.GetInNamespaceBinder((CSharpSyntaxNode)factory.SyntaxTree.GetRoot()));
var imports = binders.Select(binder => binder.ImportChain.Imports);
Assert.DoesNotContain(Imports.Empty, imports);
return imports.ToArray();
}
}
}
|