Skip to content
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style

dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static

dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
Expand All @@ -77,7 +77,7 @@ dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = n
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style

dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly

dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
Expand Down
6 changes: 4 additions & 2 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8278,6 +8278,7 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO
{
usingKeyword = CheckFeatureAvailability(usingKeyword, MessageID.IDS_FeatureUsingDeclarations);
}
bool canParseAsLocalFunction = usingKeyword == default;

var mods = _pool.Allocate();
this.ParseDeclarationModifiers(mods);
Expand All @@ -8288,7 +8289,7 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO
TypeSyntax type;
LocalFunctionStatementSyntax localFunction;
this.ParseLocalDeclaration(variables,
allowLocalFunctions: usingKeyword == default,
allowLocalFunctions: canParseAsLocalFunction,
mods: mods.ToList(),
type: out type,
localFunction: out localFunction);
Expand All @@ -8301,7 +8302,8 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO

// If we find an accessibility modifier but no local function it's likely
// the user forgot a closing brace. Let's back out of statement parsing.
if (mods.Count > 0 &&
if (canParseAsLocalFunction &&
mods.Count > 0 &&
IsAccessibilityModifier(((SyntaxToken)mods[0]).ContextualKind))
{
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UnitTests;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.Semantics
Expand Down Expand Up @@ -769,5 +770,29 @@ static void Main()
Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "using S3 S3 = new S3();").WithArguments("S3.Dispose()").WithLocation(40, 9)
);
}

[Fact]
[WorkItem(36413, "https://github.com/dotnet/roslyn/issues/36413")]
public void UsingDeclarationsWithInvalidModifiers()
{
var source = @"
using System;
class C
{
static void Main()
{
using public readonly var x = (IDisposable)null;
}
}
";
CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(
// (7,15): error CS0106: The modifier 'public' is not valid for this item
// using public readonly var x = (IDisposable)null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(7, 15),
// (7,22): error CS0106: The modifier 'readonly' is not valid for this item
// using public readonly var x = (IDisposable)null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(7, 22)
);
}
}
}
38 changes: 38 additions & 0 deletions src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,44 @@ public void TestUsingVarWithVarDeclaration()
Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString());
}

[Fact]
[WorkItem(36413, "https://github.com/dotnet/roslyn/issues/36413")]
public void TestUsingVarWithInvalidDeclaration()
{
var text = "using public readonly var a = b;";
var statement = this.ParseStatement(text, options: TestOptions.Regular8);

Assert.NotNull(statement);
Assert.Equal(SyntaxKind.LocalDeclarationStatement, statement.Kind());
Assert.Equal(text, statement.ToString());
Assert.Equal(2, statement.Errors().Length);
Assert.Equal((int)ErrorCode.ERR_BadMemberFlag, statement.Errors()[0].Code);
Assert.Equal("public", statement.Errors()[0].Arguments[0]);
Assert.Equal((int)ErrorCode.ERR_BadMemberFlag, statement.Errors()[1].Code);
Assert.Equal("readonly", statement.Errors()[1].Arguments[0]);

var us = (LocalDeclarationStatementSyntax)statement;
Assert.NotNull(us.UsingKeyword);
Assert.Equal(SyntaxKind.UsingKeyword, us.UsingKeyword.Kind());

Assert.NotNull(us.Declaration);
Assert.NotNull(us.Declaration.Type);
Assert.Equal("var", us.Declaration.Type.ToString());
Assert.Equal(SyntaxKind.IdentifierName, us.Declaration.Type.Kind());
Assert.Equal(SyntaxKind.IdentifierToken, ((IdentifierNameSyntax)us.Declaration.Type).Identifier.Kind());
Assert.Equal(2, us.Modifiers.Count);
Assert.Equal("public", us.Modifiers[0].ToString());
Assert.Equal("readonly", us.Modifiers[1].ToString());
Assert.Equal(1, us.Declaration.Variables.Count);
Assert.NotNull(us.Declaration.Variables[0].Identifier);
Assert.Equal("a", us.Declaration.Variables[0].Identifier.ToString());
Assert.Null(us.Declaration.Variables[0].ArgumentList);
Assert.NotNull(us.Declaration.Variables[0].Initializer);
Assert.NotNull(us.Declaration.Variables[0].Initializer.EqualsToken);
Assert.NotNull(us.Declaration.Variables[0].Initializer.Value);
Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString());
}

