diff --git a/Src/Compilers/CSharp/Portable/Binder/Imports.cs b/Src/Compilers/CSharp/Portable/Binder/Imports.cs index d96092c8f582fbe0786d6019377308b1011d0560..71ba86eeff03d31a4a6e097a10de33a388bc6f2e 100644 --- a/Src/Compilers/CSharp/Portable/Binder/Imports.cs +++ b/Src/Compilers/CSharp/Portable/Binder/Imports.cs @@ -107,31 +107,36 @@ internal sealed class Imports var uniqueUsings = new HashSet(); - 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: '' is a '' 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()); } @@ -474,20 +477,46 @@ internal bool IsUsingAlias(string name, bool callerIsSemanticModel) ImmutableArray candidates = Binder.GetCandidateMembers(typeOrNamespace.NamespaceOrType, name, options, originalBinder: originalBinder); foreach (Symbol symbol in candidates) { - // lookup via "using namespace" ignores namespaces inside - if (symbol.Kind != SymbolKind.Namespace) + switch (symbol.Kind) { - // 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); - } + // lookup via "using namespace" ignores namespaces inside + 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; + } - 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); } } } diff --git a/Src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/Src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 9b49c631e34696a00df62c075a301fc48ad1e04f..b5497f3341239fa67f1bad5deb06b5f514baeadb 100644 --- a/Src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/Src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -1853,7 +1853,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to A using namespace directive can only be applied to namespaces; '{0}' is a type not a namespace. + /// Looks up a localized string similar to A 'using namespace' directive can only be applied to namespaces; '{0}' is a type not a namespace. Consider using a 'using static' directive instead. /// internal static string ERR_BadUsingNamespace { get { @@ -1862,7 +1862,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to A using directive can only be applied to static classes or namespaces; the type '{0}' is not a static class. + /// Looks up a localized string similar to A 'using static' directive can only be applied to types; '{0}' is a namespace not a type. Consider using a 'using namespace' directive instead. /// internal static string ERR_BadUsingType { get { @@ -4948,6 +4948,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to Assembly culture strings may not contain embedded NUL characters.. + /// + internal static string ERR_InvalidAssemblyCulture { + get { + return ResourceManager.GetString("ERR_InvalidAssemblyCulture", resourceCulture); + } + } + /// /// Looks up a localized string similar to Executables cannot be satellite assemblies; culture should always be empty. /// @@ -5911,6 +5920,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to A 'using static' directive cannot be used to declare an alias. + /// + internal static string ERR_NoAliasHere { + get { + return ResourceManager.GetString("ERR_NoAliasHere", resourceCulture); + } + } + /// /// Looks up a localized string similar to A base class is required for a 'base' reference. /// @@ -8990,6 +9008,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to using static. + /// + internal static string IDS_FeatureUsingStatic { + get { + return ResourceManager.GetString("IDS_FeatureUsingStatic", resourceCulture); + } + } + /// /// Looks up a localized string similar to fixed variable. /// diff --git a/Src/Compilers/CSharp/Portable/CSharpResources.resx b/Src/Compilers/CSharp/Portable/CSharpResources.resx index ff3830b8d7834afaa1b72e039b0fca62a927f4ad..df8a65a009be2c8129066ad249294d9293deffb1 100644 --- a/Src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/Src/Compilers/CSharp/Portable/CSharpResources.resx @@ -631,10 +631,13 @@ 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 - A using namespace directive can only be applied to namespaces; '{0}' is a type not a namespace + A 'using namespace' directive can only be applied to namespaces; '{0}' is a type not a namespace. Consider using a 'using static' directive instead - A using directive can only be applied to static classes or namespaces; the type '{0}' is not a static class + A 'using static' directive can only be applied to types; '{0}' is a namespace not a type. Consider using a 'using namespace' directive instead + + + A 'using static' directive cannot be used to declare an alias No enclosing loop out of which to break or continue @@ -3993,4 +3996,7 @@ Assembly culture strings may not contain embedded NUL characters. - + + using static + + \ No newline at end of file diff --git a/Src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/Src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 84a7a9867884d6596b3f78f61b6853e2f50cb05e..ec5b930204758c7deeb04163eda106decbf60077 100644 --- a/Src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/Src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1296,5 +1296,6 @@ internal enum ErrorCode ERR_SubexpressionNotInNameof = 8082, ERR_AliasQualifiedNameNotAnExpression = 8083, ERR_NameofMethodGroupWithTypeParameters = 8084, + ERR_NoAliasHere = 8085, } } diff --git a/Src/Compilers/CSharp/Portable/Errors/MessageID.cs b/Src/Compilers/CSharp/Portable/Errors/MessageID.cs index ee35026371e938f6bda666fa985748081748e843..969106a094169611cd29dfb41c54c3cd9a651639 100644 --- a/Src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/Src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -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. diff --git a/Src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/Src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index dbaa30a107334b2d47b57af6c431c24bc9425bdd..7c297d3c729d25109344408b6780dcc798429d8e 100644 --- a/Src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/Src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -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() diff --git a/Src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/Src/Compilers/CSharp/Portable/Syntax/Syntax.xml index d25fca484d91c10c9e67f4855d01e79c8f676b8d..baecf930d24e1a9dab84961ee9b17ba8223e8b44 100644 --- a/Src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/Src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -2181,6 +2181,7 @@ + diff --git a/Src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/Src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index c1a3579698ec3ae16a62802b591fbd050d3a40f2..9d4cff95e62f6c1685b7cb640a2dfa18e87d2411 100644 --- a/Src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/Src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1969,5 +1969,16 @@ public static BlockSyntax Block(IEnumerable statements) accessorList: accessorList, expressionBody: default(ArrowExpressionClauseSyntax)); } + + /// Creates a new UsingDirectiveSyntax instance. + 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 diff --git a/Src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs b/Src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs index 858520fdce4d2969cd95b8fc5409f2eee584bdaa..b70d090a8a062d9cab7fd01fa3e4bdc71efe9c4b 100644 --- a/Src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs +++ b/Src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs @@ -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"), diff --git a/Src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs b/Src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs index 80384d6578bfbc1fa872a79ec8cd583f245cfb60..03ab70b6db39f1269ed4ca512fd4d048ceca2aed 100644 --- a/Src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs +++ b/Src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs @@ -1994,7 +1994,7 @@ static void Main() public void StaticType() { var source = @" -using System.Math; +using static System.Math; class D { diff --git a/Src/Compilers/CSharp/Test/Semantic/Semantics/NameCollisionTests.cs b/Src/Compilers/CSharp/Test/Semantic/Semantics/NameCollisionTests.cs index a9ee44c38d99419ed1a22a0b0026239b399bd746..4d44ff8892c5df506d2b75a224230d5d4c83190d 100644 --- a/Src/Compilers/CSharp/Test/Semantic/Semantics/NameCollisionTests.cs +++ b/Src/Compilers/CSharp/Test/Semantic/Semantics/NameCollisionTests.cs @@ -1872,8 +1872,8 @@ static void Main() public void Bug879811_1() { const string source = @" -using Static; -using Static; +using static Static; +using static Static; public static class Static { @@ -1902,8 +1902,8 @@ static void Main(string[] args) public void Bug879811_2() { const string source = @" -using Static; -using Static; +using static Static; +using static Static; public static class Static { @@ -1923,10 +1923,10 @@ static void Main() CreateCompilationWithMscorlib(source).VerifyDiagnostics( // (3,7): warning CS0105: The using directive for 'Static' appeared previously in this namespace // using Static; - Diagnostic(ErrorCode.WRN_DuplicateUsing, "Static").WithArguments("Static").WithLocation(3, 7), + Diagnostic(ErrorCode.WRN_DuplicateUsing, "Static").WithArguments("Static").WithLocation(3, 14), // (3,1): hidden CS8019: Unnecessary using directive. // using Static; - Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Static;").WithLocation(3, 1)); + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Static;").WithLocation(3, 1)); } [Fact] @@ -1934,7 +1934,7 @@ static void Main() public void Bug879811_3() { const string source = @" -using Static; +using static Static; public static class Static { @@ -1946,7 +1946,7 @@ public class Nested namespace N { - using Static; + using static Static; class D { static void Main() @@ -1958,7 +1958,7 @@ static void Main() CreateCompilationWithMscorlib(source).VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using Static; - Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Static;").WithLocation(2, 1)); + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Static;").WithLocation(2, 1)); } } } diff --git a/Src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/Src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index dc13f54bb1e0a2ffc3a9ae8d2382ce52c3f9c1b8..55f02ed9a77473d21df7d7492b83b9a7b10cf14c 100644 --- a/Src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/Src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -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() diff --git a/Src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs b/Src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs index c1d91be6e7a97b40fffc6f8d2c8566f31b74ac3f..5181443aeaa52897b45d9d22dca7f8e866c82c0c 100644 --- a/Src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs +++ b/Src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetDeclaredSymbolAPITests.cs @@ -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 { diff --git a/Src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/Src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index 9a6546f708ae7c1d0d5a9590fc27cd64f60da737..e4198c3510b083312657f3fb79c00ffa9ff95586 100644 --- a/Src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/Src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -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")] diff --git a/Src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs b/Src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs index 2e0417c42ed9ffb12f53205dede0e70aca84f60f..4f1922c4c3222d7ef0ac7a794e9100c68cdb0d1a 100644 --- a/Src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs +++ b/Src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs @@ -1838,18 +1838,46 @@ public class C { } var compilation = CreateCompilationWithMscorlib(source); // Once we allow static import of nonstatic classes, this should not be an error. 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?) - // class A : 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 - // using D; - Diagnostic(ErrorCode.ERR_BadUsingType, "D").WithArguments("D").WithLocation(2, 7), - // (2,1): hidden CS8019: Unnecessary using directive. - // using D; - Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using D;").WithLocation(2, 1), - // (1,1): hidden CS8019: Unnecessary using directive. - // using A.B; - Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using A.B;").WithLocation(1, 1) + // (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 : C + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "C").WithArguments("C").WithLocation(4, 14), + // (1,7): error CS0138: A 'using namespace' directive can only be applied to namespaces; 'A.B' is a type not a namespace. Consider using a 'using static' directive instead + // using A.B; + Diagnostic(ErrorCode.ERR_BadUsingNamespace, "A.B").WithArguments("A.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_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), + // (1,1): hidden CS8019: Unnecessary using directive. + // using A.B; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using A.B;").WithLocation(1, 1) + ); + } + + [Fact, WorkItem(1085632, "DevDiv")] + public void BaseLookupRecursionWithStaticImport02() + { + var source = +@"using static A.B; +using static D; + +class A : 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.B; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static A.B;").WithLocation(1, 1) ); } } diff --git a/Src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/Src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index e8ca75373d7a69758c0a9bad9fb4e75329ba3a3b..fae724c3c7f6602b7d641502ac72187e22cffd2f 100644 --- a/Src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/Src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -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;"; + 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 TestUsingAliasName() {