Beispiel #1
0
        public void ImplicitlyTypedArrayLocal()
        {
            var compilation = CreateCompilation(@"
class M {}

class C 
{ 
     public void F()
     {
        var a = new[] { new M() };
     }
}
");

            compilation.VerifyDiagnostics();

            var method      = (SourceMemberMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("F").Single();
            var diagnostics = new DiagnosticBag();
            var block       = MethodCompiler.BindMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics);

            var locDecl = (BoundLocalDeclaration)block.Statements.Single();
            var localA  = (ArrayTypeSymbol)locDecl.DeclaredTypeOpt.Display;

            var typeM = compilation.GlobalNamespace.GetMember <TypeSymbol>("M");

            Assert.Equal(typeM, localA.ElementType);
        }
Beispiel #2
0
        internal void TestOverloadResolutionWithDiff(string source, MetadataReference[] additionalRefs = null)
        {
            // The mechanism of this test is: we build the bound tree for the code passed in and then extract
            // from it the nodes that describe the method symbols. We then compare the description of
            // the symbols given to the comment that follows the call.

            var mscorlibRef = AssemblyMetadata.CreateFromImage(ProprietaryTestResources.NetFX.v4_0_30316_17626.mscorlib).GetReference(display: "mscorlib");
            var references = new[] { mscorlibRef }.Concat(additionalRefs ?? SpecializedCollections.EmptyArray <MetadataReference>());

            var compilation = CreateCompilation(source, references, TestOptions.ReleaseDll);

            var method      = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single();
            var diagnostics = new DiagnosticBag();
            var block       = MethodCompiler.BindMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics);
            var tree        = BoundTreeDumperNodeProducer.MakeTree(block);
            var results     = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value)
                                          .Where(x => x.Text == "method" && x.Value != null)
                                          .Select(x => x.Value)
                                          .ToArray());

            // var r = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value).ToArray();

            var expected = string.Join("\n", source
                                       .Split(new[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries)
                                       .Where(x => x.Contains("//-"))
                                       .Select(x => x.Substring(x.IndexOf("//-") + 3))
                                       .ToArray());

            AssertEx.Equal(expected, results);
        }
Beispiel #3
0
        internal ImmutableArray <Diagnostic> FlowDiagnostics(CSharpCompilation compilation)
        {
            var flowDiagnostics = DiagnosticBag.GetInstance();

            foreach (var method in AllMethods(compilation.SourceModule.GlobalNamespace))
            {
                var sourceSymbol = method as SourceMemberMethodSymbol;
                if (sourceSymbol == null)
                {
                    continue;
                }

                var boundBody = MethodCompiler.BindMethodBody(
                    sourceSymbol,
                    new TypeCompilationState(sourceSymbol.ContainingType, compilation, null),
                    new BindingDiagnosticBag(new DiagnosticBag())
                    );
                if (boundBody != null)
                {
                    FlowAnalysisPass.Rewrite(
                        sourceSymbol,
                        boundBody,
                        flowDiagnostics,
                        hasTrailingExpression: false,
                        originalBodyNested: false
                        );
                }
            }

            return(flowDiagnostics.ToReadOnlyAndFree <Diagnostic>());
        }
        internal static BoundStatement ParseAndBindMethodBody(string program, bool lower, string typeName = DefaultTypeName, string methodName = DefaultMethodName)
        {
            var compilation = CreateCompilationWithMscorlib(program);
            var method      = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single();
            var diagnostics = DiagnosticBag.GetInstance();

            try
            {
                // Provide an Emit.Module so that the lowering passes will be run
                var module = new PEAssemblyBuilder(
                    (SourceAssemblySymbol)compilation.Assembly,
                    EmitOptions.Default,
                    OutputKind.ConsoleApplication,
                    GetDefaultModulePropertiesForSerialization(),
                    Enumerable.Empty <ResourceDescription>(),
                    assemblySymbolMapper: null);

                TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module);

                var block = MethodCompiler.BindMethodBody(method, compilationState, diagnostics);
                if ((block == null) || !lower)
                {
                    return(block);
                }

                StateMachineTypeSymbol stateMachineTypeOpt;
                VariableSlotAllocator  lazyVariableSlotAllocator = null;
                var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance();

                var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance();

                var body = MethodCompiler.LowerBodyOrInitializer(
                    method: method,
                    methodOrdinal: 0,
                    body: block,
                    previousSubmissionFields: null,
                    compilationState: compilationState,
                    diagnostics: diagnostics,
                    lazyVariableSlotAllocator: ref lazyVariableSlotAllocator,
                    lambdaDebugInfoBuilder: lambdaDebugInfoBuilder,
                    closureDebugInfoBuilder: closureDebugInfoBuilder,
                    stateMachineTypeOpt: out stateMachineTypeOpt);

                lambdaDebugInfoBuilder.Free();
                closureDebugInfoBuilder.Free();

                return(body);
            }
            finally
            {
                diagnostics.Free();
            }
        }