[Fact]
public void TestUsingVarWithVarDeclarationTree()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.MoveToNamespace;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace;
using Microsoft.VisualStudio.Composition;
Expand All @@ -16,14 +20,15 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MoveToNamespace
[UseExportProvider]
public class MoveToNamespaceTests : AbstractMoveToNamespaceTests
{
private static readonly IExportProviderFactory CSharpExportProviderFactory =
private static readonly IExportProviderFactory ExportProviderFactory =
ExportProviderCache.GetOrCreateExportProviderFactory(
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic
.WithPart(typeof(TestMoveToNamespaceOptionsService))
.WithPart(typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService)));
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithPart(typeof(TestMoveToNamespaceOptionsService)));

protected override TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters)
=> TestWorkspace.CreateCSharp(initialMarkup, parameters.parseOptions, parameters.compilationOptions, exportProvider: CSharpExportProviderFactory.CreateExportProvider());
=> CreateWorkspaceFromFile(initialMarkup, parameters, ExportProviderFactory);

protected TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters, IExportProviderFactory exportProviderFactory)
=> TestWorkspace.CreateCSharp(initialMarkup, parameters.parseOptions, parameters.compilationOptions, exportProvider: exportProviderFactory.CreateExportProvider());

protected override ParseOptions GetScriptOptions() => Options.Script;

Expand Down Expand Up @@ -1080,5 +1085,34 @@ class C2
{
{"Two.C2", "Three.C2" }
});

[WpfFact, Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
[WorkItem(35577, "https://github.com/dotnet/roslyn/issues/35577")]
public async Task MoveToNamespace_WithoutOptionsService()
{
var code = @"namespace A[||]
{
class MyClass
{
void Method() { }
}
}";

var exportProviderWithoutOptionsService = ExportProviderCache.GetOrCreateExportProviderFactory(
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithoutPartsOfType(typeof(IMoveToNamespaceOptionsService)));

using (var workspace = CreateWorkspaceFromFile(code, new TestParameters(), exportProviderWithoutOptionsService))
using (var testState = new TestState(workspace))
{
Assert.Null(testState.TestMoveToNamespaceOptionsService);

var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync(
testState.InvocationDocument,
testState.TestInvocationDocument.SelectedSpans.Single(),
CancellationToken.None);

Assert.Empty(actions);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,23 @@ void M(int? a)
new TestParameters(parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)));
}

