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

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

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