Beispiel #5
0
        internal static BoundBlock ParseAndBindMethodBody(string program, string typeName = DefaultTypeName, string methodName = DefaultMethodName)
        {
            var compilation = CreateCompilation(program);
            var method      = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single();

            // Provide an Emit.Module so that the lowering passes will be run
            var module = new PEAssemblyBuilder(
                (SourceAssemblySymbol)compilation.Assembly,
                emitOptions: EmitOptions.Default,
                outputKind: OutputKind.ConsoleApplication,
                serializationProperties: GetDefaultModulePropertiesForSerialization(),
                manifestResources: Enumerable.Empty <ResourceDescription>());

            TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module);

            var diagnostics = DiagnosticBag.GetInstance();
            var block       = MethodCompiler.BindMethodBody(method, compilationState, diagnostics);

            diagnostics.Free();
            return(block);
        }
Beispiel #6
0
        internal ImmutableArray <Diagnostic> FlowDiagnostics(CSharpCompilation compilation)
        {
            var flowDiagnostics = DiagnosticBag.GetInstance();

            foreach (var method in AllMethods(compilation.SourceModule.GlobalNamespace))
            {
                var sourceSymbol = method as SourceMethodSymbol;
                if (sourceSymbol == null)
                {
                    continue;
                }

                var boundBody = MethodCompiler.BindMethodBody(sourceSymbol, new DiagnosticBag());
                if (boundBody != null)
                {
                    FlowAnalysisPass.Rewrite(sourceSymbol, boundBody, flowDiagnostics);
                }
            }

            return(flowDiagnostics.ToReadOnlyAndFree <Diagnostic>());
        }
Beispiel #7
0
        internal static BoundStatement ParseAndBindMethodBody(string program, bool lower, string typeName = DefaultTypeName, string methodName = DefaultMethodName)
        {
            var compilation = CreateCompilationWithMscorlib(program);
            var method      = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single();
            var diagnostics = DiagnosticBag.GetInstance();

            try
            {
                var block = MethodCompiler.BindMethodBody(method, diagnostics);
                if ((block == null) || !lower)
                {
                    return(block);
                }

                // Provide an Emit.Module so that the lowering passes will be run
                var module = new PEAssemblyBuilder(
                    (SourceAssemblySymbol)compilation.Assembly,
                    null,
                    OutputKind.ConsoleApplication,
                    GetDefaultModulePropertiesForSerialization(),
                    Enumerable.Empty <ResourceDescription>(),
                    assemblySymbolMapper: null);

                TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module);

                var body = MethodCompiler.LowerBodyOrInitializer(
                    generateDebugInfo: true,
                    method: method,
                    body: block,
                    previousSubmissionFields: null,
                    compilationState: compilationState,
                    diagnostics: diagnostics);

                return(body);
            }
            finally
            {
                diagnostics.Free();
            }
        }