[Fact]
[WorkItem(36467, "https://github.com/dotnet/roslyn/issues/36467")]
[Trait(Traits.Feature, Traits.Features.CodeActionsUseCompoundAssignment)]
public async Task TestNotSuggestedWhenRightHandIsThrowExpression()
{
await TestMissingAsync(
@"using System;
public class C
{
void M(int? a)
{
a [||]= a ?? throw new Exception();
}
}",
new TestParameters(parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8)));
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCompoundAssignment)]
public async Task TestField()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UseLocalFunction;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
Expand Down Expand Up @@ -3660,5 +3661,33 @@ void M()
}
}", parseOptions: CSharp8ParseOptions);
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
public async Task TestWithNullableParameterAndReturn()
{
await TestInRegularAndScriptAsync(
@"#nullable enable

using System;

class Program
{
static void Main(string[] args)
{
Func<string?, string?> [||]f = s => s;
}
}",
@"#nullable enable

using System;

class Program
{
static void Main(string[] args)
{
static string? f(string? s) => s;
}
}", parseOptions: TestOptions.Regular8WithNullableAnalysis);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void Dispose()
public Document InvocationDocument => Workspace.CurrentSolution.GetDocument(TestInvocationDocument.Id);

public TestMoveToNamespaceOptionsService TestMoveToNamespaceOptionsService
=> (TestMoveToNamespaceOptionsService)Workspace.Services.GetService<IMoveToNamespaceOptionsService>();
=> (TestMoveToNamespaceOptionsService)MoveToNamespaceService.OptionsService;

public IMoveToNamespaceService MoveToNamespaceService
=> InvocationDocument.GetLanguageService<IMoveToNamespaceService>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// 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.Immutable;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Host.Mef;
using System.Composition;

namespace Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace
{
[ExportWorkspaceService(typeof(IMoveToNamespaceOptionsService)), Shared]
[Export(typeof(IMoveToNamespaceOptionsService)), Shared]
[PartNotDiscoverable]
class TestMoveToNamespaceOptionsService : IMoveToNamespaceOptionsService
{
internal static readonly MoveToNamespaceOptionsResult DefaultOptions = new MoveToNamespaceOptionsResult("TestNewNamespaceValue");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ internal class CSharpMoveToNamespaceService :
AbstractMoveToNamespaceService<NamespaceDeclarationSyntax, TypeDeclarationSyntax>
{
[ImportingConstructor]
public CSharpMoveToNamespaceService()
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpMoveToNamespaceService(
[Import(AllowDefault = true)] IMoveToNamespaceOptionsService optionsService)
: base(optionsService)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ ParameterSyntax PromoteParameter(ParameterSyntax parameterNode, IParameterSymbol

if (parameterNode.Type == null)
{
parameterNode = parameterNode.WithType(delegateParameter?.Type.GenerateTypeSyntax() ?? s_objectType);
parameterNode = parameterNode.WithType(delegateParameter?.Type.WithNullability(delegateParameter.NullableAnnotation).GenerateTypeSyntax() ?? s_objectType);
}

if (delegateParameter?.HasExplicitDefaultValue == true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.LanguageServices;
using System.Text;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.MoveToNamespace
Expand All @@ -23,6 +22,7 @@ internal interface IMoveToNamespaceService : ILanguageService
Task<MoveToNamespaceAnalysisResult> AnalyzeTypeAtPositionAsync(Document document, int position, CancellationToken cancellationToken);
Task<MoveToNamespaceResult> MoveToNamespaceAsync(MoveToNamespaceAnalysisResult analysisResult, string targetNamespace, CancellationToken cancellationToken);
MoveToNamespaceOptionsResult GetChangeNamespaceOptions(Document document, string defaultNamespace, ImmutableArray<string> namespaces);
IMoveToNamespaceOptionsService OptionsService { get; }
}

internal abstract class AbstractMoveToNamespaceService<TNamespaceDeclarationSyntax, TNamedTypeDeclarationSyntax>
Expand All @@ -35,16 +35,28 @@ internal abstract class AbstractMoveToNamespaceService<TNamespaceDeclarationSynt
protected abstract string GetNamespaceName(TNamedTypeDeclarationSyntax namedTypeSyntax);
protected abstract bool IsContainedInNamespaceDeclaration(TNamespaceDeclarationSyntax namespaceSyntax, int position);

public IMoveToNamespaceOptionsService OptionsService { get; }

protected AbstractMoveToNamespaceService(IMoveToNamespaceOptionsService moveToNamespaceOptionsService)
{
OptionsService = moveToNamespaceOptionsService;
}

public async Task<ImmutableArray<AbstractMoveToNamespaceCodeAction>> GetCodeActionsAsync(
Document document,
TextSpan span,
CancellationToken cancellationToken)
{
var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, cancellationToken).ConfigureAwait(false);

if (typeAnalysisResult.CanPerform)
// Code actions cannot be completed without the options needed
// to fill in missing information.
if (OptionsService != null)
{
return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult));
var typeAnalysisResult = await AnalyzeTypeAtPositionAsync(document, span.Start, cancellationToken).ConfigureAwait(false);

if (typeAnalysisResult.CanPerform)
{
return ImmutableArray.Create(AbstractMoveToNamespaceCodeAction.Generate(this, typeAnalysisResult));
}
}

return ImmutableArray<AbstractMoveToNamespaceCodeAction>.Empty;
Expand Down Expand Up @@ -237,14 +249,8 @@ public MoveToNamespaceOptionsResult GetChangeNamespaceOptions(
ImmutableArray<string> namespaces)
{
var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
var moveToNamespaceOptionsService = document.Project.Solution.Workspace.Services.GetService<IMoveToNamespaceOptionsService>();

if (moveToNamespaceOptionsService == null)
{
return MoveToNamespaceOptionsResult.Cancelled;
}

return moveToNamespaceOptionsService.GetChangeNamespaceOptions(
return OptionsService.GetChangeNamespaceOptions(
defaultNamespace,
namespaces,
syntaxFactsService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public MoveToNamespaceCodeActionProvider()

public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var service = context.Document.GetLanguageService<IMoveToNamespaceService>();
var actions = await service.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
var moveToNamespaceService = context.Document.GetLanguageService<IMoveToNamespaceService>();
var actions = await moveToNamespaceService.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
context.RegisterRefactorings(actions);
}
}
Expand Down
Loading