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); }
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); }
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(); } }
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); }
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>()); }
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(); } }
/// <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); } }