PageRenderTime 5ms CodeModel.GetById 4ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Compilers/CSharp/Test/Semantic/Semantics/UsingStatementTests.cs

https://github.com/EkardNT/Roslyn
C# | 730 lines | 608 code | 82 blank | 40 comment | 0 complexity | e4a2a3ddfcd29ed43ca17217b1c47dfc MD5 | raw file
  1// Copyright (c) Microsoft Open Technologies, Inc.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
  2
  3using System.Collections;
  4using System.Collections.Generic;
  5using System.Linq;
  6using Microsoft.CodeAnalysis.CSharp.Symbols;
  7using Microsoft.CodeAnalysis.CSharp.Syntax;
  8using Microsoft.CodeAnalysis.Text;
  9using Roslyn.Test.Utilities;
 10using Xunit;
 11
 12namespace Microsoft.CodeAnalysis.CSharp.UnitTests
 13{
 14    /// <summary>
 15    /// Tests related to binding (but not lowering) using statements (not directives).
 16    /// </summary>
 17    public class UsingStatementTests : CompilingTestBase
 18    {
 19        string ManagedClass = @"
 20class MyManagedType : System.IDisposable
 21{
 22    public void Dispose()
 23    { }
 24}";
 25
 26        string ManagedStruct = @"
 27struct MyManagedType : System.IDisposable
 28{
 29    public void Dispose()
 30    { }
 31}";
 32
 33        [Fact]
 34        public void SemanticModel()
 35        {
 36            var source = @"
 37class C
 38{
 39    static void Main()
 40    {
 41        using (System.IDisposable i = null)
 42        {
 43            i.Dispose(); //this makes no sense, but we're only testing binding
 44        }
 45    }
 46}
 47";
 48
 49            var compilation = CreateCompilationWithMscorlib(source);
 50            compilation.VerifyDiagnostics();
 51
 52            var tree = compilation.SyntaxTrees.Single();
 53            var model = compilation.GetSemanticModel(tree);
 54
 55            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
 56
 57            var declaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Single());
 58            Assert.NotNull(declaredSymbol);
 59            Assert.Equal(SymbolKind.Local, declaredSymbol.Kind);
 60            var declaredLocal = (LocalSymbol)declaredSymbol;
 61            Assert.Equal("i", declaredLocal.Name);
 62            Assert.Equal(SpecialType.System_IDisposable, declaredLocal.Type.SpecialType);
 63
 64            var memberAccessExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single();
 65
 66            var info = model.GetSymbolInfo(memberAccessExpression.Expression);
 67            Assert.NotNull(info);
 68            Assert.Equal(declaredLocal, info.Symbol);
 69
 70            var lookupSymbol = model.LookupSymbols(memberAccessExpression.SpanStart, name: declaredLocal.Name).Single();
 71            Assert.Equal(declaredLocal, lookupSymbol);
 72        }
 73
 74        [Fact]
 75        public void MethodGroup()
 76        {
 77            var source = @"
 78class C
 79{
 80    static void Main()
 81    {
 82        using (Main)
 83        {
 84        }
 85    }
 86}
 87";
 88
 89            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
 90                // (6,16): error CS1674: 'method group': type used in a using statement must be implicitly convertible to 'System.IDisposable'
 91                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "Main").WithArguments("method group"));
 92        }
 93
 94        [Fact]
 95        public void Lambda()
 96        {
 97            var source = @"
 98class C
 99{
100    static void Main()
101    {
102        using (x => x)
103        {
104        }
105    }
106}
107";
108
109            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
110                // (6,16): error CS1674: 'lambda expression': type used in a using statement must be implicitly convertible to 'System.IDisposable'
111                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "x => x").WithArguments("lambda expression"));
112        }
113
114        [Fact]
115        public void Null()
116        {
117            var source = @"
118class C
119{
120    static void Main()
121    {
122        using (null)
123        {
124        }
125    }
126}
127";
128
129            CreateCompilationWithMscorlib(source).VerifyDiagnostics();
130        }
131
132        [Fact]
133        public void UnusedVariable()
134        {
135            var source = @"
136class C
137{
138    static void Main()
139    {
140        using (System.IDisposable d = null)
141        {
142        }
143    }
144}
145";
146
147            CreateCompilationWithMscorlib(source).VerifyDiagnostics();
148        }
149
150        [Fact]
151        public void EmbeddedStatement()
152        {
153            var source = @"
154class C
155{
156    static void Main()
157    {
158        using (System.IDisposable a = null)
159            using (System.IDisposable b = null)
160                using (System.IDisposable c = null) ;
161    }
162}
163";
164
165            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
166                // (8,53): warning CS0642: Possible mistaken empty statement
167                Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";"));
168        }
169
170        [Fact]
171        public void ModifyUsingLocal()
172        {
173            var source = @"
174using System;
175
176class C
177{
178    static void Main()
179    {
180        using (IDisposable i = null)
181        {
182            i = null;
183            Ref(ref i);
184            Out(out i);
185        }
186    }
187
188    static void Ref(ref IDisposable i) { }
189    static void Out(out IDisposable i) { i = null; }
190}
191";
192
193            var compilation = CreateCompilationWithMscorlib(source);
194            compilation.VerifyDiagnostics(
195                // (10,13): error CS1656: Cannot assign to 'i' because it is a 'using variable'
196                Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "i").WithArguments("i", "using variable"),
197                // (11,21): error CS1657: Cannot pass 'i' as a ref or out argument because it is a 'using variable'
198                Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "i").WithArguments("i", "using variable"),
199                // (12,21): error CS1657: Cannot pass 'i' as a ref or out argument because it is a 'using variable'
200                Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "i").WithArguments("i", "using variable"));
201        }
202
203        [Fact]
204        public void ImplicitType1()
205        {
206            var source = @"
207using System.IO;
208
209class C
210{
211    static void Main()
212    {
213        using (var a = new StreamWriter(""""))
214        {
215        }
216    }
217}
218";
219
220            var compilation = CreateCompilationWithMscorlib(source);
221            compilation.VerifyDiagnostics();
222
223            var tree = compilation.SyntaxTrees.Single();
224            var model = compilation.GetSemanticModel(tree);
225
226            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
227
228            var declaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Single());
229
230            Assert.Equal("System.IO.StreamWriter a", declaredSymbol.ToTestDisplayString());
231
232            var typeInfo = model.GetSymbolInfo(usingStatement.Declaration.Type);
233            Assert.Equal(((LocalSymbol)declaredSymbol).Type, typeInfo.Symbol);
234        }
235
236        [Fact]
237        public void ImplicitType2()
238        {
239            var source = @"
240using System.IO;
241
242class C
243{
244    static void Main()
245    {
246        using (var a = new StreamWriter(""""), b = new StreamReader(""""))
247        {
248        }
249    }
250}
251";
252
253            var compilation = CreateCompilationWithMscorlib(source);
254            compilation.VerifyDiagnostics(
255                // (8,16): error CS0819: Implicitly-typed variables cannot have multiple declarators
256                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, @"var a = new StreamWriter(""""), b = new StreamReader("""")"));
257
258            var tree = compilation.SyntaxTrees.Single();
259            var model = compilation.GetSemanticModel(tree);
260
261            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
262
263            var firstDeclaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.First());
264
265            Assert.Equal("System.IO.StreamWriter a", firstDeclaredSymbol.ToTestDisplayString());
266
267            var typeInfo = model.GetSymbolInfo(usingStatement.Declaration.Type);
268            // lowest/last bound node with associated syntax is being picked up. Fine for now.
269            Assert.Equal(((LocalSymbol)model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Last())).Type, typeInfo.Symbol);
270        }
271
272        [Fact]
273        public void ModifyLocalInUsingExpression()
274        {
275            var source = @"
276using System;
277
278class C
279{
280    void Main()
281    {
282        IDisposable i = null;
283        using (i)
284        {
285            i = null; //CS0728
286            Ref(ref i); //CS0728
287            this[out i] = 1; //CS0728
288        }
289    }
290
291    void Ref(ref IDisposable i) { }
292    int this[out IDisposable i] { set { i = null; } } //this is illegal, so if we break this test, we may need a metadata indexer
293}
294";
295
296            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
297                // (18,14): error CS0631: ref and out are not valid in this context
298                Diagnostic(ErrorCode.ERR_IllegalRefParam, "out"),
299                // (11,13): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
300                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
301                // (12,21): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
302                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
303                // (13,22): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
304                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"));
305        }
306
307        [Fact]
308        public void ModifyParameterInUsingExpression()
309        {
310            var source = @"
311using System;
312
313class C
314{
315    void M(IDisposable i)
316    {
317        using (i)
318        {
319            i = null; //CS0728
320            Ref(ref i); //CS0728
321            this[out i] = 1; //CS0728
322        }
323    }
324
325    void Ref(ref IDisposable i) { }
326    int this[out IDisposable i] { set { i = null; } } //this is illegal, so if we break this test, we may need a metadata indexer
327}
328";
329
330            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
331                // (17,14): error CS0631: ref and out are not valid in this context
332                Diagnostic(ErrorCode.ERR_IllegalRefParam, "out"),
333                // (10,13): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
334                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
335                // (11,21): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
336                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
337                // (12,22): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
338                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"));
339        }
340
341        // The object could be created outside the "using" statement 
342        [Fact]
343        public void ResourceCreatedOutsideUsing()
344        {
345            var source = @"
346using System;
347class Program
348{
349    static void Main(string[] args)
350    {
351        MyManagedType mnObj1 = null;
352        using (mnObj1)
353        {
354        }
355    }
356}
357" + ManagedClass;
358
359            var compilation = CreateCompilationWithMscorlib(source);
360            VerifyDeclaredSymbolForUsingStatements(compilation);
361        }
362
363        // The object created inside the "using" statement but declared no variable
364        [Fact]
365        public void ResourceCreatedInsideUsingWithNoVarDecalred()
366        {
367            var source = @"
368using System;
369class Program
370{
371    static void Main(string[] args)
372    {
373        using (new MyManagedType())
374        {
375        }
376    }
377}
378" + ManagedStruct;
379            var compilation = CreateCompilationWithMscorlib(source);
380            VerifyDeclaredSymbolForUsingStatements(compilation);
381        }
382
383        // Multiple resource created inside Using
384        /// <bug id="10509" project="Roslyn"/>
385        [Fact()]
386        public void MultipleResourceCreatedInsideUsing()
387        {
388            var source = @"
389using System;
390class Program
391{
392    static void Main(string[] args)
393    {
394        using (MyManagedType mnObj1 = null, mnObj2 = default(MyManagedType))
395        {
396        }
397    }
398}
399" + ManagedStruct;
400
401            var compilation = CreateCompilationWithMscorlib(source);
402            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj1", "mnObj2");
403            foreach (var x in symbols)
404            {
405                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type);
406            }
407        }
408
409        [Fact]
410        public void MultipleResourceCreatedInNestedUsing()
411        {
412            var source = @"
413using System;
414class Program
415{
416    static void Main(string[] args)
417    {
418        using (MyManagedType mnObj1 = null, mnObj2 = default(MyManagedType))
419        {
420            using (MyManagedType mnObj3 = null, mnObj4 = default(MyManagedType))
421            {
422                mnObj3.Dispose(); 
423            }
424        }
425    }
426}
427" + ManagedClass;
428
429            var compilation = CreateCompilationWithMscorlib(source);
430
431            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 2, "mnObj3", "mnObj4");
432            foreach (var x in symbols)
433            {
434                var localSymbol = (LocalSymbol)x;
435                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 2);
436                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type, 2);
437            }
438        }
439
440        [Fact]
441        public void ResourceTypeDerivedFromClassImplementIdisposable()
442        {
443            var source = @"
444using System;
445class Program
446{
447    public static void Main(string[] args)
448    {
449        using (MyManagedTypeDerived mnObj = new MyManagedTypeDerived())
450        {
451        }
452    }
453}
454class MyManagedTypeDerived : MyManagedType
455{ }
456" + ManagedClass;
457
458            var compilation = CreateCompilationWithMscorlib(source);
459
460            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
461            foreach (var x in symbols)
462            {
463                var localSymbol = (LocalSymbol)x;
464                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
465                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type, 1);
466            }
467        }
468
469        [Fact]
470        public void LinqInUsing()
471        {
472            var source = @"
473using System;
474using System.Linq;
475class Program
476{
477    public static void Main(string[] args)
478    {
479        using (var mnObj = (from x in ""1"" select new MyManagedType()).First () )
480        {
481        }
482    }
483}
484" + ManagedClass;
485
486            var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
487
488            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
489            foreach (var x in symbols)
490            {
491                var localSymbol = (LocalSymbol)x;
492                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
493                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type, 1);
494            }
495        }
496
497        [Fact]
498        public void LambdaInUsing()
499        {
500            var source = @"
501using System;
502using System.Linq;
503class Program
504{
505    public static void Main(string[] args)
506    {
507        MyManagedType[] mnObjs = { };
508        using (var mnObj = mnObjs.Where(x => x.ToString() == "").First())
509        {
510        }
511    }
512}
513" + ManagedStruct;
514
515            var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
516
517            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
518            foreach (var x in symbols)
519            {
520                var localSymbol = (LocalSymbol)x;
521                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
522                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type, 1);
523            }
524        }
525
526        [Fact]
527        public void UsingForGenericType()
528        {
529            var source = @"
530using System;
531using System.Collections.Generic;
532class Test<T>
533{
534    public static IEnumerator<T> M<U>(IEnumerable<T> items) where U : IDisposable, new()
535    {
536        using (U u = new U())
537        {
538        }
539        return null;
540    }
541}
542";
543            var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
544
545            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "u");
546            foreach (var x in symbols)
547            {
548                var localSymbol = (LocalSymbol)x;
549                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
550                VerifySymbolInfoForUsingStatements(compilation, ((LocalSymbol)x).Type, 1);
551            }
552        }
553
554        [Fact]
555        public void UsingForGenericTypeWithClassConstraint()
556        {
557            var source = @"using System;
558class A { }
559class B : A, IDisposable
560{
561    void IDisposable.Dispose() { }
562}
563class C
564{
565    static void M<T0, T1, T2, T3, T4>(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)
566        where T0 : A
567        where T1 : A, IDisposable
568        where T2 : B
569        where T3 : T1
570        where T4 : T2
571    {
572        using (t0) { }
573        using (t1) { }
574        using (t2) { }
575        using (t3) { }
576        using (t4) { }
577    }
578}";
579            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
580                // (16,16): error CS1674: 'T0': type used in a using statement must be implicitly convertible to 'System.IDisposable'
581                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "t0").WithArguments("T0").WithLocation(16, 16));
582        }
583
584        [WorkItem(543168, "DevDiv")]
585        [Fact]
586        public void EmbeddedDeclaration()
587        {
588            var source = @"
589class C
590{
591    static void Main()
592    {
593        using(null) object o = new object();
594    }
595}
596";
597
598            CreateCompilationWithMscorlib(source).VerifyDiagnostics(
599                // (6,20): error CS1023: Embedded statement cannot be a declaration or labeled statement
600                Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "object o = new object();"));
601        }
602
603        [WorkItem(529547, "DevDiv")]
604        [Fact]
605        public void UnusedLocal()
606        {
607            var source = @"
608using System;
609
610class C : IDisposable
611{
612    public void Dispose()
613    {
614    }
615}
616
617struct S : IDisposable
618{
619    public void Dispose()
620    {
621    }
622}
623
624public class Test
625{
626    public static void Main()
627    {
628        using (S s = new S()) { } //fine
629        using (C c = new C()) { } //fine
630    }
631}";
632
633            CreateCompilationWithMscorlib(source).VerifyDiagnostics();
634        }
635
636        [WorkItem(545331, "DevDiv")]
637        [Fact]
638        public void MissingIDisposable()
639        {
640            var source = @"
641class C
642{
643    void M()
644    {
645        using (var v = null) ;
646    }
647}";
648
649            CreateCompilation(source).VerifyDiagnostics(
650                // Related to the using statement:
651
652                // (6,30): warning CS0642: Possible mistaken empty statement
653                //         using (var v = null) ;
654                Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";"),
655
656                // Cascading from the lack of mscorlib:
657
658                // (2,7): error CS0518: Predefined type 'System.Object' is not defined or imported
659                // class C
660                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "C").WithArguments("System.Object"),
661                // (4,5): error CS0518: Predefined type 'System.Void' is not defined or imported
662                //     void M()
663                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "void").WithArguments("System.Void"),
664                // (6,16): error CS0518: Predefined type 'System.Object' is not defined or imported
665                //         using (var v = null) ;
666                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "var").WithArguments("System.Object"),
667                // (6,20): error CS0815: Cannot assign <null> to an implicitly-typed variable
668                //         using (var v = null) ;
669                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, "v = null").WithArguments("<null>"),
670                // (2,7): error CS1729: 'object' does not contain a constructor that takes 0 arguments
671                // class C
672                Diagnostic(ErrorCode.ERR_BadCtorArgCount, "C").WithArguments("object", "0")
673                );
674        }
675
676        #region help method
677
678        UsingStatementSyntax GetUsingStatements(CSharpCompilation compilation, int index = 1)
679        {
680            var tree = compilation.SyntaxTrees.Single();
681            var model = compilation.GetSemanticModel(tree);
682            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
683            return usingStatements[index - 1];
684        }
685
686        IEnumerable VerifyDeclaredSymbolForUsingStatements(CSharpCompilation compilation, int index = 1, params string[] variables)
687        {
688            var tree = compilation.SyntaxTrees.Single();
689            var model = compilation.GetSemanticModel(tree);
690
691            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
692            var i = 0;
693            foreach (var x in usingStatements[index - 1].Declaration.Variables)
694            {
695                var symbol = model.GetDeclaredSymbol(x);
696                Assert.Equal(SymbolKind.Local, symbol.Kind);
697                Assert.Equal(variables[i++].ToString(), symbol.ToDisplayString());
698                yield return symbol;
699            }
700        }
701
702        SymbolInfo VerifySymbolInfoForUsingStatements(CSharpCompilation compilation, Symbol symbol, int index = 1)
703        {
704            var tree = compilation.SyntaxTrees.Single();
705            var model = compilation.GetSemanticModel(tree);
706
707            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
708
709            var type = model.GetSymbolInfo(usingStatements[index - 1].Declaration.Type);
710
711            Assert.Equal(symbol, type.Symbol);
712
713            return type;
714        }
715
716        ISymbol VerifyLookUpSymbolForUsingStatements(CSharpCompilation compilation, Symbol symbol, int index = 1)
717        {
718            var tree = compilation.SyntaxTrees.Single();
719            var model = compilation.GetSemanticModel(tree);
720            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
721
722            var actualSymbol = model.LookupSymbols(usingStatements[index - 1].SpanStart, name: symbol.Name).Single();
723            Assert.Equal(SymbolKind.Local, actualSymbol.Kind);
724            Assert.Equal(symbol, actualSymbol);
725            return actualSymbol;
726        }
727
728        #endregion
729    }
730}