提交 7cd8fdfb 编写于 作者: V vladres

Implements User Story 1085744: New design for 'using static' directives (changeset 1380564)

上级 4ff68fb1
......@@ -107,31 +107,36 @@ internal sealed class Imports
var uniqueUsings = new HashSet<NamespaceOrTypeSymbol>();
foreach (var u in usingDirectives)
foreach (var usingDirective in usingDirectives)
{
binder.Compilation.RecordImport(u);
binder.Compilation.RecordImport(usingDirective);
if (u.Alias != null)
if (usingDirective.Alias != null)
{
string identifierValueText = u.Alias.Name.Identifier.ValueText;
if (usingDirective.StaticKeyword != default(SyntaxToken))
{
diagnostics.Add(ErrorCode.ERR_NoAliasHere, usingDirective.Alias.Name.Location);
}
string identifierValueText = usingDirective.Alias.Name.Identifier.ValueText;
if (usingAliases != null && usingAliases.ContainsKey(identifierValueText))
{
// Suppress diagnostics if we're already broken.
if (!u.Name.IsMissing)
if (!usingDirective.Name.IsMissing)
{
// The using alias '{0}' appeared previously in this namespace
diagnostics.Add(ErrorCode.ERR_DuplicateAlias, u.Alias.Name.Location, identifierValueText);
diagnostics.Add(ErrorCode.ERR_DuplicateAlias, usingDirective.Alias.Name.Location, identifierValueText);
}
}
else
{
//EDMAURER an O(m*n) algorithm here but n (number of extern aliases) will likely be very small.
foreach (var e in externAliases)
foreach (var externAlias in externAliases)
{
if (e.Alias.Name == identifierValueText)
if (externAlias.Alias.Name == identifierValueText)
{
// The using alias '{0}' appeared previously in this namespace
diagnostics.Add(ErrorCode.ERR_DuplicateAlias, u.Location, identifierValueText);
diagnostics.Add(ErrorCode.ERR_DuplicateAlias, usingDirective.Location, identifierValueText);
break;
}
}
......@@ -143,63 +148,61 @@ internal sealed class Imports
// EDMAURER construct the alias sym with the binder for which we are building imports. That
// way the alias target can make use of extern alias definitions.
usingAliases.Add(identifierValueText, new AliasAndUsingDirective(new AliasSymbol(usingsBinder, u), u));
usingAliases.Add(identifierValueText, new AliasAndUsingDirective(new AliasSymbol(usingsBinder, usingDirective), usingDirective));
}
}
else
{
if (u.Name.IsMissing)
if (usingDirective.Name.IsMissing)
{
//don't try to lookup namespaces inserted by parser error recovery
continue;
}
var imported = usingsBinder.BindNamespaceOrTypeSymbol(u.Name, diagnostics, basesBeingResolved);
var imported = usingsBinder.BindNamespaceOrTypeSymbol(usingDirective.Name, diagnostics, basesBeingResolved);
if (imported.Kind == SymbolKind.Namespace)
{
if (uniqueUsings.Contains(imported))
if (usingDirective.StaticKeyword != default(SyntaxToken))
{
diagnostics.Add(ErrorCode.ERR_BadUsingType, usingDirective.Name.Location, imported);
}
else if (uniqueUsings.Contains(imported))
{
diagnostics.Add(ErrorCode.WRN_DuplicateUsing, u.Name.Location, imported);
diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, imported);
}
else
{
uniqueUsings.Add(imported);
usings.Add(new NamespaceOrTypeAndUsingDirective(imported, u));
usings.Add(new NamespaceOrTypeAndUsingDirective(imported, usingDirective));
}
}
else if (imported.Kind == SymbolKind.NamedType)
{
var importedType = (NamedTypeSymbol)imported;
if (!binder.AllowStaticClassUsings)
if (usingDirective.StaticKeyword == default(SyntaxToken))
{
// error: A using directive can only be applied to namespace; '{0}' is a type not a namespace
diagnostics.Add(ErrorCode.ERR_BadUsingNamespace, u.Name.Location, importedType);
diagnostics.Add(ErrorCode.ERR_BadUsingNamespace, usingDirective.Name.Location, imported);
}
else if (importedType.IsStatic && importedType.TypeKind == TypeKind.Class)
else
{
var importedType = (NamedTypeSymbol)imported;
if (uniqueUsings.Contains(importedType))
{
diagnostics.Add(ErrorCode.WRN_DuplicateUsing, u.Name.Location, importedType);
diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, importedType);
}
else
{
uniqueUsings.Add(importedType);
usings.Add(new NamespaceOrTypeAndUsingDirective(importedType, u));
usings.Add(new NamespaceOrTypeAndUsingDirective(importedType, usingDirective));
}
}
else
{
// error: A using directive can only be applied to classes that are static; '{0}' is not a static class
diagnostics.Add(ErrorCode.ERR_BadUsingType, u.Name.Location, importedType);
}
}
else if (imported.Kind != SymbolKind.ErrorType)
{
// Do not report additional error if the symbol itself is erroneous.
// error: '<symbol>' is a '<symbol kind>' but is used as 'type or namespace'
diagnostics.Add(ErrorCode.ERR_BadSKknown, u.Name.Location,
u.Name,
diagnostics.Add(ErrorCode.ERR_BadSKknown, usingDirective.Name.Location,
usingDirective.Name,
imported.GetKindText(),
MessageID.IDS_SK_TYPE_OR_NAMESPACE.Localize());
}
......@@ -473,10 +476,37 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel)
{
ImmutableArray<Symbol> candidates = Binder.GetCandidateMembers(typeOrNamespace.NamespaceOrType, name, options, originalBinder: originalBinder);
foreach (Symbol symbol in candidates)
{
switch (symbol.Kind)
{
// lookup via "using namespace" ignores namespaces inside
if (symbol.Kind != SymbolKind.Namespace)
case SymbolKind.Namespace:
continue;
// lookup via "using static" ignores extension methods and non-static methods
case SymbolKind.Method:
if (!symbol.IsStatic || ((MethodSymbol)symbol).IsExtensionMethod)
{
continue;
}
break;
// types are considered static members for purposes of "using static" feature
// regardless of whether they are declared with "static" modifier or not
case SymbolKind.NamedType:
break;
// lookup via "using static" ignores non-static members
default:
if (!symbol.IsStatic)
{
continue;
}
break;
}
// Found a match in our list of normal using directives. Mark the directive
// as being seen so that it won't be reported to the user as something that
// can be removed.
......@@ -490,7 +520,6 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel)
}
}
}
}
internal void LookupExtensionMethodsInUsings(
ArrayBuilder<MethodSymbol> methods,
......
......@@ -1853,7 +1853,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to A using namespace directive can only be applied to namespaces; &apos;{0}&apos; is a type not a namespace.
/// Looks up a localized string similar to A &apos;using namespace&apos; directive can only be applied to namespaces; &apos;{0}&apos; is a type not a namespace. Consider using a &apos;using static&apos; directive instead.
/// </summary>
internal static string ERR_BadUsingNamespace {
get {
......@@ -1862,7 +1862,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to A using directive can only be applied to static classes or namespaces; the type &apos;{0}&apos; is not a static class.
/// Looks up a localized string similar to A &apos;using static&apos; directive can only be applied to types; &apos;{0}&apos; is a namespace not a type. Consider using a &apos;using namespace&apos; directive instead.
/// </summary>
internal static string ERR_BadUsingType {
get {
......@@ -4948,6 +4948,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Assembly culture strings may not contain embedded NUL characters..
/// </summary>
internal static string ERR_InvalidAssemblyCulture {
get {
return ResourceManager.GetString("ERR_InvalidAssemblyCulture", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Executables cannot be satellite assemblies; culture should always be empty.
/// </summary>
......@@ -5911,6 +5920,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to A &apos;using static&apos; directive cannot be used to declare an alias.
/// </summary>
internal static string ERR_NoAliasHere {
get {
return ResourceManager.GetString("ERR_NoAliasHere", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A base class is required for a &apos;base&apos; reference.
/// </summary>
......@@ -8990,6 +9008,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to using static.
/// </summary>
internal static string IDS_FeatureUsingStatic {
get {
return ResourceManager.GetString("IDS_FeatureUsingStatic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to fixed variable.
/// </summary>
......
......@@ -631,10 +631,13 @@
<value>A local or parameter named '{0}' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter</value>
</data>
<data name="ERR_BadUsingNamespace" xml:space="preserve">
<value>A using namespace directive can only be applied to namespaces; '{0}' is a type not a namespace</value>
<value>A 'using namespace' directive can only be applied to namespaces; '{0}' is a type not a namespace. Consider using a 'using static' directive instead</value>
</data>
<data name="ERR_BadUsingType" xml:space="preserve">
<value>A using directive can only be applied to static classes or namespaces; the type '{0}' is not a static class</value>
<value>A 'using static' directive can only be applied to types; '{0}' is a namespace not a type. Consider using a 'using namespace' directive instead</value>
</data>
<data name="ERR_NoAliasHere" xml:space="preserve">
<value>A 'using static' directive cannot be used to declare an alias</value>
</data>
<data name="ERR_NoBreakOrCont" xml:space="preserve">
<value>No enclosing loop out of which to break or continue</value>
......@@ -3993,4 +3996,7 @@
<data name="ERR_InvalidAssemblyCulture" xml:space="preserve">
<value>Assembly culture strings may not contain embedded NUL characters.</value>
</data>
<data name="IDS_FeatureUsingStatic" xml:space="preserve">
<value>using static</value>
</data>
</root>
\ No newline at end of file
......@@ -1296,5 +1296,6 @@ internal enum ErrorCode
ERR_SubexpressionNotInNameof = 8082,
ERR_AliasQualifiedNameNotAnExpression = 8083,
ERR_NameofMethodGroupWithTypeParameters = 8084,
ERR_NoAliasHere = 8085,
}
}
......@@ -106,6 +106,8 @@ internal enum MessageID
IDS_LogoLine1 = MessageBase + 12698,
IDS_LogoLine2 = MessageBase + 12699,
IDS_CSCHelp = MessageBase + 12700,
IDS_FeatureUsingStatic = MessageBase + 12701,
}
// Message IDs may refer to strings that need to be localized.
......@@ -150,6 +152,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureNameof:
case MessageID.IDS_FeatureDictionaryInitializer:
case MessageID.IDS_FeatureStructParameterlessConstructors:
case MessageID.IDS_FeatureUsingStatic:
return LanguageVersion.CSharp6;
// C# 5 features.
......
......@@ -933,6 +933,12 @@ private UsingDirectiveSyntax ParseUsingDirective()
var usingToken = this.EatToken(SyntaxKind.UsingKeyword);
var staticToken = default(SyntaxToken);
if (this.CurrentToken.Kind == SyntaxKind.StaticKeyword)
{
staticToken = this.EatToken(SyntaxKind.StaticKeyword);
}
NameEqualsSyntax alias = null;
if (this.IsNamedAssignment())
{
......@@ -975,7 +981,13 @@ private UsingDirectiveSyntax ParseUsingDirective()
semicolon = this.EatToken(SyntaxKind.SemicolonToken);
}
return syntaxFactory.UsingDirective(usingToken, alias, name, semicolon);
var usingDirective = syntaxFactory.UsingDirective(usingToken, staticToken, alias, name, semicolon);
if (staticToken != default(SyntaxToken))
{
usingDirective = CheckFeatureAvailability(usingDirective, MessageID.IDS_FeatureUsingStatic);
}
return usingDirective;
}
private bool IsPossibleGlobalAttributeDeclaration()
......
......@@ -2181,6 +2181,7 @@
<Field Name="UsingKeyword" Type="SyntaxToken">
<Kind Name="UsingKeyword"/>
</Field>
<Field Name="StaticKeyword" Type="SyntaxToken" Optional="true"/>
<Field Name="Alias" Type="NameEqualsSyntax" Optional="true"/>
<Field Name="Name" Type="NameSyntax"/>
<Field Name="SemicolonToken" Type="SyntaxToken">
......
......@@ -1969,5 +1969,16 @@ public static BlockSyntax Block(IEnumerable<StatementSyntax> statements)
accessorList: accessorList,
expressionBody: default(ArrowExpressionClauseSyntax));
}
/// <summary>Creates a new UsingDirectiveSyntax instance.</summary>
public static UsingDirectiveSyntax UsingDirective(NameEqualsSyntax alias, NameSyntax name)
{
return UsingDirective(
usingKeyword: Token(SyntaxKind.UsingKeyword),
staticKeyword: default(SyntaxToken),
alias: alias,
name: name,
semicolonToken: Token(SyntaxKind.SemicolonToken));
}
}
}
\ No newline at end of file
......@@ -5919,9 +5919,9 @@ class System : Attribute
// (2,7): warning CS0437: The type 'System' in '' conflicts with the imported namespace 'System' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
// using System;
Diagnostic(ErrorCode.WRN_SameFullNameThisAggNs, "System").WithArguments("", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System"),
// (2,7): error CS7007: A using directive can only be applied to static classes or namespaces; 'System' is a non-static class
// (2,7): error CS0138: A 'using namespace' directive can only be applied to namespaces; 'System' is a type not a namespace. Consider using a 'using static' directive instead
// using System;
Diagnostic(ErrorCode.ERR_BadUsingType, "System").WithArguments("System").WithLocation(2, 7),
Diagnostic(ErrorCode.ERR_BadUsingNamespace, "System").WithArguments("System").WithLocation(2, 7),
// (4,16): error CS0246: The type or namespace name 'Attribute' could not be found (are you missing a using directive or an assembly reference?)
// class System : Attribute
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Attribute").WithArguments("Attribute"),
......
......@@ -1994,7 +1994,7 @@ static void Main()
public void StaticType()
{
var source = @"
using System.Math;
using static System.Math;
class D
{
......
......@@ -1872,8 +1872,8 @@ static void Main()
public void Bug879811_1()
{
const string source = @"
using Static<string>;
using Static<int>;
using static Static<string>;
using static Static<int>;
public static class Static<T>
{
......@@ -1902,8 +1902,8 @@ static void Main(string[] args)
public void Bug879811_2()
{
const string source = @"
using Static<string>;
using Static<System.String>;
using static Static<string>;
using static Static<System.String>;
public static class Static<T>
{
......@@ -1923,10 +1923,10 @@ static void Main()
CreateCompilationWithMscorlib(source).VerifyDiagnostics(
// (3,7): warning CS0105: The using directive for 'Static<string>' appeared previously in this namespace
// using Static<System.String>;
Diagnostic(ErrorCode.WRN_DuplicateUsing, "Static<System.String>").WithArguments("Static<string>").WithLocation(3, 7),
Diagnostic(ErrorCode.WRN_DuplicateUsing, "Static<System.String>").WithArguments("Static<string>").WithLocation(3, 14),
// (3,1): hidden CS8019: Unnecessary using directive.
// using Static<System.String>;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Static<System.String>;").WithLocation(3, 1));
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Static<System.String>;").WithLocation(3, 1));
}
[Fact]
......@@ -1934,7 +1934,7 @@ static void Main()
public void Bug879811_3()
{
const string source = @"
using Static<string>;
using static Static<string>;
public static class Static<T>
{
......@@ -1946,7 +1946,7 @@ public class Nested
namespace N
{
using Static<int>;
using static Static<int>;
class D
{
static void Main()
......@@ -1958,7 +1958,7 @@ static void Main()
CreateCompilationWithMscorlib(source).VerifyDiagnostics(
// (2,1): hidden CS8019: Unnecessary using directive.
// using Static<string>;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Static<string>;").WithLocation(2, 1));
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Static<string>;").WithLocation(2, 1));
}
}
}
......@@ -7061,7 +7061,7 @@ public static int Test(this int o)
namespace C
{
using A.B;
using A.C.X;
using static A.C.X;
class M
{
public static int Main()
......
......@@ -2652,11 +2652,11 @@ public static void foo(string a)
namespace A
{
using S1;
using static S1;
namespace B
{
using S2;
using static S2;
public static class Z
{
......
......@@ -3331,7 +3331,35 @@ public void ExtensionMethodFromUsingStatic()
{
const string source = @"
using System;
using N.S;
using static N.S;
class Program
{
static void Main()
{
1.Foo();
}
}
namespace N
{
static class S
{
public static void Foo(this int x)
{
Console.Write(x);
}
}
}";
CompileAndVerify(source, expectedOutput: "1");
}
[Fact, WorkItem(1085744, "DevDiv")]
public void ExtensionMethodsAreNotImportedAsSimpleNames()
{
const string source = @"
using System;
using static N.S;
class Program
{
......@@ -3352,7 +3380,11 @@ public static void Foo(this int x)
}
}
}";
CompileAndVerify(source, expectedOutput: "11");
var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
compilation.VerifyDiagnostics(
// (10,9): error CS0103: The name 'Foo' does not exist in the current context
// Foo(1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "Foo").WithArguments("Foo").WithLocation(10, 9));
}
[Fact, WorkItem(1010648, "DevDiv")]
......@@ -3361,7 +3393,7 @@ public void ExtensionMethodImportedTwiceNoErrors()
const string source = @"
using System;
using N;
using N.S;
using static N.S;
class Program
{
......@@ -3389,7 +3421,7 @@ public void ExtensionMethodIsNotDisambiguatedByUsingStaticAtTheSameLevel()
{
const string source = @"
using N;
using N.S;
using static N.S;
class Program
{
......@@ -3431,7 +3463,7 @@ public void ExtensionMethodIsDisambiguatedByUsingStaticAtDeeperLevel()
namespace K
{
using S;
using static S;
class Program
{
......@@ -3471,8 +3503,8 @@ public void ExtensionMethodAmbiguousAcrossMultipleUsingStatic()
namespace K
{
using N.S;
using N.R;
using static N.S;
using static N.R;
class Program
{
......@@ -3514,7 +3546,7 @@ public void ExtensionMethodsInTheContainingClassDoNotHaveHigherPrecedence()
const string source = @"
namespace N
{
using Program;
using static Program;
static class Program
{
......@@ -3542,7 +3574,7 @@ public static void Foo(this int x)
Diagnostic(ErrorCode.ERR_AmbigCall, "Foo").WithArguments("N.Program.Foo(int)", "N.R.Foo(int)").WithLocation(10, 15),
// (4,5): hidden CS8019: Unnecessary using directive.
// using Program;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Program;").WithLocation(4, 5));
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Program;").WithLocation(4, 5));
}
[Fact, WorkItem(1010648, "DevDiv")]
......
......@@ -1841,9 +1841,12 @@ public class C { }
// (4,14): error CS0246: The type or namespace name 'C' could not be found (are you missing a using directive or an assembly reference?)
// class A<T> : C
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "C").WithArguments("C").WithLocation(4, 14),
// (2,7): error CS7007: A using directive can only be applied to static classes or namespaces; the type 'D' is not a static class
// (1,7): error CS0138: A 'using namespace' directive can only be applied to namespaces; 'A<int>.B' is a type not a namespace. Consider using a 'using static' directive instead
// using A<int>.B;
Diagnostic(ErrorCode.ERR_BadUsingNamespace, "A<int>.B").WithArguments("A<int>.B").WithLocation(1, 7),
// (2,7): error CS0138: A 'using namespace' directive can only be applied to namespaces; 'D' is a type not a namespace. Consider using a 'using static' directive instead
// using D;
Diagnostic(ErrorCode.ERR_BadUsingType, "D").WithArguments("D").WithLocation(2, 7),
Diagnostic(ErrorCode.ERR_BadUsingNamespace, "D").WithArguments("D").WithLocation(2, 7),
// (2,1): hidden CS8019: Unnecessary using directive.
// using D;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using D;").WithLocation(2, 1),
......@@ -1852,5 +1855,30 @@ public class C { }
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using A<int>.B;").WithLocation(1, 1)
);
}
[Fact, WorkItem(1085632, "DevDiv")]
public void BaseLookupRecursionWithStaticImport02()
{
var source =
@"using static A<int>.B;
using static D;
class A<T> : C
{
public static class B { }
}
class D
{
public class C { }
}";
var compilation = CreateCompilationWithMscorlib(source);
// Once we allow static import of nonstatic classes, this should not be an error.
compilation.VerifyDiagnostics(
// (1,1): hidden CS8019: Unnecessary using directive.
// using static A<int>.B;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static A<int>.B;").WithLocation(1, 1)
);
}
}
}
......@@ -3,10 +3,9 @@
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
......@@ -81,11 +80,79 @@ public void TestUsing()
Assert.NotNull(ud.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, ud.UsingKeyword.CSharpKind());
Assert.Null(ud.Alias);
Assert.True(ud.StaticKeyword == default(SyntaxToken));
Assert.NotNull(ud.Name);
Assert.Equal("a", ud.Name.ToString());
Assert.NotNull(ud.SemicolonToken);
}
[Fact]
public void TestUsingStatic()
{
var text = "using static a;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
var ud = file.Usings[0];
Assert.NotNull(ud.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, ud.UsingKeyword.CSharpKind());
Assert.Equal(SyntaxKind.StaticKeyword, ud.StaticKeyword.CSharpKind());
Assert.Null(ud.Alias);
Assert.NotNull(ud.Name);
Assert.Equal("a", ud.Name.ToString());
Assert.NotNull(ud.SemicolonToken);
}
[Fact]
public void TestUsingStaticInWrongOrder()
{
var text = "static using a;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToFullString());
var errors = file.Errors();
Assert.True(errors.Length > 0);
Assert.Equal((int)ErrorCode.ERR_NamespaceUnexpected, errors[0].Code);
}
[Fact]
public void TestDuplicateStatic()
{
var text = "using static static a;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToString());
var errors = file.Errors();
Assert.True(errors.Length > 0);
Assert.Equal((int)ErrorCode.ERR_IdentifierExpectedKW, errors[0].Code);
}
[Fact]
public void TestUsingNamespace()
{
var text = "using namespace a;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToString());
var errors = file.Errors();
Assert.True(errors.Length > 0);
Assert.Equal((int)ErrorCode.ERR_IdentifierExpectedKW, errors[0].Code);
}
[Fact]
public void TestUsingDottedName()
{
......@@ -101,12 +168,57 @@ public void TestUsingDottedName()
Assert.NotNull(ud.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, ud.UsingKeyword.CSharpKind());
Assert.True(ud.StaticKeyword == default(SyntaxToken));
Assert.Null(ud.Alias);
Assert.NotNull(ud.Name);
Assert.Equal("a.b", ud.Name.ToString());
Assert.NotNull(ud.SemicolonToken);
}
[Fact]
public void TestUsingStaticDottedName()
{
var text = "using static a.b;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
var ud = file.Usings[0];
Assert.NotNull(ud.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, ud.UsingKeyword.CSharpKind());
Assert.Equal(SyntaxKind.StaticKeyword, ud.StaticKeyword.CSharpKind());
Assert.Null(ud.Alias);
Assert.NotNull(ud.Name);
Assert.Equal("a.b", ud.Name.ToString());
Assert.NotNull(ud.SemicolonToken);
}
[Fact]
public void TestUsingStaticGenericName()
{
var text = "using static a<int?>;";
var file = this.ParseFile(text);
Assert.NotNull(file);
Assert.Equal(1, file.Usings.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
var ud = file.Usings[0];
Assert.NotNull(ud.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, ud.UsingKeyword.CSharpKind());
Assert.Equal(SyntaxKind.StaticKeyword, ud.StaticKeyword.CSharpKind());
Assert.Null(ud.Alias);
Assert.NotNull(ud.Name);
Assert.Equal("a<int?>", ud.Name.ToString());
Assert.NotNull(ud.SemicolonToken);
}
[Fact]
public void TestUsingAliasName()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册