Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer completion for #nullable enable|disable #31171

Merged
merged 5 commits into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Syntax/DirectiveTriviaSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public SyntaxToken DirectiveNameToken
return ((LoadDirectiveTriviaSyntax)this).LoadKeyword;
case SyntaxKind.ShebangDirectiveTrivia:
return ((ShebangDirectiveTriviaSyntax)this).ExclamationToken;
case SyntaxKind.NullableDirectiveTrivia:
return ((NullableDirectiveTriviaSyntax)this).NullableKeyword;
default:
throw ExceptionUtilities.UnexpectedValue(this.Kind());
}
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ public static bool IsPreprocessorDirective(SyntaxKind kind)
case SyntaxKind.LoadDirectiveTrivia:
case SyntaxKind.BadDirectiveTrivia:
case SyntaxKind.ShebangDirectiveTrivia:
case SyntaxKind.NullableDirectiveTrivia:
return true;
default:
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ private void VerifyDirectivesSpecial(CSharpSyntaxNode node, params DirectiveInfo
Assert.Equal(exp.Text, setting.ValueText);
Assert.True(setting.Kind() == SyntaxKind.EnableKeyword || setting.Kind() == SyntaxKind.DisableKeyword);
}
Assert.Equal(SyntaxKind.NullableKeyword, nn.DirectiveNameToken.Kind());
Assert.True(SyntaxFacts.IsPreprocessorDirective(SyntaxKind.NullableDirectiveTrivia));
Assert.True(SyntaxFacts.IsPreprocessorKeyword(SyntaxKind.NullableKeyword));
break;
default:
if (null != exp.Text)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
{
public class DisableKeywordRecommenderTests : KeywordRecommenderTests
{
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
sharwell marked this conversation as resolved.
Show resolved Hide resolved
public async Task TestAfterNullable()
{
await VerifyKeywordAsync(@"#nullable $$");
}

[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestNotAtRoot_Interactive()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
{
[Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public class EnableKeywordRecommenderTests : KeywordRecommenderTests
sharwell marked this conversation as resolved.
Show resolved Hide resolved
{
[Fact]
public async Task TestAfterNullable()
{
await VerifyKeywordAsync(@"#nullable $$");
}

[Fact]
public async Task TestNotAfterHash()
{
await VerifyAbsenceAsync(@"#$$");
}

[Fact]
public async Task TestNotAtRoot_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script, @"$$");
}

[Fact]
public async Task TestNotAfterClass_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"class C { }
$$");
}

[Fact]
public async Task TestNotAfterGlobalStatement_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"System.Console.WriteLine();
$$");
}

[Fact]
public async Task TestNotAfterGlobalVariableDeclaration_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"int i = 0;
$$");
}

[Fact]
public async Task TestNotInUsingAlias()
{
await VerifyAbsenceAsync(@"using Goo = $$");
}

[Fact]
public async Task TestNotInEmptyStatement()
{
await VerifyAbsenceAsync(AddInsideMethod(@"$$"));
}

[Fact]
public async Task TestNotAfterPragma()
{
await VerifyAbsenceAsync(@"#pragma $$");
}

[Fact]
public async Task TestNotAfterPragmaWarning()
{
await VerifyAbsenceAsync(@"#pragma warning $$");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
{
[Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public class NullableKeywordRecommenderTests : KeywordRecommenderTests
sharwell marked this conversation as resolved.
Show resolved Hide resolved
{
[Fact]
public async Task TestNotAtRoot_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"$$");
}

[Fact]
public async Task TestNotAfterClass_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"class C { }
$$");
}

[Fact]
public async Task TestNotAfterGlobalStatement_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"System.Console.WriteLine();
$$");
}

[Fact]
public async Task TestNotAfterGlobalVariableDeclaration_Interactive()
{
await VerifyAbsenceAsync(SourceCodeKind.Script,
@"int i = 0;
$$");
}

[Fact]
public async Task TestNotInUsingAlias()
{
await VerifyAbsenceAsync(
@"using Goo = $$");
}

[Fact]
public async Task TestNotInEmptyStatement()
{
await VerifyAbsenceAsync(AddInsideMethod(
@"$$"));
}

[Fact]
public async Task TestAfterHash()
{
await VerifyKeywordAsync(
@"#$$");
}

[Fact]
public async Task TestAfterHashAndSpace()
{
await VerifyKeywordAsync(
@"# $$");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ private static ImmutableArray<IKeywordRecommender<CSharpSyntaxContext>> GetKeywo
new DynamicKeywordRecommender(),
new ElifKeywordRecommender(),
new ElseKeywordRecommender(),
new EnableKeywordRecommender(),
new EndIfKeywordRecommender(),
new EndRegionKeywordRecommender(),
new EnumKeywordRecommender(),
Expand Down Expand Up @@ -96,6 +97,7 @@ private static ImmutableArray<IKeywordRecommender<CSharpSyntaxContext>> GetKeywo
new NameOfKeywordRecommender(),
new NamespaceKeywordRecommender(),
new NewKeywordRecommender(),
new NullableKeywordRecommender(),
new NullKeywordRecommender(),
new ObjectKeywordRecommender(),
new OnKeywordRecommender(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ public DisableKeywordRecommender()

protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken)
{
// # pragma warning |
// # pragma warning d|
var previousToken1 = context.TargetToken;
var previousToken2 = previousToken1.GetPreviousToken(includeSkipped: true);
var previousToken3 = previousToken2.GetPreviousToken(includeSkipped: true);

if (previousToken1.Kind() == SyntaxKind.NullableKeyword &&
previousToken2.Kind() == SyntaxKind.HashToken)
{
// # nullable |
// # nullable d|
return true;
}

// # pragma warning |
// # pragma warning d|
return
previousToken1.Kind() == SyntaxKind.WarningKeyword &&
previousToken2.Kind() == SyntaxKind.PragmaKeyword &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;

namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders
{
internal class EnableKeywordRecommender : AbstractSyntacticSingleKeywordRecommender
{
public EnableKeywordRecommender()
: base(SyntaxKind.EnableKeyword, isValidInPreprocessorContext: true)
{
}

protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken)
{
var previousToken1 = context.TargetToken;
var previousToken2 = previousToken1.GetPreviousToken(includeSkipped: true);

// # nullable |
// # nullable e|
return previousToken1.Kind() == SyntaxKind.NullableKeyword &&
previousToken2.Kind() == SyntaxKind.HashToken;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;

namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders
{
internal class NullableKeywordRecommender : AbstractSyntacticSingleKeywordRecommender
{
public NullableKeywordRecommender()
: base(SyntaxKind.NullableKeyword, isValidInPreprocessorContext: true)
{
}

protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken)
{
return context.IsPreProcessorKeywordContext;
}
sharwell marked this conversation as resolved.
Show resolved Hide resolved
}
}