Beispiel #8
0
        /// <summary>
        /// Verify the type and nullability inferred by NullabilityWalker of all expressions in the source
        /// that are followed by specific annotations. Annotations are of the form /*T:type*/.
        /// </summary>
        internal static void VerifyTypes(this CSharpCompilation compilation, SyntaxTree tree = null)
        {
            if (tree == null)
            {
                foreach (var syntaxTree in compilation.SyntaxTrees)
                {
                    VerifyTypes(compilation, syntaxTree);
                }
                return;
            }

            var root           = tree.GetRoot();
            var allAnnotations = getAnnotations();

            if (allAnnotations.IsEmpty)
            {
                return;
            }

            var model = compilation.GetSemanticModel(tree);
            var annotationsByMethod = allAnnotations.GroupBy(annotation => annotation.Expression.Ancestors().OfType <BaseMethodDeclarationSyntax>().First()).ToArray();

            foreach (var annotations in annotationsByMethod)
            {
                var method      = (MethodSymbol)model.GetDeclaredSymbol(annotations.Key);
                var diagnostics = DiagnosticBag.GetInstance();
                var block       = MethodCompiler.BindMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics);
                var dictionary  = new Dictionary <SyntaxNode, TypeSymbolWithAnnotations>();
                NullableWalker.Analyze(
                    compilation,
                    method,
                    block,
                    diagnostics,
                    callbackOpt: (BoundExpression expr, TypeSymbolWithAnnotations exprType) => dictionary[expr.Syntax] = exprType);
                diagnostics.Free();
                var expectedTypes = annotations.SelectAsArray(annotation => annotation.Text);
                var actualTypes   = annotations.SelectAsArray(annotation => toDisplayString(annotation.Expression));
                // Consider reporting the correct source with annotations on mismatch.
                AssertEx.Equal(expectedTypes, actualTypes, message: method.ToTestDisplayString());

                foreach (var entry in dictionary.Values.Where(v => !v.IsNull))
                {
                    // Result types cannot have nested types that are unspeakables
                    Assert.Null(entry.VisitType(typeOpt: null,
                                                typeWithAnnotationsPredicateOpt: (tswa, a, b) => !tswa.Equals(entry, TypeCompareKind.ConsiderEverything) && !tswa.NullableAnnotation.IsSpeakable(),
                                                typePredicateOpt: (ts, _, b) => false, arg: (object)null, canDigThroughNullable: true));
                }

                string toDisplayString(SyntaxNode syntaxOpt)
                {
                    return((syntaxOpt != null) && dictionary.TryGetValue(syntaxOpt, out var type) ?
                           (type.IsNull ? "<null>" : type.ToDisplayString(TypeSymbolWithAnnotations.TestDisplayFormat)) :
                           null);
                }
            }

            ImmutableArray <(ExpressionSyntax Expression, string Text)> getAnnotations()
            {
                var builder = ArrayBuilder <(ExpressionSyntax, string)> .GetInstance();

                foreach (var token in root.DescendantTokens())
                {
                    foreach (var trivia in token.TrailingTrivia)
                    {
                        if (trivia.Kind() == SyntaxKind.MultiLineCommentTrivia)
                        {
                            var          text   = trivia.ToFullString();
                            const string prefix = "/*T:";
                            const string suffix = "*/";
                            if (text.StartsWith(prefix) && text.EndsWith(suffix))
                            {
                                var expr = getEnclosingExpression(token);
                                Assert.True(expr != null, $"VerifyTypes could not find a matching expression for annotation '{text}'.");

                                var content = text.Substring(prefix.Length, text.Length - prefix.Length - suffix.Length);
                                builder.Add((expr, content));
                            }
                        }
                    }
                }
                return(builder.ToImmutableAndFree());
            }

            ExpressionSyntax getEnclosingExpression(SyntaxToken token)
            {
                var node = token.Parent;

                while (true)
                {
                    var expr = asExpression(node);
                    if (expr != null)
                    {
                        return(expr);
                    }
                    if (node == root)
                    {
                        break;
                    }
                    node = node.Parent;
                }
                return(null);
            }

            ExpressionSyntax asExpression(SyntaxNode node)
            {
                var expr = node as ExpressionSyntax;

                if (expr == null)
                {
                    return(null);
                }
                switch (expr.Kind())
                {
                case SyntaxKind.ParenthesizedExpression:
                    return(((ParenthesizedExpressionSyntax)expr).Expression);

                case SyntaxKind.IdentifierName:
                    if (expr.Parent is MemberAccessExpressionSyntax memberAccess && memberAccess.Name == expr)
                    {
                        return(memberAccess);
                    }
                    break;
                }
                return(expr);
            }
        }