提交 cec7a985 编写于 作者: C Charles Stoner

Allow goto in scripts

上级 42da9bd8
......@@ -764,9 +764,9 @@ private InContainerBinder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax
public override Binder VisitCompilationUnit(CompilationUnitSyntax parent)
{
return VisitCompilationUnit(
parent,
inUsing: IsInUsing(parent),
inScript: InScript);
parent,
inUsing: IsInUsing(parent),
inScript: InScript);
}
internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool inUsing, bool inScript)
......
......@@ -852,8 +852,9 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
options |= LookupOptions.MustNotBeMethodTypeParameter;
}
var name = node.Identifier.ValueText;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsWithFallback(lookupResult, node.Identifier.ValueText, arity: arity, useSiteDiagnostics: ref useSiteDiagnostics, options: options);
this.LookupSymbolsWithFallback(lookupResult, name, arity: arity, useSiteDiagnostics: ref useSiteDiagnostics, options: options);
diagnostics.Add(node, useSiteDiagnostics);
if (lookupResult.Kind != LookupResultKind.Empty)
......@@ -862,7 +863,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
bool isError = false;
bool wasError;
var members = ArrayBuilder<Symbol>.GetInstance();
Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, node.Identifier.ValueText, node.Arity, members, diagnostics, out wasError); // reports diagnostics in result.
Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, name, node.Arity, members, diagnostics, out wasError); // reports diagnostics in result.
isError |= wasError;
......@@ -876,7 +877,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
typeArgumentList,
typeArguments,
receiver,
node.Identifier.ValueText,
name,
members,
lookupResult,
receiver != null ? BoundMethodGroupFlags.HasImplicitReceiver : BoundMethodGroupFlags.None,
......@@ -919,15 +920,15 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
}
else if (IsJoinRangeVariableInLeftKey(node))
{
Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, node.Identifier.ValueText);
Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, name);
}
else if (IsInJoinRightKey(node))
{
Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, node.Identifier.ValueText);
Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, name);
}
else
{
Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, node.Identifier.ValueText);
Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, name);
}
}
......
......@@ -2,6 +2,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -106,7 +107,7 @@ internal struct ProcessedFieldInitializers
firstDebugImports = parentBinder.ImportChain;
}
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol);
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);
BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
boundInitializers.Add(boundInitializer);
......@@ -137,6 +138,8 @@ internal struct ProcessedFieldInitializers
// factory across siblings. Unfortunately, we cannot reuse the binder itself, because
// individual fields might have their own binders (e.g. because of being declared unsafe).
BinderFactory binderFactory = null;
// Label instances must be shared across all global statements.
ScriptLocalScopeBinder.Labels labels = null;
for (int j = 0; j < siblingInitializers.Length; j++)
{
......@@ -150,44 +153,47 @@ internal struct ProcessedFieldInitializers
}
var syntaxRef = initializer.Syntax;
Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular);
var syntaxTree = syntaxRef.SyntaxTree;
Debug.Assert(syntaxTree.Options.Kind != SourceCodeKind.Regular);
var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax();
var syntax = (CSharpSyntaxNode)syntaxRef.GetSyntax();
var syntaxRoot = syntaxTree.GetCompilationUnitRoot();
if (binderFactory == null)
{
binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
binderFactory = compilation.GetBinderFactory(syntaxTree);
labels = new ScriptLocalScopeBinder.Labels(scriptInitializer, syntaxRoot);
}
Binder scriptClassBinder = binderFactory.GetBinder(initializerNode);
Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass);
Binder scriptClassBinder = binderFactory.GetBinder(syntax);
Debug.Assert(((NamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass);
if (firstDebugImports == null)
{
firstDebugImports = scriptClassBinder.ImportChain;
}
Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptInitializer, scriptClassBinder);
Binder parentBinder = new ExecutableCodeBinder(
syntaxRoot,
scriptInitializer,
new ScriptLocalScopeBinder(labels, scriptClassBinder));
BoundInitializer boundInitializer;
if ((object)fieldSymbol != null)
{
boundInitializer = BindFieldInitializer(
new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol),
parentBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol),
fieldSymbol,
(EqualsValueClauseSyntax)initializerNode,
(EqualsValueClauseSyntax)syntax,
diagnostics);
}
else if (initializerNode.Kind() == SyntaxKind.LabeledStatement)
{
// TODO: labels in interactive
var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray<BoundNode>.Empty, true);
boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement);
}
else
{
var collisionDetector = new LocalScopeBinder(parentBinder);
boundInitializer = BindGlobalStatement(collisionDetector, scriptInitializer, (StatementSyntax)initializerNode, diagnostics,
boundInitializer = BindGlobalStatement(
parentBinder,
scriptInitializer,
(StatementSyntax)syntax,
diagnostics,
isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1);
}
......
......@@ -53,31 +53,36 @@ internal void LookupExtensionMethods(LookupResult result, string name, int arity
/// <remarks>
/// Makes a second attempt if the results are not viable, in order to produce more detailed failure information (symbols and diagnostics).
/// </remarks>
private void LookupSymbolsWithFallback(LookupResult result, string name, int arity, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved = null, LookupOptions options = LookupOptions.Default)
private Binder LookupSymbolsWithFallback(LookupResult result, string name, int arity, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved = null, LookupOptions options = LookupOptions.Default)
{
Debug.Assert(options.AreValid());
// don't create diagnosis instances unless lookup fails
this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics);
var binder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics);
Debug.Assert((binder != null) || result.IsClear);
if (result.Kind != LookupResultKind.Viable && result.Kind != LookupResultKind.Empty)
{
result.Clear();
// retry to get diagnosis
this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics);
var otherBinder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics);
Debug.Assert(binder == otherBinder);
}
Debug.Assert(result.IsMultiViable || result.IsClear || result.Error != null);
return binder;
}
private void LookupSymbolsInternal(
private Binder LookupSymbolsInternal(
LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert(result.IsClear);
Debug.Assert(options.AreValid());
Binder binder = null;
for (var scope = this; scope != null && !result.IsMultiViable; scope = scope.Next)
{
if (!result.IsClear)
if (binder != null)
{
var tmp = LookupResult.GetInstance();
scope.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
......@@ -87,8 +92,13 @@ private void LookupSymbolsWithFallback(LookupResult result, string name, int ari
else
{
scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
if (!result.IsClear)
{
binder = scope;
}
}
}
return binder;
}
internal virtual void LookupSymbolsInSingleBinder(
......
......@@ -342,7 +342,7 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti
var result = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
var binder = this.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
// result.Symbols can be empty in some malformed code, e.g. when a labeled statement is used an embedded statement in an if or foreach statement
// In this case we create new label symbol on the fly, and an error is reported by parser
......@@ -357,14 +357,18 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti
}
// check to see if this label (illegally) hides a label from an enclosing scope
result.Clear();
this.Next.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
if (result.IsMultiViable)
if (binder != null)
{
// The label '{0}' shadows another label by the same name in a contained scope
Error(diagnostics, ErrorCode.ERR_LabelShadow, node.Identifier, node.Identifier.ValueText);
hasError = true;
result.Clear();
binder.Next.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
if (result.IsMultiViable)
{
// The label '{0}' shadows another label by the same name in a contained scope
Error(diagnostics, ErrorCode.ERR_LabelShadow, node.Identifier, node.Identifier.ValueText);
hasError = true;
}
}
diagnostics.Add(node, useSiteDiagnostics);
result.Free();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
......
......@@ -159,22 +159,25 @@ protected SourceLocalSymbol MakeLocal(VariableDeclarationSyntax declaration, Var
protected void BuildLabels(SyntaxList<StatementSyntax> statements, ref ArrayBuilder<LabelSymbol> labels)
{
var containingMethod = (MethodSymbol)this.ContainingMemberOrLambda;
foreach (var statement in statements)
{
var stmt = statement;
while (stmt.Kind() == SyntaxKind.LabeledStatement)
{
var labeledStatement = (LabeledStatementSyntax)stmt;
if (labels == null)
{
labels = ArrayBuilder<LabelSymbol>.GetInstance();
}
BuildLabels(containingMethod, statement, ref labels);
}
}
var labelSymbol = new SourceLabelSymbol(containingMethod, labeledStatement.Identifier);
labels.Add(labelSymbol);
stmt = labeledStatement.Statement;
internal static void BuildLabels(MethodSymbol containingMethod, StatementSyntax statement, ref ArrayBuilder<LabelSymbol> labels)
{
while (statement.Kind() == SyntaxKind.LabeledStatement)
{
var labeledStatement = (LabeledStatementSyntax)statement;
if (labels == null)
{
labels = ArrayBuilder<LabelSymbol>.GetInstance();
}
var labelSymbol = new SourceLabelSymbol(containingMethod, labeledStatement.Identifier);
labels.Add(labelSymbol);
statement = labeledStatement.Statement;
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal class NameofBinder : Binder
internal sealed class NameofBinder : Binder
{
private readonly SyntaxNode _nameofArgument;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class ScriptLocalScopeBinder : LocalScopeBinder
{
private readonly Labels _labels;
internal ScriptLocalScopeBinder(Labels labels, Binder next) : base(next)
{
_labels = labels;
}
internal override Symbol ContainingMemberOrLambda
{
get { return _labels.ScriptInitializer; }
}
protected override ImmutableArray<LabelSymbol> BuildLabels()
{
return _labels.GetLabels();
}
// Labels potentially shared across multiple ScriptLocalScopeBinder instances.
new internal sealed class Labels
{
private readonly SynthesizedInteractiveInitializerMethod _scriptInitializer;
private readonly CompilationUnitSyntax _syntax;
private ImmutableArray<LabelSymbol> _lazyLabels;
internal Labels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax)
{
_scriptInitializer = scriptInitializer;
_syntax = syntax;
}
internal SynthesizedInteractiveInitializerMethod ScriptInitializer
{
get { return _scriptInitializer; }
}
internal ImmutableArray<LabelSymbol> GetLabels()
{
if (_lazyLabels == null)
{
ImmutableInterlocked.InterlockedInitialize(ref _lazyLabels, GetLabels(_scriptInitializer, _syntax));
}
return _lazyLabels;
}
private static ImmutableArray<LabelSymbol> GetLabels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax)
{
var builder = ArrayBuilder<LabelSymbol>.GetInstance();
foreach (var member in syntax.Members)
{
if (member.Kind() != SyntaxKind.GlobalStatement)
{
continue;
}
LocalScopeBinder.BuildLabels(scriptInitializer, ((GlobalStatementSyntax)member).Statement, ref builder);
}
return builder.ToImmutableAndFree();
}
}
}
}
......@@ -141,6 +141,7 @@
<Compile Include="Binder\MethodGroupResolution.cs" />
<Compile Include="Binder\NameofBinder.cs" />
<Compile Include="Binder\NamespaceOrTypeAndUsingDirective.cs" />
<Compile Include="Binder\ScriptLocalScopeBinder.cs" />
<Compile Include="Binder\Semantics\AccessCheck.cs" />
<Compile Include="Binder\Semantics\BestTypeInferrer.cs" />
<Compile Include="Binder\Semantics\Conversions\BestIndex.cs" />
......
......@@ -1368,10 +1368,11 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax)
container = baseType;
}
if (!binder.IsInMethodBody && (options & LookupOptions.NamespacesOrTypesOnly) == 0)
if (!binder.IsInMethodBody &&
(options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly | LookupOptions.LabelsOnly)) == 0)
{
// Method type parameters are not in scope outside a method body unless
// the position is either:
// Method type parameters are not in scope outside a method
// body unless the position is either:
// a) in a type-only context inside an expression, or
// b) inside of an XML name attribute in an XML doc comment.
var parentExpr = token.Parent as ExpressionSyntax;
......
......@@ -9,15 +9,13 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class MethodBodySemanticModel : MemberSemanticModel
{
private DiagnosticBag _ignoredDiagnostics = new DiagnosticBag();
private MethodBodySemanticModel(CSharpCompilation compilation, Symbol owner, Binder rootBinder, CSharpSyntaxNode syntax, SyntaxTreeSemanticModel parentSemanticModelOpt = null, int speculatedPosition = 0)
: base(compilation, syntax, owner, rootBinder, parentSemanticModelOpt, speculatedPosition)
{
Debug.Assert((object)owner != null);
Debug.Assert(owner.Kind == SymbolKind.Method);
Debug.Assert(syntax != null);
Debug.Assert(owner.ContainingType.IsScriptClass || syntax.Kind() != SyntaxKind.CompilationUnit);
Debug.Assert(syntax.Kind() != SyntaxKind.CompilationUnit);
}
/// <summary>
......@@ -29,16 +27,6 @@ internal static MethodBodySemanticModel Create(CSharpCompilation compilation, Me
return new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax);
}
/// <summary>
/// Creates a SemanticModel for an ArrowExpressionClause, which includes
/// an ExecutableCodeBinder and a ScopedExpressionBinder.
/// </summary>
internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, ArrowExpressionClauseSyntax syntax)
{
Binder binder = new ExecutableCodeBinder(syntax, owner, rootBinder);
return new MethodBodySemanticModel(compilation, owner, binder, syntax);
}
internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics)
{
if (node.Kind() == SyntaxKind.ArrowExpressionClause)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -26,6 +25,7 @@ internal partial class SyntaxTreeSemanticModel : CSharpSemanticModel
private readonly BinderFactory _binderFactory;
private Func<CSharpSyntaxNode, MemberSemanticModel> _createMemberModelFunction;
private readonly bool _ignoresAccessibility;
private ScriptLocalScopeBinder.Labels _globalStatementLabels;
private static readonly Func<CSharpSyntaxNode, bool> s_isMemberDeclarationFunction = IsMemberDeclaration;
......@@ -979,14 +979,27 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
case SyntaxKind.GlobalStatement:
{
Debug.Assert(!this.IsRegularCSharp);
var parent = node.Parent;
// TODO (tomat): handle misplaced global statements
if (node.Parent.Kind() == SyntaxKind.CompilationUnit)
if (parent.Kind() == SyntaxKind.CompilationUnit)
{
var scriptConstructor = this.Compilation.ScriptClass.InstanceConstructors.First();
var scriptInitializer = _compilation.ScriptClass.GetScriptInitializer();
Debug.Assert((object)scriptInitializer != null);
if ((object)scriptInitializer == null)
{
return null;
}
// Share labels across all global statements.
if (_globalStatementLabels == null)
{
Interlocked.CompareExchange(ref _globalStatementLabels, new ScriptLocalScopeBinder.Labels(scriptInitializer, (CompilationUnitSyntax)parent), null);
}
return MethodBodySemanticModel.Create(
this.Compilation,
scriptConstructor,
outer,
scriptInitializer,
new ScriptLocalScopeBinder(_globalStatementLabels, outer),
node);
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......
......@@ -3,11 +3,12 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
public class GotoStatementTest : EmitMetadataTestBase
public class GotoTests : EmitMetadataTestBase
{
[Fact]
public void Goto()
......@@ -804,34 +805,256 @@ public static int Main()
CompileAndVerify(text, expectedOutput: "Catch");
}
[Fact(Skip = "3712"), WorkItem(3712)]
public void Goto_Script()
[Fact]
public void OutOfScriptBlock()
{
string source = @"
using System;
string source =
@"bool b = true;
L0: ;
{
{
System.Console.WriteLine(b);
if (b) b = !b;
else goto L1;
goto L0;
}
L1: ;
}";
string expectedOutput =
@"True
False";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
Console.WriteLine(""a"");
goto C;
Console.Write(""you won't see me"");
C: Console.WriteLine(""b"");
";
string expectedOutput = @"a
b
";
CompileAndVerify(source, parseOptions: new CSharpParseOptions(kind: SourceCodeKind.Script), expectedOutput: expectedOutput);
[Fact]
public void IntoScriptBlock()
{
string source =
@"goto L0;
{
L0: goto L1;
}
{
L1: ;
}";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
// (1,6): error CS0159: No such label 'L0' within the scope of the goto statement
// goto L0;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L0").WithArguments("L0").WithLocation(1, 6),
// (3,14): error CS0159: No such label 'L1' within the scope of the goto statement
// L0: goto L1;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L1").WithArguments("L1").WithLocation(3, 14),
// (3,5): warning CS0164: This label has not been referenced
// L0: goto L1;
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L0").WithLocation(3, 5),
// (6,5): warning CS0164: This label has not been referenced
// L1: ;
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L1").WithLocation(6, 5));
}
[Fact]
public void AcrossScriptDeclarations()
{
string source =
@"int P { get; } = G(""P"");
L:
int F = G(""F"");
int Q { get; } = G(""Q"");
static int x = 2;
static int G(string s)
{
System.Console.WriteLine(""{0}: {1}"", x, s);
x++;
return x;
}
if (Q < 4) goto L;";
string expectedOutput =
@"2: P
3: F
4: Q";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
[Fact]
public void AcrossSubmissions()
{
var references = new[] { MscorlibRef_v4_0_30316_17626, SystemCoreRef };
var source0 =
@"bool b = false;
L: ;
if (b)
{
goto L;
}";
var source1 =
@"goto L;";
var s0 = CSharpCompilation.CreateScriptCompilation("s0.dll", SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script), references);
s0.VerifyDiagnostics();
var s1 = CSharpCompilation.CreateScriptCompilation("s1.dll", SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Script), references, previousScriptCompilation: s0);
s1.VerifyDiagnostics(
// (1,6): error CS0159: No such label 'L' within the scope of the goto statement
// goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(1, 6));
}
[Fact]
public void OutOfScriptMethod()
{
string source =
@"static void F(bool b)
{
if (b) goto L;
}
L:
F(true);";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script);
compilation.VerifyDiagnostics(
// (5,1): warning CS0164: This label has not been referenced
// L:
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L").WithLocation(5, 1),
// (3,17): error CS0159: No such label 'L' within the scope of the goto statement
// if (b) goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(3, 17));
}
[Fact]
public void IntoScriptMethod()
{
string source =
@"static void F()
{
L:
return;
}
goto L;";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script);
compilation.VerifyDiagnostics(
// (6,6): error CS0159: No such label 'L' within the scope of the goto statement
// goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(6, 6),
// (3,1): warning CS0164: This label has not been referenced
// L:
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L").WithLocation(3, 1));
}
[Fact]
public void InScriptSwitch()
{
string source =
@"int x = 3;
switch (x)
{
case 1:
break;
case 2:
System.Console.WriteLine(x);
break;
default:
goto case 2;
}";
string expectedOutput =
@"3";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
[Fact]
public void DuplicateLabelInScript()
{
string source =
@"bool b = false;
L: ;
if (b)
{
goto L;
}
else
{
b = !b;
if (b) goto L;
L: ;
}";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
// (11,1): error CS0158: The label 'L' shadows another label by the same name in a contained scope
// L: ;
Diagnostic(ErrorCode.ERR_LabelShadow, "L").WithArguments("L").WithLocation(11, 1));
}
[Fact]
public void DuplicateLabelInSeparateSubmissions()
{
var references = new[] { MscorlibRef_v4_0_30316_17626, SystemCoreRef };
var source0 =
@"bool b = false;
L: ;
if (b)
{
goto L;
}";
var source1 =
@"if (!b)
{
b = !b;
if (b) goto L;
L: ;
}";
var s0 = CSharpCompilation.CreateScriptCompilation("s0.dll", SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script), references);
s0.VerifyDiagnostics();
var s1 = CSharpCompilation.CreateScriptCompilation("s1.dll", SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Script), references, previousScriptCompilation: s0);
s1.VerifyDiagnostics();
}
[Fact]
public void LoadedFile()
{
var sourceA =
@"goto A;
A: goto B;";
var sourceB =
@"#load ""a.csx""
goto B;
B: goto A;";
var resolver = TestSourceReferenceResolver.Create(KeyValuePair.Create("a.csx", sourceA));
var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver);
var compilation = CreateCompilationWithMscorlib45(sourceB, options: options, parseOptions: TestOptions.Script);
compilation.GetDiagnostics().Verify(
// a.csx(2,9): error CS0159: No such label 'B' within the scope of the goto statement
// A: goto B;
Diagnostic(ErrorCode.ERR_LabelNotFound, "B").WithArguments("B").WithLocation(2, 9),
// (3,9): error CS0159: No such label 'A' within the scope of the goto statement
// B: goto A;
Diagnostic(ErrorCode.ERR_LabelNotFound, "A").WithArguments("A").WithLocation(3, 9));
}
[Fact, WorkItem(3712)]
public void Label_GetDeclaredSymbol_Script()
{
string source =
@"L0: goto L1;
static void F() { }
L1: goto L0;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement);
var symbol = model.GetDeclaredSymbol(label);
Assert.Equal("L0", symbol.Name);
}
[Fact(Skip = "3712"), WorkItem(3712)]
[Fact, WorkItem(3712)]
public void Label_GetDeclaredSymbol_Error_Script()
{
string source = @"
C: \a\b\
";
var tree = Parse(source, options: new CSharpParseOptions(kind: SourceCodeKind.Script));
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement);
var symbol = model.GetDeclaredSymbol(label);
// TODO: Add some verification for symbol...
Assert.Equal("C", symbol.Name);
}
}
}
......@@ -298,6 +298,38 @@ public void LabelLookup()
Assert.Empty(model.LookupLabels(source.Length - 1)); // Used to assert.
}
[Fact]
public void Labels()
{
string source =
@"L0: ;
goto L0;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var root = tree.GetCompilationUnitRoot();
var statements = root.ChildNodes().Select(n => ((GlobalStatementSyntax)n).Statement).ToArray();
var symbol0 = model.GetDeclaredSymbol((LabeledStatementSyntax)statements[0]);
Assert.NotNull(symbol0);
var symbol1 = model.GetSymbolInfo(((GotoStatementSyntax)statements[1]).Expression).Symbol;
Assert.Same(symbol0, symbol1);
}
[Fact]
public void Variables()
{
string source =
@"int x = 1;
object y = x;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var root = tree.GetCompilationUnitRoot();
var declarations = root.ChildNodes().Select(n => ((FieldDeclarationSyntax)n).Declaration.Variables[0]).ToArray();
var symbol0 = model.GetDeclaredSymbol(declarations[0]);
Assert.NotNull(symbol0);
var symbol1 = model.GetSymbolInfo(declarations[1].Initializer.Value).Symbol;
Assert.Same(symbol0, symbol1);
}
[WorkItem(543890)]
[Fact]
public void ThisIndexerAccessInSubmission()
......
......@@ -2115,7 +2115,7 @@ static int Main()
}
[Fact]
public void SwitchFallOut_Script1()
public void SwitchFallOut_Script()
{
var source =
@"using System;
......@@ -2137,7 +2137,7 @@ public void SwitchFallOut_Script1()
}
[Fact]
public void SwitchFallOut_Script2()
public void SwitchFallOut_Submission()
{
var source =
@"using System;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Xunit;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
......@@ -39,8 +39,8 @@ public void MissingFile()
public void FileWithErrors()
{
var code = "#load \"a.csx\"";
var resolver = CreateResolver(
Script("a.csx", @"
var resolver = TestSourceReferenceResolver.Create(
KeyValuePair.Create("a.csx", @"
#load ""b.csx""
asdf();"));
var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver);
......@@ -72,20 +72,5 @@ public void NoSourceReferenceResolver()
// #load "test"
Diagnostic(ErrorCode.ERR_SourceFileReferencesNotSupported, @"#load ""test""").WithLocation(1, 1));
}
private static SourceReferenceResolver CreateResolver(params KeyValuePair<string, string>[] scripts)
{
var sources = new Dictionary<string, string>();
foreach (var script in scripts)
{
sources.Add(script.Key, script.Value);
}
return TestSourceReferenceResolver.Create(sources);
}
private static KeyValuePair<string, string> Script(string path, string source)
{
return new KeyValuePair<string, string>(path, source);
}
}
}
......@@ -398,6 +398,20 @@ System.Console.Write("complete")
}")
End Sub
<Fact>
Public Sub ScriptEntryPoint_MissingMethods()
Dim comp = CreateCompilationWithMscorlib(
<compilation>
<file name="a.vbx"><![CDATA[
System.Console.WriteLine(1)
]]></file>
</compilation>,
parseOptions:=TestOptions.Script,
options:=TestOptions.DebugExe)
comp.VerifyDiagnostics(
Diagnostic(ERRID.ERR_MissingRuntimeHelper).WithArguments("Task.GetAwaiter").WithLocation(1, 1))
End Sub
End Class
End Namespace
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.CodeAnalysis;
......@@ -12,6 +13,11 @@ public sealed class TestSourceReferenceResolver : SourceReferenceResolver
{
public static readonly SourceReferenceResolver Default = new TestSourceReferenceResolver(sources: null);
public static SourceReferenceResolver Create(params KeyValuePair<string, string>[] sources)
{
return TestSourceReferenceResolver.Create(sources.ToDictionary(p => p.Key, p => p.Value));
}
public static SourceReferenceResolver Create(Dictionary<string, string> sources = null)
{
return (sources == null || sources.Count == 0) ? Default : new TestSourceReferenceResolver(sources);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册