Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 60 additions & 19 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,10 @@ private void ParseNamespaceBody(ref SyntaxToken openBrace, ref NamespaceBodyBuil
}

case SyntaxKind.UsingKeyword:
if (isGlobal && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken)
if (isGlobal && (this.PeekToken(1).Kind == SyntaxKind.OpenParenToken || (!IsScript && IsPossibleTopLevelUsingLocalDeclarationStatement())))
{
// incomplete members must be processed before we add any nodes to the body:
AddIncompleteMembers(ref pendingIncompleteMembers, ref body);
body.Members.Add(adjustStateAndReportStatementOutOfOrder(ref seen, ParseTopLevelUsingStatement()));
// Top-level using statement or using local declaration
goto default;
}
else
{
Expand Down Expand Up @@ -591,20 +590,6 @@ MemberDeclarationSyntax adjustStateAndReportStatementOutOfOrder(ref NamespacePar
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private GlobalStatementSyntax ParseTopLevelUsingStatement()
{
bool wasInAsync = IsInAsync;
if (!IsScript)
{
IsInAsync = true; // We are implicitly in an async context
}

var topLevelUsingStatement = CheckSimpleProgramsFeatureAvailability(_syntaxFactory.GlobalStatement(ParseUsingStatement(attributes: default)));
IsInAsync = wasInAsync;
return topLevelUsingStatement;
}

private GlobalStatementSyntax CheckSimpleProgramsFeatureAvailability(GlobalStatementSyntax globalStatementSyntax)
{
if (IsScript || _checkedSimpleProgramsFeatureAvailability)
Expand Down Expand Up @@ -2374,7 +2359,6 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool
switch (statement?.Kind)
{
case null:
case SyntaxKind.LocalDeclarationStatement:
case SyntaxKind.LocalFunctionStatement:
case SyntaxKind.ExpressionStatement when
!isScript &&
Expand All @@ -2386,6 +2370,9 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool

return false;

case SyntaxKind.LocalDeclarationStatement:
return !isScript && ((LocalDeclarationStatementSyntax)statement).UsingKeyword is object;

default:
return true;
}
Expand Down Expand Up @@ -6957,6 +6944,11 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
return true;
}

return IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(isGlobalScriptLevel);
}

private bool IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(bool isGlobalScriptLevel)
{
bool? typedIdentifier = IsPossibleTypedIdentifierStart(this.CurrentToken, this.PeekToken(1), allowThisKeyword: false);
Copy link
Contributor

@cston cston Mar 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line. #Resolved

if (typedIdentifier != null)
{
Expand All @@ -6978,6 +6970,8 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
//
// Note that we explicitly do this check when we see that the code spreads over multiple
// lines. We don't want this if the user has actually written "X.Y z"
var tk = this.CurrentToken.ContextualKind;

if (tk == SyntaxKind.IdentifierToken)
{
var token1 = PeekToken(1);
Expand Down Expand Up @@ -7053,6 +7047,53 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
}
}

private bool IsPossibleTopLevelUsingLocalDeclarationStatement()
{
if (this.CurrentToken.Kind != SyntaxKind.UsingKeyword)
{
return false;
}

var tk = PeekToken(1).Kind;

if (tk == SyntaxKind.RefKeyword)
{
return true;
}

if (IsDeclarationModifier(tk)) // treat `const int x = 2;` as a local variable declaration
{
if (tk != SyntaxKind.StaticKeyword) // For `static` we still need to make sure we have a typed identifier after it, because `using static type;` is a valid using directive.
{
return true;
}
}
else if (SyntaxFacts.IsPredefinedType(tk))
{
return true;
}

var resetPoint = this.GetResetPoint();
try
{
// Skip 'using' keyword
EatToken();

if (tk == SyntaxKind.StaticKeyword)
{
// Skip 'static' keyword
EatToken();
}

return IsPossibleFirstTypedIdentifierInLocaDeclarationStatement(isGlobalScriptLevel: false);
}
finally
{
this.Reset(ref resetPoint);
this.Release(ref resetPoint);
}
}

// Looks ahead for a declaration of a field, property or method declaration following a nullable type T?.
private bool IsPossibleDeclarationStatementFollowingNullableType()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,27 @@ ref int local(bool flag, ref int a, ref int b)
CompileAndVerify(comp, expectedOutput: "100 200 300", verify: Verification.Skipped);
}

[Fact]
public void LocalDeclarationStatement_09()
{
var text = @"
using var a = new MyDisposable();
System.Console.Write(1);

class MyDisposable : System.IDisposable
{
public void Dispose()
{
System.Console.Write(2);
}
}
";

var comp = CreateCompilation(text, options: TestOptions.DebugExe, parseOptions: DefaultParseOptions);

CompileAndVerify(comp, expectedOutput: "12", verify: Verification.Skipped);
}

[Fact]
public void LocalUsedBeforeDeclaration_01()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,12 @@ public void Repro611177()
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);

var usingSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingDirectiveSyntax>().Single();
model.GetSymbolInfo(usingSyntax);
Assert.Empty(tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingDirectiveSyntax>());

var identifierSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single();
model.GetSymbolInfo(identifierSyntax);
foreach (var identifierSyntax in tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>())
{
model.GetSymbolInfo(identifierSyntax);
}
}

[WorkItem(611177, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/611177")]
Expand Down
Loading