提交 7a1ac4e5 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into moveDocHighlights

......@@ -15,6 +15,7 @@
<!-- The release moniker for our packages. Developers should use "dev" and official builds pick the branch
moniker listed below -->
<RoslynNuGetMoniker Condition="'$(RoslynNuGetMoniker)' == ''">dev</RoslynNuGetMoniker>
<RoslynNuGetMoniker Condition="'$(OfficialBuild)' == 'true'">beta2</RoslynNuGetMoniker>
<!-- This is the base of the NuGet versioning for prerelease packages -->
<NuGetPreReleaseVersion>$(RoslynFileVersionBase)-$(RoslynNuGetMoniker)</NuGetPreReleaseVersion>
......
......@@ -246,7 +246,7 @@
<Compile Include="ConvertToInterpolatedString\ConvertPlaceholderToInterpolatedStringTests.cs" />
<Compile Include="CodeActions\EncapsulateField\EncapsulateFieldTests.cs" />
<Compile Include="CodeActions\ExtractMethod\ExtractMethodTests.cs" />
<Compile Include="CodeActions\GenerateDefaultConstructors\GenerateDefaultConstructorsTests.cs" />
<Compile Include="GenerateDefaultConstructors\GenerateDefaultConstructorsTests.cs" />
<Compile Include="Diagnostics\UpgradeProject\UpgradeProjectTests.cs" />
<Compile Include="Completion\CompletionProviders\DeclarationNameCompletionProviderTests_NameDeclarationInfoTests.cs" />
<Compile Include="GenerateFromMembers\AddConstructorParametersFromMembers\AddConstructorParametersFromMembersTests.cs" />
......@@ -396,6 +396,7 @@
<Compile Include="UseCollectionInitializer\UseCollectionInitializerTests.cs" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionForNullableTests.cs" />
<Compile Include="UseCoalesceExpression\UseCoalesceExpressionTests.cs" />
<Compile Include="UseDefaultLiteral\UseDefaultLiteralTests.cs" />
<Compile Include="UseExplicitTupleName\UseExplicitTupleNameTests.cs" />
<Compile Include="UseExpressionBody\Refactoring\UseExpressionBodyForConstructorsRefactoringTests.cs" />
<Compile Include="UseExpressionBody\Refactoring\UseExpressionBodyForConversionOperatorsRefactoringTests.cs" />
......
......@@ -1483,7 +1483,6 @@ public void InterpolationFormatClause_update()
edits.VerifyEdits("Update [x = $\"Hello{123:N1}\"]@8 -> [x = $\"Hello{123:N2}\"]@8");
}
[WorkItem(18970, "https://github.com/dotnet/roslyn/issues/18970")]
[Fact]
public void MatchCasePattern_UpdateDelete()
{
......@@ -1507,9 +1506,9 @@ public void MatchCasePattern_UpdateDelete()
var expected = new MatchingPairs {
{ "switch(shape) { case Point p: return 0; case Circle c: return 1; }", "switch(shape) { case Circle circle: return 1; }" },
{ "p", "circle" },
{ "case Circle c: return 1;", "case Circle circle: return 1;" },
{ "case Circle c:", "case Circle circle:" },
{ "c", "circle" },
{ "return 1;", "return 1;" }
};
......@@ -1716,7 +1715,6 @@ public void Switch_Case_Update()
"Update [case 1: f(); break;]@18 -> [case 2: f(); break;]@18");
}
[WorkItem(18970, "https://github.com/dotnet/roslyn/issues/18970")]
[Fact]
public void CasePatternLabel_UpdateDelete()
{
......@@ -1739,12 +1737,11 @@ public void CasePatternLabel_UpdateDelete()
edits.VerifyEdits(
"Update [case Circle c: return 1;]@55 -> [case Circle circle: return 1;]@26",
"Update [p]@37 -> [circle]@38",
"Move [p]@37 -> @38",
"Update [c]@67 -> [circle]@38",
"Delete [case Point p: return 0;]@26",
"Delete [case Point p:]@26",
"Delete [return 0;]@40",
"Delete [c]@67");
"Delete [p]@37",
"Delete [return 0;]@40");
}
#endregion
......@@ -8423,12 +8420,11 @@ public void CasePattern_UpdateDelete()
edits.VerifyEdits(
"Update [case Circle c: A(c); break;]@55 -> [case Circle c1: A(c1); break;]@26",
"Update [A(c);]@70 -> [A(c1);]@42",
"Update [p]@37 -> [c1]@38",
"Move [p]@37 -> @38",
"Update [c]@67 -> [c1]@38",
"Delete [case Point p: return 0;]@26",
"Delete [case Point p:]@26",
"Delete [return 0;]@40",
"Delete [c]@67");
"Delete [p]@37",
"Delete [return 0;]@40");
}
[Fact]
......
......@@ -2316,66 +2316,6 @@ public Base(bool val = false)
}");
}
[WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task TestGenerateFromDerivedClass()
{
await TestInRegularAndScriptAsync(
@"class Base
{
public Base(string value)
{
}
}
class [||]Derived : Base
{
}",
@"class Base
{
public Base(string value)
{
}
}
class Derived : Base
{
public Derived(string value) : base(value)
{
}
}");
}
[WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task TestGenerateFromDerivedClass2()
{
await TestInRegularAndScriptAsync(
@"class Base
{
public Base(int a, string value = null)
{
}
}
class [||]Derived : Base
{
}",
@"class Base
{
public Base(int a, string value = null)
{
}
}
class Derived : Base
{
public Derived(int a, string value = null) : base(a, value)
{
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task TestGenerateWithIncorrectConstructorArguments_Crash()
{
......
......@@ -2,11 +2,12 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.GenerateDefaultConstructors;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.GenerateDefaultConstructors
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateDefaultConstructors
{
public class GenerateDefaultConstructorsTests : AbstractCSharpCodeActionTest
{
......@@ -590,7 +591,7 @@ protected Program(SerializationInfo info, StreamingContext context) : base(info,
{
}
}",
index: 3,
index: 4,
ignoreTrivia: false);
}
......@@ -728,10 +729,6 @@ public Program()
{
}
public Program()
{
}
public Program(string message) : base(message)
{
}
......@@ -806,6 +803,66 @@ class B
public B((int a, string b) x)
{
}
}");
}
[WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task TestGenerateFromDerivedClass()
{
await TestInRegularAndScriptAsync(
@"class Base
{
public Base(string value)
{
}
}
class [||]Derived : Base
{
}",
@"class Base
{
public Base(string value)
{
}
}
class Derived : Base
{
public Derived(string value) : base(value)
{
}
}");
}
[WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task TestGenerateFromDerivedClass2()
{
await TestInRegularAndScriptAsync(
@"class Base
{
public Base(int a, string value = null)
{
}
}
class [||]Derived : Base
{
}",
@"class Base
{
public Base(int a, string value = null)
{
}
}
class Derived : Base
{
public Derived(int a, string value = null) : base(a, value)
{
}
}");
}
}
......
......@@ -159,7 +159,7 @@ public Program(int i)
this.i = i;
}
public Program(int i, string s, bool b = default(bool)) : this(i)
public Program(int i, string s, bool b = false) : this(i)
{
this.s = s;
this.b = b;
......
......@@ -47,6 +47,8 @@ internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProvider
SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithNoneEnforcement),
SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, CSharpCodeStyleOptions.NeverWithNoneEnforcement));
private static readonly ParseOptions CSharp7_1 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1);
internal async Task TestWithAllCodeStyleOptionsOffAsync(
string initialMarkup, string expectedMarkup,
int index = 0, bool ignoreTrivia = true,
......@@ -6789,5 +6791,37 @@ class Class : IInterface
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
public async Task TestOptionalParameterWithDefaultLiteral()
{
await TestWithAllCodeStyleOptionsOffAsync(
@"
using System.Threading;
interface IInterface
{
void Method1(CancellationToken cancellationToken = default(CancellationToken));
}
class Class : [|IInterface|]
{
}",
@"
using System.Threading;
interface IInterface
{
void Method1(CancellationToken cancellationToken = default(CancellationToken));
}
class Class : IInterface
{
public void Method1(CancellationToken cancellationToken = default)
{
throw new System.NotImplementedException();
}
}", parseOptions: CSharp7_1);
}
}
}
\ No newline at end of file
// 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.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseDefaultLiteral
{
public class UseDefaultLiteralTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpUseDefaultLiteralDiagnosticAnalyzer(), new CSharpUseDefaultLiteralCodeFixProvider());
private static readonly CSharpParseOptions s_parseOptions =
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_1);
private static readonly TestParameters s_testParameters =
new TestParameters(parseOptions: s_parseOptions);
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestNotInCSharp7()
{
await TestMissingAsync(
@"
class C
{
void Foo(string s = [||]default(string))
{
}
}", parameters: new TestParameters(
parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInParameterList()
{
await TestAsync(
@"
class C
{
void Foo(string s = [||]default(string))
{
}
}",
@"
class C
{
void Foo(string s = default)
{
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInIfCheck()
{
await TestAsync(
@"
class C
{
void Foo(string s)
{
if (s == [||]default(string)) { }
}
}",
@"
class C
{
void Foo(string s)
{
if (s == default) { }
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInReturnStatement()
{
await TestAsync(
@"
class C
{
string Foo()
{
return [||]default(string);
}
}",
@"
class C
{
string Foo()
{
return default;
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInReturnStatement2()
{
await TestMissingAsync(
@"
class C
{
string Foo()
{
return [||]default(int);
}
}", parameters: s_testParameters);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInLambda1()
{
await TestAsync(
@"
using System;
class C
{
void Foo()
{
Func<string> f = () => [||]default(string);
}
}",
@"
using System;
class C
{
void Foo()
{
Func<string> f = () => [||]default;
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInLambda2()
{
await TestMissingAsync(
@"
using System;
class C
{
void Foo()
{
Func<string> f = () => [||]default(int);
}
}", parameters: s_testParameters);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInLocalInitializer()
{
await TestAsync(
@"
class C
{
void Foo()
{
string s = [||]default(string);
}
}",
@"
class C
{
void Foo()
{
string s = default;
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInLocalInitializer2()
{
await TestMissingAsync(
@"
class C
{
void Foo()
{
string s = [||]default(int);
}
}", parameters: s_testParameters);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestNotForVar()
{
await TestMissingAsync(
@"
class C
{
void Foo()
{
var s = [||]default(string);
}
}", parameters: s_testParameters);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestInInvocationExpression()
{
await TestAsync(
@"
class C
{
void Foo()
{
Bar([||]default(string));
}
void Bar(string s) { }
}",
@"
class C
{
void Foo()
{
Bar(default);
}
void Bar(string s) { }
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestNotWithMultipleOverloads()
{
await TestMissingAsync(
@"
class C
{
void Foo()
{
Bar([||]default(string));
}
void Bar(string s) { }
void Bar(int i);
}", parameters: s_testParameters);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestLeftSideOfTernary()
{
await TestAsync(
@"
class C
{
void Foo(bool b)
{
var v = b ? [||]default(string) : default(string);
}
}",
@"
class C
{
void Foo(bool b)
{
var v = b ? default : default(string);
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestRightSideOfTernary()
{
await TestAsync(
@"
class C
{
void Foo(bool b)
{
var v = b ? default(string) : [||]default(string);
}
}",
@"
class C
{
void Foo(bool b)
{
var v = b ? default(string) : default;
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestFixAll1()
{
await TestAsync(
@"
class C
{
void Foo()
{
string s1 = {|FixAllInDocument:default|}(string);
string s2 = default(string);
}
}",
@"
class C
{
void Foo()
{
string s1 = default;
string s2 = default;
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestFixAll2()
{
await TestAsync(
@"
class C
{
void Foo(bool b)
{
string s1 = b ? {|FixAllInDocument:default|}(string) : default(string);
}
}",
@"
class C
{
void Foo(bool b)
{
string s1 = b ? default : default(string);
}
}", parseOptions: s_parseOptions);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseDefaultLiteral)]
public async Task TestFixAll3()
{
await TestAsync(
@"
class C
{
void Foo()
{
string s1 = {|FixAllInDocument:default|}(string);
string s2 = default(int);
}
}",
@"
class C
{
void Foo()
{
string s1 = default;
string s2 = default(int);
}
}", parseOptions: s_parseOptions);
}
}
}
\ No newline at end of file
......@@ -166,6 +166,7 @@
<Compile Include="Implementation\Intellisense\Completion\CompletionFilterReason.cs" />
<Compile Include="Implementation\Intellisense\Completion\FilterResult.cs" />
<Compile Include="Implementation\Structure\BlockTagState.cs" />
<Compile Include="Implementation\Suggestions\ISuggestedActionCallback.cs" />
<Compile Include="Implementation\Suggestions\SuggestedActionSetComparer.cs" />
<Compile Include="Implementation\Suggestions\SuggestedActionsSource.cs" />
<Compile Include="ReferenceHighlighting\NagivateToHighlightReferenceCommandHandler.cs" />
......
......@@ -19,9 +19,12 @@ internal sealed class MetadataAsSourceGeneratedFileInfo
public readonly string TemporaryFilePath;
private readonly ParseOptions _parseOptions;
public MetadataAsSourceGeneratedFileInfo(string rootPath, Project sourceProject, INamedTypeSymbol topLevelNamedType)
{
this.SourceProjectId = sourceProject.Id;
_parseOptions = sourceProject.ParseOptions;
this.Workspace = sourceProject.Solution.Workspace;
this.LanguageName = sourceProject.Language;
this.References = sourceProject.MetadataReferences.ToImmutableArray();
......@@ -79,10 +82,11 @@ public MetadataAsSourceGeneratedFileInfo(string rootPath, Project sourceProject,
assemblyName: AssemblyIdentity.Name,
language: LanguageName,
compilationOptions: compilationOptions,
parseOptions: _parseOptions,
documents: new[] { assemblyInfoDocument, generatedDocument },
metadataReferences: References);
return Tuple.Create(projectInfo, generatedDocumentId);
}
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
internal interface ISuggestedActionCallback
{
void OnSuggestedActionExecuted(SuggestedAction action);
}
}
......@@ -90,21 +90,25 @@ protected Task<ImmutableArray<CodeActionOperation>> GetPreviewOperationsAsync(Ca
public void Invoke(CancellationToken cancellationToken)
{
// While we're not technically doing anything async here, we need to let the
// While we're not technically doing anything async here, we need to let the
// integration test harness know that it should not proceed until all this
// work is done. Otherwise it might ask to do some work before we finish.
// That can happen because although we're on the UI thread, we may do things
// that end up causing VS to pump the messages that the test harness enqueues
// to the UI thread as well.
// to the UI thread as well.
using (SourceProvider.OperationListener.BeginAsyncOperation($"{nameof(SuggestedAction)}.{nameof(Invoke)}"))
{
// WaitIndicator cannot be used with async/await. Even though we call async methods
// WaitIndicator cannot be used with async/await. Even though we call async methods
// later in this call chain, do not await them.
SourceProvider.WaitIndicator.Wait(CodeAction.Title, CodeAction.Message, allowCancel: true, showProgress: true, action: waitContext =>
{
using (var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, waitContext.CancellationToken))
{
InnerInvoke(waitContext.ProgressTracker, linkedSource.Token);
foreach (var actionCallback in SourceProvider.ActionCallbacks)
{
actionCallback.Value.OnSuggestedActionExecuted(this);
}
}
});
}
......
......@@ -39,6 +39,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
public readonly ICodeActionEditHandlerService EditHandler;
public readonly IAsynchronousOperationListener OperationListener;
public readonly IWaitIndicator WaitIndicator;
public readonly ImmutableArray<Lazy<ISuggestedActionCallback>> ActionCallbacks;
public readonly ImmutableArray<Lazy<IImageMonikerService, OrderableMetadata>> ImageMonikerServices;
......@@ -50,11 +51,13 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
ICodeActionEditHandlerService editHandler,
IWaitIndicator waitIndicator,
[ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners,
[ImportMany] IEnumerable<Lazy<IImageMonikerService, OrderableMetadata>> imageMonikerServices)
[ImportMany] IEnumerable<Lazy<IImageMonikerService, OrderableMetadata>> imageMonikerServices,
[ImportMany] IEnumerable<Lazy<ISuggestedActionCallback>> actionCallbacks)
{
_codeRefactoringService = codeRefactoringService;
_diagnosticService = diagnosticService;
_codeFixService = codeFixService;
ActionCallbacks = actionCallbacks.ToImmutableArray();
EditHandler = editHandler;
WaitIndicator = waitIndicator;
OperationListener = new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.LightBulb);
......
......@@ -597,7 +597,7 @@ public async Task AddDefaultParameterWithNonDefaultValueToMethod()
public async Task AddDefaultParameterWithDefaultValueToMethod()
{
var input = "class C { public void [|M|]() { } }";
var expected = "class C { public void M(double number = default(double)) { } }";
var expected = "class C { public void M(double number = 0) { } }";
await TestAddParametersAsync(input, expected,
Parameters(Parameter(typeof(double), "number", true)));
}
......
......@@ -27,7 +27,12 @@ internal class TestContext : IDisposable
private readonly IMetadataAsSourceFileService _metadataAsSourceService;
private readonly ITextBufferFactoryService _textBufferFactoryService;
public static TestContext Create(string projectLanguage = null, IEnumerable<string> metadataSources = null, bool includeXmlDocComments = false, string sourceWithSymbolReference = null)
public static TestContext Create(
string projectLanguage = null,
IEnumerable<string> metadataSources = null,
bool includeXmlDocComments = false,
string sourceWithSymbolReference = null,
string languageVersion = null)
{
projectLanguage = projectLanguage ?? LanguageNames.CSharp;
metadataSources = metadataSources ?? SpecializedCollections.EmptyEnumerable<string>();
......@@ -35,7 +40,9 @@ public static TestContext Create(string projectLanguage = null, IEnumerable<stri
? new[] { AbstractMetadataAsSourceTests.DefaultMetadataSource }
: metadataSources;
var workspace = CreateWorkspace(projectLanguage, metadataSources, includeXmlDocComments, sourceWithSymbolReference);
var workspace = CreateWorkspace(
projectLanguage, metadataSources, includeXmlDocComments,
sourceWithSymbolReference, languageVersion);
return new TestContext(workspace);
}
......@@ -214,11 +221,21 @@ private static string DeduceLanguageString(string input)
? LanguageNames.VisualBasic : LanguageNames.CSharp;
}
private static TestWorkspace CreateWorkspace(string projectLanguage, IEnumerable<string> metadataSources, bool includeXmlDocComments, string sourceWithSymbolReference)
private static TestWorkspace CreateWorkspace(
string projectLanguage, IEnumerable<string> metadataSources,
bool includeXmlDocComments, string sourceWithSymbolReference,
string languageVersion)
{
var xmlString = string.Concat(@"
<Workspace>
<Project Language=""", projectLanguage, @""" CommonReferences=""true"">");
<Project Language=""", projectLanguage, @""" CommonReferences=""true""");
if (languageVersion != null)
{
xmlString += $@" LanguageVersion=""{languageVersion}""";
}
xmlString += ">";
metadataSources = metadataSources ?? new[] { AbstractMetadataAsSourceTests.DefaultMetadataSource };
......
......@@ -14,9 +14,11 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.MetadataAsSource
{
public abstract partial class AbstractMetadataAsSourceTests
{
internal static async Task GenerateAndVerifySourceAsync(string metadataSource, string symbolName, string projectLanguage, string expected, bool ignoreTrivia = true, bool includeXmlDocComments = false)
internal static async Task GenerateAndVerifySourceAsync(
string metadataSource, string symbolName, string projectLanguage, string expected,
bool ignoreTrivia = true, bool includeXmlDocComments = false, string languageVersion = null)
{
using (var context = TestContext.Create(projectLanguage, SpecializedCollections.SingletonEnumerable(metadataSource), includeXmlDocComments))
using (var context = TestContext.Create(projectLanguage, SpecializedCollections.SingletonEnumerable(metadataSource), includeXmlDocComments, languageVersion: languageVersion))
{
await context.GenerateAndVerifySourceAsync(symbolName, expected, ignoreTrivia);
}
......
......@@ -1360,5 +1360,30 @@ public interface [|IComImport|]
int Prop {{ get; }}
}}");
}
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestOptionalParameterWithDefaultLiteral()
{
var metadataSource = @"
using System.Threading;
public class C {
public void M(CancellationToken cancellationToken = default(CancellationToken)) { }
}";
var symbolName = "C";
await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, $@"
#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// {CodeAnalysisResources.InMemoryAssembly}
#endregion
using System.Threading;
public class [|C|]
{{
public C();
public void M(CancellationToken cancellationToken = default);
}}", languageVersion: "CSharp7_1");
}
}
}
\ No newline at end of file
......@@ -3311,6 +3311,31 @@ class C
New TextChange(New TextSpan(0, _caretPosition), newText))
Return Task.FromResult(change)
End Function
<WorkItem(15348, "https://github.com/dotnet/roslyn/issues/15348")>
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestAfterCasePatternSwitchLabel() As Task
Using state = TestState.CreateCSharpTestState(
<Document>
class C
{
void M()
{
object o = 1;
switch(o)
{
case int i:
$$
break;
}
}
}
</Document>)
state.SendTypeChars("this")
Await state.AssertSelectedCompletionItem(displayText:="this", isHardSelected:=True)
End Using
End Function
End Class
End Class
End Namespace
\ No newline at end of file
......@@ -96,6 +96,7 @@ public static class Features
public const string CodeActionsUseAutoProperty = "CodeActions.UseAutoProperty";
public const string CodeActionsUseCoalesceExpression = "CodeActions.UseCoalesceExpression";
public const string CodeActionsUseCollectionInitializer = "CodeActions.UseCollectionInitializer";
public const string CodeActionsUseDefaultLiteral = "CodeActions.UseDefaultLiteral";
public const string CodeActionsUseExpressionBody = "CodeActions.UseExpressionBody";
public const string CodeActionsUseImplicitType = "CodeActions.UseImplicitType";
public const string CodeActionsUseExplicitType = "CodeActions.UseExplicitType";
......
......@@ -227,7 +227,7 @@
<Compile Include="ConvertToInterpolatedString\ConvertPlaceholderToInterpolatedStringTests.vb" />
<Compile Include="CodeActions\EncapsulateField\EncapsulateFieldTests.vb" />
<Compile Include="CodeActions\ExtractMethod\ExtractMethodTests.vb" />
<Compile Include="CodeActions\GenerateDefaultConstructors\GenerateDefaultConstructorsTests.vb" />
<Compile Include="GenerateDefaultConstructors\GenerateDefaultConstructorsTests.vb" />
<Compile Include="AddConstructorParametersFromMembers\AddConstructorParametersFromMembersTests.vb" />
<Compile Include="GenerateConstructorFromMembers\GenerateConstructorFromMembersTests.vb" />
<Compile Include="GenerateEqualsAndGetHashCodeFromMembers\GenerateEqualsAndGetHashCodeFromMembersTests.vb" />
......@@ -276,7 +276,7 @@
<Compile Include="Diagnostics\ExitContinue\ExitContinueCodeActionTests.vb" />
<Compile Include="Diagnostics\FixIncorrectFunctionReturnType\FixIncorrectFunctionReturnTypeTests.vb" />
<Compile Include="Diagnostics\FullyQualify\FullyQualifyTests.vb" />
<Compile Include="Diagnostics\GenerateConstructor\GenerateConstructorTests.vb" />
<Compile Include="GenerateConstructor\GenerateConstructorTests.vb" />
<Compile Include="Diagnostics\GenerateEndConstruct\GenerateEndConstructTests.vb" />
<Compile Include="Diagnostics\GenerateEnumMember\GenerateEnumMemberTests.vb" />
<Compile Include="Diagnostics\GenerateEvent\GenerateEventTests.vb" />
......
......@@ -2,10 +2,11 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.VisualBasic.Diagnostics
Imports Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.GenerateConstructor
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateConstructor
Public Class GenerateConstructorTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest
......@@ -1528,98 +1529,6 @@ End Class")
End Function
End Class
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType1() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As String)
End Sub
End Class
Public Class [||]Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As String)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New(a As String)
MyBase.New(a)
End Sub
End Class")
End Function
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType2() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class [||]Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New(a As Integer, Optional b As String = Nothing)
MyBase.New(a, b)
End Sub
End Class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class [|;;|]Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class ;;Derived
Inherits Base
Public Sub New(a As Integer, Optional b As String = Nothing)
MyBase.New(a, b)
End Sub
End Class")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateConstructorNotOfferedForDuplicate() As Task
Await TestMissingInRegularAndScriptAsync(
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings
Imports Microsoft.CodeAnalysis.GenerateDefaultConstructors
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.GenerateDefaultConstructors
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultConstructors
Public Class GenerateDefaultConstructorsTests
Inherits AbstractVisualBasicCodeActionTest
......@@ -27,8 +28,7 @@ Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits Exception
Public Sub New(message As String)
MyBase.New(message)
Public Sub New()
End Sub
Sub Main(args As String())
End Sub
......@@ -51,8 +51,8 @@ Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits Exception
Public Sub New(message As String, innerException As Exception)
MyBase.New(message, innerException)
Public Sub New(message As String)
MyBase.New(message)
End Sub
Sub Main(args As String())
End Sub
......@@ -74,20 +74,50 @@ End Class",
"Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits Exception
Public Sub New(message As String, innerException As Exception)
MyBase.New(message, innerException)
End Sub
Sub Main(args As String())
End Sub
End Class",
index:=2)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)>
Public Async Function TestException3() As Task
Await TestInRegularAndScriptAsync(
"Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits [||]Exception
Sub Main(args As String())
End Sub
End Class",
"Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Class Program
Inherits Exception
Protected Sub New(info As SerializationInfo, context As StreamingContext)
MyBase.New(info, context)
End Sub
Sub Main(args As String())
End Sub
End Class",
index:=2)
index:=3)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)>
Public Async Function TestException3() As Task
Public Async Function TestException4() As Task
Await TestInRegularAndScriptAsync(
"Imports System
Imports System.Collections.Generic
......@@ -101,33 +131,47 @@ End Class",
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Class Program
Inherits Exception
Public Sub New()
End Sub
Public Sub New(message As String)
MyBase.New(message)
End Sub
Public Sub New(message As String, innerException As Exception)
MyBase.New(message, innerException)
End Sub
Protected Sub New(info As SerializationInfo, context As StreamingContext)
MyBase.New(info, context)
End Sub
Sub Main(args As String())
End Sub
End Class",
index:=3)
index:=4)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)>
<WorkItem(539676, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539676")>
Public Async Function TestNotOfferedOnResolvedBaseClassName() As Task
Await TestMissingInRegularAndScriptAsync(
Await TestInRegularAndScript1Async(
"Class Base
End Class
Class Derived
Inherits B[||]ase
End Class",
"Class Base
End Class
Class Derived
Inherits Base
Public Sub New()
End Sub
End Class")
End Function
......@@ -252,8 +296,7 @@ Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits Exception
Public Sub New()
End Sub
Public Sub New()
End Sub
Public Sub New(message As String)
......@@ -288,8 +331,7 @@ Imports System.Collections.Generic
Imports System.Linq
Class Program
Inherits Exception
Public Sub New(message As String)
MyBase.New(message)
Public Sub New()
End Sub
Sub Main(args As String())
End Sub
......@@ -484,5 +526,97 @@ End Class
index:=2,
ignoreTrivia:=False)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public [||]Class ;;Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class ;;Derived
Inherits Base
Public Sub New(a As Integer, Optional b As String = Nothing)
MyBase.New(a, b)
End Sub
End Class")
End Function
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType1() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As String)
End Sub
End Class
Public Class [||]Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As String)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New(a As String)
MyBase.New(a)
End Sub
End Class")
End Function
<WorkItem(6541, "https://github.com/dotnet/Roslyn/issues/6541")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)>
Public Async Function TestGenerateInDerivedType2() As Task
Await TestInRegularAndScriptAsync(
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class [||]Derived
Inherits Base
End Class",
"
Public Class Base
Public Sub New(a As Integer, Optional b As String = Nothing)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New(a As Integer, Optional b As String = Nothing)
MyBase.New(a, b)
End Sub
End Class")
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -96,6 +96,7 @@
<Compile Include="UpgradeProject\CSharpUpgradeProjectCodeFixProvider.cs" />
<Compile Include="UseCoalesceExpression\CSharpUseCoalesceExpressionForNullableDiagnosticAnalyzer.cs" />
<Compile Include="UseCoalesceExpression\CSharpUseCoalesceExpressionDiagnosticAnalyzer.cs" />
<Compile Include="UseDefaultLiteral\CSharpUseDefaultLiteralCodeFixProvider.cs" />
<Compile Include="UseExpressionBody\Helpers\UseExpressionBodyHelper.cs" />
<Compile Include="UseExpressionBody\UseExpressionBodyCodeRefactoringProvider.cs" />
<Compile Include="UseExpressionBody\UseExpressionBodyDiagnosticAnalyzer.cs" />
......@@ -110,6 +111,7 @@
<Compile Include="AddBraces\CSharpAddBracesDiagnosticAnalyzer.cs" />
<Compile Include="UseCollectionInitializer\CSharpUseCollectionInitializerCodeFixProvider.cs" />
<Compile Include="UseCollectionInitializer\CSharpUseCollectionInitializerDiagnosticAnalyzer.cs" />
<Compile Include="UseDefaultLiteral\CSharpUseDefaultLiteralDiagnosticAnalyzer.cs" />
<Compile Include="UseNullPropagation\CSharpUseNullPropagationCodeFixProvider.cs" />
<Compile Include="UseNullPropagation\CSharpUseNullPropagationDiagnosticAnalyzer.cs" />
<Compile Include="UseObjectInitializer\UseInitializerHelpers.cs" />
......
......@@ -681,6 +681,10 @@ protected override bool TryComputeWeightedDistance(SyntaxNode leftNode, SyntaxNo
distance = (leftNode.RawKind == rightNode.RawKind) ? 0.0 : 0.1;
return true;
case SyntaxKind.SingleVariableDesignation:
distance = ComputeWeightedDistance((SingleVariableDesignationSyntax)leftNode, (SingleVariableDesignationSyntax)rightNode);
return true;
default:
distance = 0;
return false;
......@@ -837,6 +841,25 @@ private bool TryComputeWeightedDistance(BlockSyntax leftBlock, BlockSyntax right
}
}
private double ComputeWeightedDistance(SingleVariableDesignationSyntax leftNode, SingleVariableDesignationSyntax rightNode)
{
double distance = ComputeDistance(leftNode, rightNode);
double parentDistance;
if (leftNode.Parent != null &&
rightNode.Parent != null &&
GetLabel(leftNode.Parent) == GetLabel(rightNode.Parent))
{
parentDistance = ComputeDistance(leftNode.Parent, rightNode.Parent);
}
else
{
parentDistance = 1;
}
return 0.5 * parentDistance + 0.5 * distance;
}
private static double ComputeWeightedBlockDistance(BlockSyntax leftBlock, BlockSyntax rightBlock)
{
if (TryComputeLocalsDistance(leftBlock, rightBlock, out var distance))
......
......@@ -21,19 +21,10 @@ internal class CSharpGenerateConstructorService : AbstractGenerateConstructorSer
private static readonly SyntaxAnnotation s_annotation = new SyntaxAnnotation();
protected override bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken)
{
return node is SimpleNameSyntax;
}
=> node is SimpleNameSyntax;
protected override bool IsConstructorInitializerGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken)
{
return node is ConstructorInitializerSyntax;
}
protected override bool IsClassDeclarationGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken)
{
return node is ClassDeclarationSyntax;
}
=> node is ConstructorInitializerSyntax;
protected override bool TryInitializeConstructorInitializerGeneration(
SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken,
......@@ -60,35 +51,6 @@ protected override bool IsClassDeclarationGeneration(SemanticDocument document,
return false;
}
protected override bool TryInitializeClassDeclarationGenerationState(
SemanticDocument document,
SyntaxNode node,
CancellationToken cancellationToken,
out SyntaxToken token,
out IMethodSymbol delegatedConstructor,
out INamedTypeSymbol typeToGenerateIn)
{
token = default(SyntaxToken);
typeToGenerateIn = null;
delegatedConstructor = null;
var semanticModel = document.SemanticModel;
var classDeclaration = (ClassDeclarationSyntax)node;
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration, cancellationToken);
var baseType = classSymbol.BaseType;
var constructor = baseType.Constructors.FirstOrDefault(c => IsSymbolAccessible(c, document));
if (constructor == null)
{
return false;
}
typeToGenerateIn = classSymbol;
delegatedConstructor = constructor;
token = classDeclaration.Identifier;
return true;
}
protected override bool TryInitializeSimpleNameGenerationState(
SemanticDocument document,
SyntaxNode 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.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
......@@ -12,7 +11,6 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.GenerateConstructor
{
......@@ -31,6 +29,18 @@ internal static class GenerateConstructorDiagnosticIds
ImmutableArray.Create(CS1729);
}
/// <summary>
/// This <see cref="CodeFixProvider"/> gives users a way to generate constructors for an existing
/// type when a user tries to 'new' up an instance of that type with a set of parameter that does
/// not match any existing constructor. i.e. it is the equivalent of 'Generate-Method' but for
/// constructors. Parameters for the constructor will be picked in a manner similar to Generate-
/// Method. However, this type will also attempt to hook up those parameters to existing fields
/// and properties, or pass them to a this/base constructor if available.
///
/// Importantly, this type is not responsible for generating constructors for a type based on
/// the user selecting some fields/properties of that type. Nor is it responsible for generating
/// derived class constructors for all unmatched base class constructors in a type hierarchy.
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateConstructor), Shared]
[ExtensionOrder(After = PredefinedCodeFixProviderNames.FullyQualify)]
internal class GenerateConstructorCodeFixProvider : AbstractGenerateMemberCodeFixProvider
......@@ -46,43 +56,22 @@ internal class GenerateConstructorCodeFixProvider : AbstractGenerateMemberCodeFi
protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic)
{
if (node is ObjectCreationExpressionSyntax ||
node is ConstructorInitializerSyntax ||
node is AttributeSyntax)
{
return true;
}
return diagnostic.Id == GenerateConstructorDiagnosticIds.CS7036 &&
node is ClassDeclarationSyntax &&
IsInClassDeclarationHeader((ClassDeclarationSyntax)node, token);
}
private bool IsInClassDeclarationHeader(ClassDeclarationSyntax node, SyntaxToken token)
{
var start = node.SpanStart;
var end = node.BaseList != null
? node.BaseList.Span.End
: node.Identifier.Span.End;
return TextSpan.FromBounds(start, end).Contains(token.Span);
return node is ObjectCreationExpressionSyntax ||
node is ConstructorInitializerSyntax ||
node is AttributeSyntax;
}
protected override SyntaxNode GetTargetNode(SyntaxNode node)
{
var objectCreationNode = node as ObjectCreationExpressionSyntax;
if (objectCreationNode != null)
{
return objectCreationNode.Type.GetRightmostName();
}
var attributeNode = node as AttributeSyntax;
if (attributeNode != null)
switch (node)
{
return attributeNode.Name;
case ObjectCreationExpressionSyntax objectCreationNode:
return objectCreationNode.Type.GetRightmostName();
case AttributeSyntax attributeNode:
return attributeNode.Name;
}
return node;
}
}
}
}
\ No newline at end of file
......@@ -4,8 +4,10 @@
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.GenerateFromMembers;
using Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
......@@ -16,33 +18,41 @@ internal class CSharpGenerateDefaultConstructorsService : AbstractGenerateDefaul
{
protected override bool TryInitializeState(
SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken,
out SyntaxNode baseTypeNode, out INamedTypeSymbol classType)
out INamedTypeSymbol classOrStructType)
{
if (!cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
// Offer the feature if we're on the header for the class/struct, or if we're on the
// first base-type of a class.
var syntaxFacts = document.Document.GetLanguageService<ISyntaxFactsService>();
if (syntaxFacts.IsOnTypeHeader(document.Root, textSpan.Start))
{
classOrStructType = AbstractGenerateFromMembersCodeRefactoringProvider.GetEnclosingNamedType(
document.SemanticModel, document.Root, textSpan.Start, cancellationToken);
return classOrStructType != null;
}
var syntaxTree = document.SyntaxTree;
var node = document.Root.FindToken(textSpan.Start).GetAncestor<TypeSyntax>();
if (node != null)
{
var syntaxTree = document.SyntaxTree;
var node = document.Root.FindToken(textSpan.Start).GetAncestor<TypeSyntax>();
if (node != null)
if (node.Parent is BaseTypeSyntax && node.Parent.IsParentKind(SyntaxKind.BaseList))
{
if (node.Parent is BaseTypeSyntax && node.Parent.IsParentKind(SyntaxKind.BaseList))
var baseList = (BaseListSyntax)node.Parent.Parent;
if (baseList.Types.Count > 0 &&
baseList.Types[0].Type == node &&
baseList.IsParentKind(SyntaxKind.ClassDeclaration))
{
var baseList = (BaseListSyntax)node.Parent.Parent;
if (baseList.Types.Count > 0 &&
baseList.Types[0].Type == node &&
baseList.IsParentKind(SyntaxKind.ClassDeclaration))
{
var semanticModel = document.SemanticModel;
classType = semanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken) as INamedTypeSymbol;
baseTypeNode = node;
return classType != null;
}
var semanticModel = document.SemanticModel;
classOrStructType = semanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken) as INamedTypeSymbol;
return classOrStructType != null;
}
}
}
baseTypeNode = null;
classType = null;
classOrStructType = null;
return false;
}
}
}
}
\ No newline at end of file
......@@ -73,7 +73,8 @@ protected override ImmutableArray<AbstractReducer> GetReducers()
=> ImmutableArray.Create<AbstractReducer>(
new CSharpNameReducer(),
new CSharpEscapingReducer(),
new CSharpParenthesesReducer());
new CSharpParenthesesReducer(),
new CSharpDefaultExpressionReducer());
private class FormattingRule : AbstractFormattingRule
{
......
// 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 System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral
{
[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
internal partial class CSharpUseDefaultLiteralCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; }
= ImmutableArray.Create(IDEDiagnosticIds.UseDefaultLiteralDiagnosticId);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return SpecializedTasks.EmptyTask;
}
protected override async Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor, CancellationToken cancellationToken)
{
// Fix-All for this feature is somewhat complicated. Each time we fix one case, it
// may make the next case unfixable. For example:
//
// 'var v = x ? default(string) : default(string)'.
//
// Here, we can replace either of the default expressions, but not both. So we have
// to replace one at a time, and only actually replace if it's still safe to do so.
var parseOptions = (CSharpParseOptions)document.Project.ParseOptions;
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var workspace = document.Project.Solution.Workspace;
var originalRoot = editor.OriginalRoot;
var originalNodes = diagnostics.SelectAsArray(
d => (DefaultExpressionSyntax)originalRoot.FindNode(d.Location.SourceSpan, getInnermostNodeForTie: true));
// We're going to be continually editing this tree. Track all the nodes we
// care about so we can find them across each edit.
document = document.WithSyntaxRoot(originalRoot.TrackNodes(originalNodes));
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
foreach (var originalDefaultExpression in originalNodes)
{
var defaultExpression = currentRoot.GetCurrentNode(originalDefaultExpression);
if (defaultExpression.CanReplaceWithDefaultLiteral(parseOptions, options, semanticModel, cancellationToken))
{
var replacement = SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression)
.WithTriviaFrom(defaultExpression);
document = document.WithSyntaxRoot(currentRoot.ReplaceNode(defaultExpression, replacement));
semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
}
}
editor.ReplaceNode(originalRoot, currentRoot);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(FeaturesResources.Simplify_default_expression, createChangedDocument)
{
}
}
}
}
\ No newline at end of file
// 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.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.UseDefaultLiteral
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpUseDefaultLiteralDiagnosticAnalyzer : AbstractCodeStyleDiagnosticAnalyzer
{
public CSharpUseDefaultLiteralDiagnosticAnalyzer()
: base(IDEDiagnosticIds.UseDefaultLiteralDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Simplify_default_expression), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.default_expression_can_be_simplified), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
=> DiagnosticAnalyzerCategory.SemanticSpanAnalysis;
public override bool OpenFileOnly(Workspace workspace)
=> false;
protected override void InitializeWorker(AnalysisContext context)
=> context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.DefaultExpression);
private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
var cancellationToken = context.CancellationToken;
var syntaxTree = context.Node.SyntaxTree;
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
}
var parseOptions = (CSharpParseOptions)syntaxTree.Options;
var defaultExpression = (DefaultExpressionSyntax)context.Node;
if (!defaultExpression.CanReplaceWithDefaultLiteral(parseOptions, optionSet, context.SemanticModel, cancellationToken))
{
return;
}
var fadeSpan = TextSpan.FromBounds(defaultExpression.OpenParenToken.SpanStart, defaultExpression.CloseParenToken.Span.End);
// Create a normal diagnostic that covers the entire default expression.
context.ReportDiagnostic(
Diagnostic.Create(GetDescriptorWithSeverity(
optionSet.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression).Notification.Value),
defaultExpression.GetLocation()));
// Also fade out the part of the default expression from the open paren through
// the close paren.
context.ReportDiagnostic(
Diagnostic.Create(
UnnecessaryWithoutSuggestionDescriptor,
syntaxTree.GetLocation(fadeSpan)));
}
}
}
\ No newline at end of file
......@@ -44,6 +44,8 @@ internal static class IDEDiagnosticIds
public const string UseExplicitTupleNameDiagnosticId = "IDE0033";
public const string UseDefaultLiteralDiagnosticId = "IDE0034";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
......
......@@ -328,7 +328,7 @@
<Compile Include="CodeRefactorings\CodeRefactoringService.cs" />
<Compile Include="ConvertToInterpolatedString\AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs" />
<Compile Include="CodeRefactorings\ExtractMethod\AbstractExtractMethodCodeRefactoringProvider.cs" />
<Compile Include="CodeRefactorings\GenerateDefaultConstructors\GenerateDefaultConstructorsCodeRefactoringProvider.cs" />
<Compile Include="GenerateDefaultConstructors\GenerateDefaultConstructorsCodeRefactoringProvider.cs" />
<Compile Include="AddConstructorParametersFromMembers\AddConstructorParametersFromMembersCodeRefactoringProvider.cs" />
<Compile Include="GenerateConstructorFromMembers\GenerateConstructorFromMembersCodeRefactoringProvider.cs" />
<Compile Include="GenerateEqualsAndGetHashCodeFromMembers\GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs" />
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class FeaturesResources {
......@@ -863,6 +863,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;default&apos; expression can be simplified.
/// </summary>
internal static string default_expression_can_be_simplified {
get {
return ResourceManager.GetString("default_expression_can_be_simplified", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to delegate.
/// </summary>
......@@ -2664,6 +2673,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Simplify &apos;default&apos; expression.
/// </summary>
internal static string Simplify_default_expression {
get {
return ResourceManager.GetString("Simplify_default_expression", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Simplify Member Access.
/// </summary>
......
......@@ -1241,4 +1241,10 @@ This version used in: {2}</value>
<data name="Implement_0" xml:space="preserve">
<value>Implement {0}</value>
</data>
<data name="Simplify_default_expression" xml:space="preserve">
<value>Simplify 'default' expression</value>
</data>
<data name="default_expression_can_be_simplified" xml:space="preserve">
<value>'default' expression can be simplified</value>
</data>
</root>
\ No newline at end of file
......@@ -16,6 +16,18 @@
namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers
{
/// <summary>
/// This <see cref="CodeRefactoringProvider"/> is responsible for allowing a user to pick a
/// set of members from a class or struct, and then generate a constructor for that takes in
/// matching parameters and assigns them to those members. The members can be picked using
/// a actual selection in the editor, or they can be picked using a picker control that will
/// then display all the viable members and allow the user to pick which ones they want to
/// use.
///
/// Importantly, this type is not responsible for generating constructors when the user types
/// something like "new MyType(x, y, z)", nor is it responsible for generating constructors
/// in a derived type that delegate to a base type. Both of those are handled by other services.
/// </summary>
[ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic,
Name = PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers), Shared]
[ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.GenerateEqualsAndGetHashCodeFromMembers)]
......@@ -93,26 +105,10 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context)
// Find all the possible writable instance fields/properties. If there are any, then
// show a dialog to the user to select the ones they want. Otherwise, if there are none
// just offer to generate the no-param constructor if they don't already have one.
// don't offer to generate anything.
var viableMembers = containingType.GetMembers().WhereAsArray(IsWritableInstanceFieldOrProperty);
if (viableMembers.Length == 0)
{
var noParamConstructor = containingType.InstanceConstructors.FirstOrDefault(c => c.Parameters.Length == 0);
if (noParamConstructor == null ||
noParamConstructor.IsImplicitlyDeclared)
{
// Offer to just make the no-param-constructor directly.
var state = State.TryGenerate(this, document, textSpan, containingType,
ImmutableArray<ISymbol>.Empty, cancellationToken);
if (state != null)
{
context.RegisterRefactoring(
new FieldDelegatingCodeAction(this, document, state, addNullChecks: false));
}
}
// already had an explicit, no-param constructor. No need to offer anything.
return;
}
......
......@@ -2,11 +2,24 @@
using System.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CodeRefactorings.GenerateDefaultConstructors
namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors
{
/// <summary>
/// This <see cref="CodeRefactoringProvider"/> gives users a way to generate constructors for
/// a derived type that delegate to a base type. For all accessibly constructors in the base
/// type, the user will be offered to create a constructor in the derived type with the same
/// signature if they don't already have one. This way, a user can override a type and easily
/// create all the forwarding constructors.
///
/// Importantly, this type is not responsible for generating constructors when the user types
/// something like "new MyType(x, y, z)", nor is it responsible for generating constructors
/// for a type based on the fields/properties of that type. Both of those are handled by other
/// services.
/// </summary>
[ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic,
Name = PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors), Shared]
internal class GenerateDefaultConstructorsCodeRefactoringProvider : CodeRefactoringProvider
......
......@@ -74,13 +74,6 @@ private State()
return false;
}
}
else if (service.IsClassDeclarationGeneration(document, node, cancellationToken))
{
if (!await TryInitializeClassDeclarationGenerationAsync(service, document, node, cancellationToken).ConfigureAwait(false))
{
return false;
}
}
else
{
return false;
......@@ -196,25 +189,6 @@ private ITypeSymbol FixType(ITypeSymbol typeSymbol, SemanticModel semanticModel,
return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> TryInitializeClassDeclarationGenerationAsync(
TService service,
SemanticDocument document,
SyntaxNode simpleName,
CancellationToken cancellationToken)
{
if (service.TryInitializeClassDeclarationGenerationState(document, simpleName, cancellationToken,
out var token, out var constructor, out var typeToGenerateIn))
{
this.Token = token;
this.DelegatedConstructorOpt = constructor;
this.ParameterTypes = constructor.Parameters.Select(p => p.Type).ToImmutableArray();
this.ParameterRefKinds = constructor.Parameters.Select(p => p.RefKind).ToList();
}
cancellationToken.ThrowIfCancellationRequested();
return await TryDetermineTypeToGenerateInAsync(document, typeToGenerateIn, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> TryInitializeSimpleNameGenerationAsync(
TService service,
SemanticDocument document,
......
......@@ -23,11 +23,9 @@ protected AbstractGenerateConstructorService()
}
protected abstract bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken);
protected abstract bool IsClassDeclarationGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken);
protected abstract bool IsConstructorInitializerGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken);
protected abstract bool TryInitializeSimpleNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray<TArgumentSyntax> arguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract bool TryInitializeClassDeclarationGenerationState(SemanticDocument document, SyntaxNode classDeclaration, CancellationToken cancellationToken, out SyntaxToken token, out IMethodSymbol constructor, out INamedTypeSymbol typeToGenerateIn);
protected abstract bool TryInitializeConstructorInitializerGeneration(SemanticDocument document, SyntaxNode constructorInitializer, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray<TArgumentSyntax> arguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract bool TryInitializeSimpleAttributeNameGenerationState(SemanticDocument document, SyntaxNode simpleName, CancellationToken cancellationToken, out SyntaxToken token, out ImmutableArray<TArgumentSyntax> arguments, out ImmutableArray<TAttributeArgumentSyntax> attributeArguments, out INamedTypeSymbol typeToGenerateIn);
protected abstract ImmutableArray<ParameterName> GenerateParameterNames(SemanticModel semanticModel, IEnumerable<TArgumentSyntax> arguments, IList<string> reservedNames, CancellationToken cancellationToken);
......
......@@ -42,7 +42,7 @@ protected override async Task<Document> GetChangedDocumentAsync(CancellationToke
{
var result = await CodeGenerator.AddMemberDeclarationsAsync(
_document.Project.Solution,
_state.ClassType,
_state.ClassOrStructType,
_constructors.Select(CreateConstructorDefinition),
cancellationToken: cancellationToken).ConfigureAwait(false);
......@@ -61,7 +61,7 @@ protected override async Task<Document> GetChangedDocumentAsync(CancellationToke
attributes: default(ImmutableArray<AttributeData>),
accessibility: constructor.DeclaredAccessibility,
modifiers: new DeclarationModifiers(),
typeName: _state.ClassType.Name,
typeName: _state.ClassOrStructType.Name,
parameters: constructor.Parameters,
statements: default(ImmutableArray<SyntaxNode>),
baseConstructorArguments: baseConstructorArguments);
......
......@@ -22,9 +22,9 @@ private static string GetDisplayText(State state, IMethodSymbol constructor)
var parameters = constructor.Parameters.Select(p => p.Name);
var parameterString = string.Join(", ", parameters);
return string.Format(FeaturesResources.Generate_constructor_0_1 + ".",
state.ClassType.Name, parameterString);
return string.Format(FeaturesResources.Generate_constructor_0_1,
state.ClassOrStructType.Name, parameterString);
}
}
}
}
}
\ No newline at end of file
// 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.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors
{
......@@ -15,16 +13,9 @@ private class CodeActionAll : AbstractCodeAction
Document document,
State state,
IList<IMethodSymbol> constructors)
: base(service, document, state, GetConstructors(state, constructors), FeaturesResources.Generate_all)
: base(service, document, state, constructors, FeaturesResources.Generate_all)
{
}
private static IList<IMethodSymbol> GetConstructors(State state, IList<IMethodSymbol> constructors)
{
return state.UnimplementedDefaultConstructor != null
? new[] { state.UnimplementedDefaultConstructor }.Concat(constructors).ToList()
: constructors;
}
}
}
}
}
\ No newline at end of file
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -15,12 +14,9 @@ internal abstract partial class AbstractGenerateDefaultConstructorsService<TServ
{
private class State
{
public INamedTypeSymbol ClassType { get; private set; }
public INamedTypeSymbol ClassOrStructType { get; private set; }
public IList<IMethodSymbol> UnimplementedConstructors { get; private set; }
public IMethodSymbol UnimplementedDefaultConstructor { get; private set; }
public SyntaxNode BaseTypeNode { get; private set; }
public ImmutableArray<IMethodSymbol> UnimplementedConstructors { get; private set; }
private State()
{
......@@ -47,56 +43,54 @@ private State()
TextSpan textSpan,
CancellationToken cancellationToken)
{
if (!service.TryInitializeState(document, textSpan, cancellationToken, out var baseTypeNode, out var classType))
{
return false;
}
if (!baseTypeNode.Span.IntersectsWith(textSpan.Start))
if (!service.TryInitializeState(document, textSpan, cancellationToken, out var classOrStructType))
{
return false;
}
this.BaseTypeNode = baseTypeNode;
this.ClassType = classType;
var baseType = this.ClassType.BaseType;
this.ClassOrStructType = classOrStructType;
if (this.ClassType.TypeKind != TypeKind.Class ||
this.ClassType.IsStatic ||
var baseType = this.ClassOrStructType.BaseType;
if (this.ClassOrStructType.IsStatic ||
baseType == null ||
baseType.SpecialType == SpecialType.System_Object ||
baseType.TypeKind == TypeKind.Error)
{
return false;
}
var semanticFacts = document.Project.LanguageServices.GetService<ISemanticFactsService>();
var classConstructors = this.ClassType.InstanceConstructors;
var baseTypeConstructors =
baseType.InstanceConstructors
.Where(c => c.IsAccessibleWithin(this.ClassType));
var classConstructors = this.ClassOrStructType.InstanceConstructors;
var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(this.ClassType.Language);
var destinationProvider = document.Project.Solution.Workspace.Services.GetLanguageServices(this.ClassOrStructType.Language);
var syntaxFacts = destinationProvider.GetService<ISyntaxFactsService>();
var isCaseSensitive = syntaxFacts.IsCaseSensitive;
var missingConstructors =
baseTypeConstructors.Where(c1 => !classConstructors.Any(
c2 => SignatureComparer.Instance.HaveSameSignature(c1.Parameters, c2.Parameters, compareParameterName: true, isCaseSensitive: syntaxFacts.IsCaseSensitive))).ToList();
this.UnimplementedConstructors =
baseType.InstanceConstructors
.WhereAsArray(c => c.IsAccessibleWithin(this.ClassOrStructType) &&
IsMissing(c, classConstructors, isCaseSensitive));
this.UnimplementedConstructors = missingConstructors;
return this.UnimplementedConstructors.Length > 0;
}
private bool IsMissing(
IMethodSymbol constructor,
ImmutableArray<IMethodSymbol> classConstructors,
bool isCaseSensitive)
{
var matchingConstructor = classConstructors.FirstOrDefault(
c => SignatureComparer.Instance.HaveSameSignature(
constructor.Parameters, c.Parameters, compareParameterName: true, isCaseSensitive: isCaseSensitive));
this.UnimplementedDefaultConstructor = baseTypeConstructors.FirstOrDefault(c => c.Parameters.Length == 0);
if (this.UnimplementedDefaultConstructor != null)
if (matchingConstructor == null)
{
if (classConstructors.Any(c => c.Parameters.Length == 0 && !c.IsImplicitlyDeclared))
{
this.UnimplementedDefaultConstructor = null;
}
return true;
}
return this.UnimplementedConstructors.Count > 0;
// We have a matching constructor in this type. But we'll still offer to create the
// constructor if the constructor that we have is implicit.
return matchingConstructor.IsImplicitlyDeclared;
}
}
}
}
}
\ No newline at end of file
// 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.Threading;
using System.Threading.Tasks;
......@@ -17,7 +16,7 @@ protected AbstractGenerateDefaultConstructorsService()
{
}
protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out SyntaxNode baseTypeNode, out INamedTypeSymbol classType);
protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out INamedTypeSymbol classOrStructType);
public async Task<ImmutableArray<CodeAction>> GenerateDefaultConstructorsAsync(
Document document,
......@@ -28,30 +27,26 @@ protected AbstractGenerateDefaultConstructorsService()
{
var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var result = ArrayBuilder<CodeAction>.GetInstance();
if (textSpan.IsEmpty)
{
var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken);
if (state != null)
{
return GetActions(document, state).AsImmutableOrNull();
foreach (var constructor in state.UnimplementedConstructors)
{
result.Add(new GenerateDefaultConstructorCodeAction((TService)this, document, state, constructor));
}
if (state.UnimplementedConstructors.Length > 1)
{
result.Add(new CodeActionAll((TService)this, document, state, state.UnimplementedConstructors));
}
}
}
return default(ImmutableArray<CodeAction>);
}
}
private IEnumerable<CodeAction> GetActions(Document document, State state)
{
foreach (var constructor in state.UnimplementedConstructors)
{
yield return new GenerateDefaultConstructorCodeAction((TService)this, document, state, constructor);
}
if (state.UnimplementedConstructors.Count > 1)
{
yield return new CodeActionAll((TService)this, document, state, state.UnimplementedConstructors);
return result.ToImmutableAndFree();
}
}
}
}
}
\ No newline at end of file
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Threading
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor
Imports System.Composition
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor
Friend Class GenerateConstructorDiagnosticIds
......@@ -60,19 +60,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor
End Function
Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean
If TypeOf node Is InvocationExpressionSyntax OrElse
TypeOf node Is ObjectCreationExpressionSyntax OrElse
TypeOf node Is AttributeSyntax Then
Return True
End If
Return diagnostic.Id = GenerateConstructorDiagnosticIds.BC30387 AndAlso
TypeOf node Is ClassBlockSyntax AndAlso
IsInClassDeclarationHeader(DirectCast(node, ClassBlockSyntax), token)
End Function
Private Function IsInClassDeclarationHeader(node As ClassBlockSyntax, token As SyntaxToken) As Boolean
Return node.ClassStatement.Span.Contains(token.Span)
Return TypeOf node Is InvocationExpressionSyntax OrElse
TypeOf node Is ObjectCreationExpressionSyntax OrElse
TypeOf node Is AttributeSyntax
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -154,33 +154,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor
Return compilation.ClassifyConversion(sourceType, targetType).IsWidening
End Function
Protected Overrides Function IsClassDeclarationGeneration(document As SemanticDocument,
node As SyntaxNode,
cancellationToken As CancellationToken) As Boolean
Return TypeOf node Is ClassBlockSyntax
End Function
Protected Overrides Function TryInitializeClassDeclarationGenerationState(
document As SemanticDocument,
classDeclaration As SyntaxNode,
cancellationToken As CancellationToken,
ByRef token As SyntaxToken,
ByRef delegatedConstructor As IMethodSymbol,
ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
Dim semanticModel = document.SemanticModel
Dim classBlock = DirectCast(classDeclaration, ClassBlockSyntax)
Dim classSymbol = semanticModel.GetDeclaredSymbol(classBlock.BlockStatement, cancellationToken)
Dim constructor = classSymbol?.BaseType?.Constructors.FirstOrDefault(Function(c) IsSymbolAccessible(c, document))
If constructor Is Nothing Then
Return False
End If
typeToGenerateIn = classSymbol
delegatedConstructor = constructor
token = classBlock.BlockStatement.Identifier
Return True
End Function
Private Shared ReadOnly s_annotation As SyntaxAnnotation = New SyntaxAnnotation
Friend Overrides Function GetDelegatingConstructor(state As State,
......
......@@ -2,8 +2,10 @@
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.GenerateFromMembers
Imports Microsoft.CodeAnalysis.GenerateMember.GenerateDefaultConstructors
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
......@@ -14,28 +16,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateDefaultConst
Protected Overrides Function TryInitializeState(
document As SemanticDocument, textSpan As TextSpan, cancellationToken As CancellationToken,
ByRef baseTypeNode As SyntaxNode, ByRef classType As INamedTypeSymbol) As Boolean
If cancellationToken.IsCancellationRequested Then
Return False
ByRef classOrStructType As INamedTypeSymbol) As Boolean
cancellationToken.ThrowIfCancellationRequested()
' Offer the feature if we're on the header for the class/struct, or if we're on the
' first base-type of a class.
Dim syntaxFacts = document.Document.GetLanguageService(Of ISyntaxFactsService)()
If syntaxFacts.IsOnTypeHeader(document.Root, textSpan.Start) Then
classOrStructType = AbstractGenerateFromMembersCodeRefactoringProvider.GetEnclosingNamedType(
document.SemanticModel, document.Root, textSpan.Start, cancellationToken)
Return classOrStructType IsNot Nothing
End If
Dim token = DirectCast(document.Root, SyntaxNode).FindToken(textSpan.Start)
Dim token = document.Root.FindToken(textSpan.Start)
Dim type = token.GetAncestor(Of TypeSyntax)()
If type IsNot Nothing AndAlso type.IsParentKind(SyntaxKind.InheritsStatement) Then
Dim baseList = DirectCast(type.Parent, InheritsStatementSyntax)
If baseList.Types.Count > 0 AndAlso
baseList.Types(0) Is type AndAlso
baseList.IsParentKind(SyntaxKind.ClassBlock) Then
classType = TryCast(document.SemanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken), INamedTypeSymbol)
baseTypeNode = type
Return classType IsNot Nothing
classOrStructType = TryCast(document.SemanticModel.GetDeclaredSymbol(baseList.Parent, cancellationToken), INamedTypeSymbol)
Return classOrStructType IsNot Nothing
End If
End If
baseTypeNode = Nothing
classType = Nothing
classOrStructType = Nothing
Return False
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -425,6 +425,21 @@ public Customer()
//]
}}
}}
";
private static readonly string s_preferSimpleDefaultExpression = $@"
using System.Threading;
class Customer
{{
//[
// {ServicesVSResources.Prefer_colon}
void DoWork(CancellationToken cancellationToken = default) {{ }}
// {ServicesVSResources.Over_colon}
void DoWork(CancellationToken cancellationToken = default(CancellationToken)) {{ }}
//]
}}
";
private static readonly string s_preferInlinedVariableDeclaration = $@"
......@@ -693,6 +708,7 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, CSharpVSResources.Prefer_pattern_matching_over_is_with_cast_check, s_preferPatternMatchingOverIsWithCastCheck, s_preferPatternMatchingOverIsWithCastCheck, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, CSharpVSResources.Prefer_pattern_matching_over_as_with_null_check, s_preferPatternMatchingOverAsWithNullCheck, s_preferPatternMatchingOverAsWithNullCheck, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferExplicitTupleNames, ServicesVSResources.Prefer_explicit_tuple_name, s_preferExplicitTupleName, s_preferExplicitTupleName, this, optionSet, expressionPreferencesGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, ServicesVSResources.Prefer_simple_default_expression, s_preferSimpleDefaultExpression, s_preferSimpleDefaultExpression, this, optionSet, expressionPreferencesGroupTitle));
AddExpressionBodyOptions(optionSet, expressionPreferencesGroupTitle);
......
......@@ -2,6 +2,7 @@
using System.Composition;
using System.Reflection;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.Internal.VisualStudio.Shell.Interop;
......@@ -10,14 +11,14 @@
namespace Microsoft.VisualStudio.LanguageServices.Experimentation
{
[ExportWorkspaceService(typeof(IExperimentationService), ServiceLayer.Host), Shared]
internal class VisualStudioExperimentationService : IExperimentationService
internal class VisualStudioExperimentationService : ForegroundThreadAffinitizedObject, IExperimentationService
{
private readonly object _experimentationServiceOpt;
private readonly MethodInfo _isCachedFlightEnabledInfo;
[ImportingConstructor]
public VisualStudioExperimentationService(
SVsServiceProvider serviceProvider)
public VisualStudioExperimentationService(SVsServiceProvider serviceProvider)
: base(assertIsForeground: true)
{
try
{
......@@ -35,6 +36,7 @@ internal class VisualStudioExperimentationService : IExperimentationService
public bool IsExperimentEnabled(string experimentName)
{
ThisCanBeCalledOnAnyThread();
if (_isCachedFlightEnabledInfo != null)
{
try
......
// 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 Microsoft.CodeAnalysis.Options;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
{
internal static class AnalyzerABTestOptions
{
private const string LocalRegistryPath = @"Roslyn\Internal\Analyzers\AB\Vsix\";
public static readonly Option<long> LastDateTimeUsedSuggestionAction = new Option<long>(nameof(AnalyzerABTestOptions),
nameof(LastDateTimeUsedSuggestionAction), defaultValue: DateTime.MinValue.ToBinary(),
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(LastDateTimeUsedSuggestionAction)));
public static readonly Option<uint> UsedSuggestedActionCount = new Option<uint>(nameof(AnalyzerABTestOptions), nameof(UsedSuggestedActionCount),
defaultValue: 0, storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(UsedSuggestedActionCount)));
public static readonly Option<bool> NeverShowAgain = new Option<bool>(nameof(AnalyzerABTestOptions), nameof(NeverShowAgain),
defaultValue: false, storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeverShowAgain)));
public static readonly Option<bool> HasMetCandidacyRequirements = new Option<bool>(nameof(AnalyzerABTestOptions), nameof(HasMetCandidacyRequirements),
defaultValue: false, storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(HasMetCandidacyRequirements)));
public static readonly Option<long> LastDateTimeInfoBarShown = new Option<long>(nameof(AnalyzerABTestOptions), nameof(LastDateTimeInfoBarShown),
defaultValue: DateTime.MinValue.ToBinary(),
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(LastDateTimeInfoBarShown)));
}
}
// 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.ComponentModel.Composition;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
{
[Export(typeof(ISuggestedActionCallback))]
internal class AnalyzerVsixSuggestedActionCallback : ForegroundThreadAffinitizedObject, ISuggestedActionCallback
{
private const string AnalyzerEnabledFlight = @"LiveCA/LiveCAcf";
private const string AnalyzerVsixHyperlink = @"https://go.microsoft.com/fwlink/?linkid=849061";
private static readonly Guid FxCopAnalyzersPackageGuid = Guid.Parse("{4A41D270-A97F-4639-A352-28732FC410E4}");
private readonly VisualStudioWorkspace _workspace;
private readonly SVsServiceProvider _serviceProvider;
/// <summary>
/// Tracks when the bar is shown so we don't show to the user more than once per session
/// </summary>
private bool _infoBarChecked = false;
/// <summary>
/// This service is initialzed by <see cref="OnSuggestedActionExecuted(SuggestedAction)"/>
/// </summary>
private IExperimentationService _experimentationService;
private LiveCodeAnalysisInstallStatus _installStatus = LiveCodeAnalysisInstallStatus.Unknown;
[ImportingConstructor]
public AnalyzerVsixSuggestedActionCallback(
VisualStudioWorkspace workspace,
SVsServiceProvider serviceProvider)
{
_workspace = workspace;
_serviceProvider = serviceProvider;
}
public void OnSuggestedActionExecuted(SuggestedAction action)
{
// If the experimentation service hasn't been retrieved, we'll need to be on the UI
// thread to get it
AssertIsForeground();
// If the user has previously clicked don't show again, then we bail out immediately
if (_workspace.Options.GetOption(AnalyzerABTestOptions.NeverShowAgain))
{
return;
}
EnsureInitialized();
// Only show if the VSIX is not installed, the info bar hasn't been shown this session,
// and the user is an A/B test candidate
if (!_infoBarChecked &&
!IsVsixInstalled() &&
IsCandidate())
{
ShowInfoBarIfNecessary();
}
}
private void EnsureInitialized()
{
// Initialize the experimentation service if it hasn't yet been fetched
if (_experimentationService == null)
{
_experimentationService = _workspace.Services.GetRequiredService<IExperimentationService>();
}
}
private bool IsVsixInstalled()
{
if (_installStatus == LiveCodeAnalysisInstallStatus.Unknown)
{
var vsShell = _serviceProvider.GetService(typeof(SVsShell)) as IVsShell;
var hr = vsShell.IsPackageInstalled(FxCopAnalyzersPackageGuid, out int installed);
if (ErrorHandler.Failed(hr))
{
FatalError.ReportWithoutCrash(Marshal.GetExceptionForHR(hr));
// We set installed to ensure we don't go through this again next time a
// suggested action is called, and we don't want to continue if the shell
// is busted.
_installStatus = LiveCodeAnalysisInstallStatus.Installed;
}
else
{
_installStatus = installed != 0 ? LiveCodeAnalysisInstallStatus.Installed : LiveCodeAnalysisInstallStatus.NotInstalled;
}
}
return _installStatus == LiveCodeAnalysisInstallStatus.Installed;
}
private bool IsCandidate()
{
// Filter for valid A/B test candidates. Candidates fill the following critera:
// 1: Are a Dotnet user (as evidenced by the fact that this code is being run)
// 2: Have triggered a lightbulb on 3 separate days
// If the user hasn't met candidacy conditions, then we check them. Otherwise, proceed
// to info bar check
var options = _workspace.Options;
var isCandidate = options.GetOption(AnalyzerABTestOptions.HasMetCandidacyRequirements);
if (!isCandidate)
{
// We store in UTC to avoid any timezone offset weirdness
var lastTriggeredTime = DateTime.FromBinary(options.GetOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction));
var currentTime = DateTime.UtcNow;
var span = currentTime - lastTriggeredTime;
if (span.TotalDays >= 1)
{
options = options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeUsedSuggestionAction, currentTime.ToBinary());
var usageCount = options.GetOption(AnalyzerABTestOptions.UsedSuggestedActionCount);
usageCount++;
options = options.WithChangedOption(AnalyzerABTestOptions.UsedSuggestedActionCount, usageCount);
if (usageCount >= 3)
{
isCandidate = true;
options = options.WithChangedOption(AnalyzerABTestOptions.HasMetCandidacyRequirements, true);
}
_workspace.Options = options;
}
}
return isCandidate;
}
private void ShowInfoBarIfNecessary()
{
// Only check for whether we should show an info bar once per session.
_infoBarChecked = true;
if (_experimentationService.IsExperimentEnabled(AnalyzerEnabledFlight))
{
// If we got true from the experimentation service, then we're in the treatment
// group, and the experiment is enabled. We determine if the infobar has been
// displayed in the past 24 hours. If it hasn't been displayed, then we do so now.
var lastTimeInfoBarShown = DateTime.FromBinary(_workspace.Options.GetOption(AnalyzerABTestOptions.LastDateTimeInfoBarShown));
var utcNow = DateTime.UtcNow;
var timeSinceLastShown = utcNow - lastTimeInfoBarShown;
if (timeSinceLastShown.TotalDays >= 1)
{
_workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.LastDateTimeInfoBarShown, utcNow.ToBinary());
var infoBarService = _workspace.Services.GetRequiredService<IInfoBarService>();
infoBarService.ShowInfoBarInGlobalView(
ServicesVSResources.Try_the_preview_version_of_our_live_code_analysis_extension_which_provides_more_fixes_for_common_API_design_naming_performance_and_reliability_issues,
// Install link
new InfoBarUI(title: ServicesVSResources.Learn_more,
kind: InfoBarUI.UIKind.HyperLink,
action: OpenInstallHyperlink),
// Don't show the InfoBar again link
new InfoBarUI(title: ServicesVSResources.Never_show_this_again,
kind: InfoBarUI.UIKind.Button,
action: DoNotShowAgain));
}
}
}
private void OpenInstallHyperlink()
{
System.Diagnostics.Process.Start(AnalyzerVsixHyperlink);
}
private void DoNotShowAgain()
{
_workspace.Options = _workspace.Options.WithChangedOption(AnalyzerABTestOptions.NeverShowAgain, true);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Experimentation
{
internal enum LiveCodeAnalysisInstallStatus
{
Unknown,
Installed,
NotInstalled
}
}
\ No newline at end of file
......@@ -19,7 +19,7 @@ namespace Microsoft.VisualStudio.LanguageServices {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class ServicesVSResources {
......@@ -1259,6 +1259,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Never show this again.
/// </summary>
internal static string Never_show_this_again {
get {
return ResourceManager.GetString("Never_show_this_again", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to New _file name:.
/// </summary>
......@@ -1556,6 +1565,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Prefer simple &apos;default&apos; expression.
/// </summary>
internal static string Prefer_simple_default_expression {
get {
return ResourceManager.GetString("Prefer_simple_default_expression", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to prefer throwing properties.
/// </summary>
......@@ -2140,6 +2158,16 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Try the preview version of our live code analysis extension, which provides more fixes for common API design, naming, performance, and reliability issues.
/// </summary>
internal static string Try_the_preview_version_of_our_live_code_analysis_extension_which_provides_more_fixes_for_common_API_design_naming_performance_and_reliability_issues {
get {
return ResourceManager.GetString("Try_the_preview_version_of_our_live_code_analysis_extension_which_provides_more_f" +
"ixes_for_common_API_design_naming_performance_and_reliability_issues", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type.
/// </summary>
......
......@@ -906,10 +906,19 @@ Additional information: {1}</value>
<data name="prefer_throwing_properties" xml:space="preserve">
<value>prefer throwing properties</value>
</data>
<data name="When_generating_properties" xml:space="preserve">
<data name="When_generating_properties" xml:space="preserve">
<value>When generating properties:</value>
</data>
</data>
<data name="Options" xml:space="preserve">
<value>Options</value>
</data>
<data name="Try_the_preview_version_of_our_live_code_analysis_extension_which_provides_more_fixes_for_common_API_design_naming_performance_and_reliability_issues" xml:space="preserve">
<value>Try the preview version of our live code analysis extension, which provides more fixes for common API design, naming, performance, and reliability issues</value>
</data>
<data name="Never_show_this_again" xml:space="preserve">
<value>Never show this again</value>
</data>
<data name="Prefer_simple_default_expression" xml:space="preserve">
<value>Prefer simple 'default' expression</value>
</data>
</root>
\ No newline at end of file
......@@ -62,6 +62,9 @@
<Compile Include="Implementation\EditAndContinue\Interop\NativeMethods.cs" />
<Compile Include="Implementation\AnalyzerDependency\IIgnorableAssemblyList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IBindingRedirectionService.cs" />
<Compile Include="Implementation\Experimentation\AnalyzerVsixSuggestedActionCallback.cs" />
<Compile Include="Implementation\Experimentation\AnalyzerABTestOptions.cs" />
<Compile Include="Implementation\Experimentation\LiveCodeAnalysisInstallStatus.cs" />
<Compile Include="Implementation\Extensions\ServiceProviderExtensions.cs" />
<Compile Include="ID.InteractiveCommands.cs" />
<Compile Include="Implementation\FindReferences\VisualStudioDefinitionsAndReferencesFactory.cs" />
......
......@@ -20,7 +20,7 @@ public CSharpNavigateTo(VisualStudioInstanceFactory instanceFactory)
{
}
[Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/19530"), Trait(Traits.Feature, Traits.Features.SignatureHelp)]
public void NavigateTo()
{
var project = new ProjectUtils.Project(ProjectName);
......
// 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;
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Xunit;
using ProjectUtils = Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils;
namespace Roslyn.VisualStudio.IntegrationTests.VisualBasic
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class BasicExpressionEvaluator : AbstractEditorTest
{
protected override string LanguageName => LanguageNames.VisualBasic;
public BasicExpressionEvaluator(VisualStudioInstanceFactory instanceFactory) : base(instanceFactory)
{
VisualStudio.SolutionExplorer.CreateSolution(nameof(BasicBuild));
var testProj = new ProjectUtils.Project("TestProj");
VisualStudio.SolutionExplorer.AddProject(testProj, WellKnownProjectTemplates.ConsoleApplication, LanguageNames.VisualBasic);
VisualStudio.Editor.SetText(@"Imports System
Module Module1
Sub Main()
Dim mySByte As SByte = SByte.MaxValue / 2
Dim myShort As Short = Short.MaxValue / 2
Dim myInt As Integer = Integer.MaxValue / 2
Dim myLong As Long = Long.MaxValue / 2
Dim myByte As Byte = Byte.MaxValue / 2
Dim myUShort As UShort = UShort.MaxValue / 2
Dim myUInt As UInteger = UInteger.MaxValue / 2
Dim myULong As ULong = ULong.MaxValue / 2
Dim myFloat As Single = Single.MaxValue / 2
Dim myDouble As Double = Double.MaxValue / 2
Dim myDecimal As Decimal = Decimal.MaxValue / 2
Dim myChar As Char = ""A""c
Dim myBool As Boolean = True
Dim myObject As Object = Nothing
Dim myString As String = String.Empty
Dim myValueType As System.ValueType = myShort
Dim myEnum As System.Enum = Nothing
Dim myArray As System.Array = Nothing
Dim myDelegate As System.Delegate = Nothing
Dim myMulticastDelegate As System.MulticastDelegate = Nothing
System.Diagnostics.Debugger.Break()
End Sub
End Module");
}
[Fact]
public void ValidateLocalsWindow()
{
VisualStudio.Debugger.Go(waitForBreakMode: true);
VisualStudio.LocalsWindow.Verify.CheckCount(20);
VisualStudio.LocalsWindow.Verify.CheckEntry("mySByte", "SByte", "64");
VisualStudio.LocalsWindow.Verify.CheckEntry("myShort", "Short", "16384");
VisualStudio.LocalsWindow.Verify.CheckEntry("myInt", "Integer", "1073741824");
VisualStudio.LocalsWindow.Verify.CheckEntry("myLong", "Long", "4611686018427387904");
VisualStudio.LocalsWindow.Verify.CheckEntry("myByte", "Byte", "128");
VisualStudio.LocalsWindow.Verify.CheckEntry("myUShort", "UShort", "32768");
VisualStudio.LocalsWindow.Verify.CheckEntry("myUInt", "UInteger", "2147483648");
VisualStudio.LocalsWindow.Verify.CheckEntry("myULong", "ULong", "9223372036854775808");
VisualStudio.LocalsWindow.Verify.CheckEntry("myFloat", "Single", "1.70141173E+38");
VisualStudio.LocalsWindow.Verify.CheckEntry("myDouble", "Double", "8.9884656743115785E+307");
VisualStudio.LocalsWindow.Verify.CheckEntry("myDecimal", "Decimal", "39614081257132168796771975168");
VisualStudio.LocalsWindow.Verify.CheckEntry("myChar", "Char", "\"A\"c");
VisualStudio.LocalsWindow.Verify.CheckEntry("myBool", "Boolean", "True");
VisualStudio.LocalsWindow.Verify.CheckEntry("myObject", "Object", "Nothing");
VisualStudio.LocalsWindow.Verify.CheckEntry("myString", "String", "\"\"");
VisualStudio.LocalsWindow.Verify.CheckEntry("myValueType", "System.ValueType {Short}", "16384");
VisualStudio.LocalsWindow.Verify.CheckEntry("myEnum", "System.Enum", "Nothing");
VisualStudio.LocalsWindow.Verify.CheckEntry("myArray", "System.Array", "Nothing");
VisualStudio.LocalsWindow.Verify.CheckEntry("myDelegate", "System.Delegate", "Nothing");
VisualStudio.LocalsWindow.Verify.CheckEntry("myMulticastDelegate", "System.MulticastDelegate", "Nothing");
}
[Fact]
public void EvaluatePrimitiveValues()
{
VisualStudio.Debugger.Go(waitForBreakMode: true);
// It is better to use the Immediate Window but DTE does not provide an access to it.
VisualStudio.Debugger.CheckExpression("myByte", "Byte", "128");
VisualStudio.Debugger.CheckExpression("myFloat", "Single", "1.70141173E+38");
VisualStudio.Debugger.CheckExpression("myChar", "Char", "\"A\"c");
VisualStudio.Debugger.CheckExpression("myObject", "Object", "Nothing");
VisualStudio.Debugger.CheckExpression("myString", "String", "\"\"");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/19526")]
public void EvaluateLambdaExpressions()
{
VisualStudio.Debugger.Go(waitForBreakMode: true);
// It is better to use the Immediate Window but DTE does not provide an access to it.
VisualStudio.Debugger.CheckExpression("(Function(val)(val+val))(1)", "Integer", "2");
}
[Fact]
public void EvaluateInvalidExpressions()
{
VisualStudio.Debugger.Go(waitForBreakMode: true);
VisualStudio.Debugger.CheckExpression("myNonsense", "", "error BC30451: 'myNonsense' is not declared. It may be inaccessible due to its protection level.");
}
[Fact]
public void StateMachineTypeParameters()
{
VisualStudio.Editor.SetText(@"
Imports System
Imports System.Collections.Generic
Module Module1
Sub Main()
For Each arg In I({ ""a"", ""b""})
Console.WriteLine(arg)
Next
End Sub
Iterator Function I(Of T)(tt As T()) As IEnumerable(Of T)
For Each item In tt
Stop
Yield item
Next
End Function
End Module
");
VisualStudio.Debugger.Go(waitForBreakMode: true);
VisualStudio.LocalsWindow.Verify.CheckEntry( new string[] { "Type variables", "T" }, "String", "String");
// It is better to use the Immediate Window but DTE does not provide an access to it.
VisualStudio.Debugger.CheckExpression("GetType(T) = GetType(String)", "Boolean", "True");
}
public new void Dispose()
{
VisualStudio.Debugger.StepOver(waitForBreakOrEnd: true);
base.Dispose();
}
}
}
\ No newline at end of file
......@@ -66,6 +66,7 @@
<Compile Include="CSharp\CSharpAddMissingReference.cs" />
<Compile Include="VisualBasic\BasicEditAndContinue.cs" />
<Compile Include="VisualBasic\BasicEndConstruct.cs" />
<Compile Include="VisualBasic\BasicExpressionEvaluator.cs" />
<Compile Include="VisualBasic\BasicReferenceHighlighting.cs" />
<Compile Include="VisualBasic\BasicKeywordHighlighting.cs" />
<Compile Include="VisualBasic\BasicEncapsulateField.cs" />
......
// 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.Generic;
using System.Linq;
using EnvDTE80;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
......@@ -9,22 +11,62 @@ internal class LocalsWindow_InProc : InProcComponent
{
public static LocalsWindow_InProc Create() => new LocalsWindow_InProc();
public int GetCount()
{
var dte = ((DTE2)GetDTE());
if (dte.Debugger.CurrentStackFrame != null) // Ensure that debugger is running
{
EnvDTE.Expressions locals = dte.Debugger.CurrentStackFrame.Locals;
return locals.Count;
}
return 0;
}
public Common.Expression GetEntry(string entryName)
{
return new Common.Expression(GetEntryInternal(entryName));
}
public Common.Expression GetEntry(params string[] entryNames)
{
return new Common.Expression(GetEntryInternal(entryNames));
}
private EnvDTE.Expression GetEntryInternal(params string[] entryNames)
{
var entry = GetEntryInternal(entryNames[0]);
for (int i = 1; i < entryNames.Length; i++)
{
entry = GetEntryInternal(entryNames[i], entry.DataMembers);
}
return entry;
}
private EnvDTE.Expression GetEntryInternal(string entryName, EnvDTE.Expressions expressions)
{
var expressionCollection = expressions.Cast<EnvDTE.Expression>();
var expressionMatched = expressionCollection.FirstOrDefault(e => e.Name == entryName);
if (expressionMatched != null)
{
return expressionMatched;
}
string nestedExpressionNamesString = string.Join(",", expressionCollection.Select(e => e.Name));
throw new Exception($"Could not find the local named {entryName}. Available locals are {nestedExpressionNamesString}.");
}
private EnvDTE.Expression GetEntryInternal(string entryName)
{
var dte = ((DTE2)GetDTE());
if (dte.Debugger.CurrentStackFrame != null) // Ensure that debugger is running
{
EnvDTE.Expressions locals = dte.Debugger.CurrentStackFrame.Locals;
foreach (EnvDTE.Expression local in locals)
{
if (local.Name == entryName)
{
return new Common.Expression(local);
}
}
return GetEntryInternal(entryName, locals);
}
throw new Exception($"Could not find the local named {entryName}.");
throw new Exception($"Could not find locals. Debugger is not running.");
}
}
}
\ No newline at end of file
......@@ -21,6 +21,19 @@ public void CheckEntry(string entryName, string expectedType, string expectedVal
Assert.Equal(expectedType, entry.Type);
Assert.Equal(expectedValue, entry.Value);
}
public void CheckEntry(string[] entryNames, string expectedType, string expectedValue)
{
var entry = _localsWindow._localsWindowInProc.GetEntry(entryNames);
Assert.Equal(expectedType, entry.Type);
Assert.Equal(expectedValue, entry.Value);
}
public void CheckCount(int expectedCount)
{
var actualCount = _localsWindow._localsWindowInProc.GetCount();
Assert.Equal(expectedCount, actualCount);
}
}
}
}
\ No newline at end of file
......@@ -98,11 +98,13 @@
<Compile Include="CodeStyle\TypeStyle\TypeStyle.cs" />
<Compile Include="CodeStyle\TypeStyle\TypeStyleHelper.cs" />
<Compile Include="Composition\CSharpWorkspaceFeatures.cs" />
<Compile Include="Simplification\Reducers\CSharpDefaultExpressionReducer.Rewriter.cs" />
<Compile Include="Diagnostics\CSharpDiagnosticPropertiesService.cs" />
<Compile Include="Execution\CSharpOptionsSerializationService.cs" />
<Compile Include="Extensions\ArrowExpressionClauseSyntaxExtensions.cs" />
<Compile Include="Extensions\AssignmentExpressionSyntaxExtensions.cs" />
<Compile Include="Extensions\BlockSyntaxExtensions.cs" />
<Compile Include="Extensions\DefaultExpressionSyntaxExtensions.cs" />
<Compile Include="Extensions\SemanticModelExtensions.cs" />
<Compile Include="Formatting\CSharpFormattingOptions.Parsers.cs" />
<Compile Include="LanguageServices\CSharpCommandLineParserService.cs" />
......@@ -212,6 +214,7 @@
<Compile Include="Simplification\Reducers\AbstractCSharpReducer.AbstractReductionRewriter.cs" />
<Compile Include="Simplification\Reducers\AbstractCSharpReducer.cs" />
<Compile Include="Simplification\Reducers\CSharpCastReducer.cs" />
<Compile Include="Simplification\Reducers\CSharpDefaultExpressionReducer.cs" />
<Compile Include="Simplification\Reducers\CSharpInferredMemberNameReducer.cs" />
<Compile Include="Simplification\Reducers\CSharpInferredMemberNameReducer.Rewriter.cs" />
<Compile Include="Simplification\Reducers\CSharpCastReducer.Rewriter.cs" />
......
......@@ -3665,9 +3665,7 @@ internal override SyntaxToken NumericLiteralToken(string text, ulong value)
=> SyntaxFactory.Literal(text, value);
public override SyntaxNode DefaultExpression(SyntaxNode type)
{
return SyntaxFactory.DefaultExpression((TypeSyntax)type);
}
=> SyntaxFactory.DefaultExpression((TypeSyntax)type).WithAdditionalAnnotations(Simplifier.Annotation);
public override SyntaxNode DefaultExpression(ITypeSymbol type)
{
......@@ -3701,7 +3699,7 @@ public override SyntaxNode DefaultExpression(ITypeSymbol type)
}
// Default to a "default(<typename>)" expression.
return SyntaxFactory.DefaultExpression(type.GenerateTypeSyntax());
return DefaultExpression(type.GenerateTypeSyntax());
}
private ExpressionSyntax Parenthesize(SyntaxNode expression)
......
......@@ -9,7 +9,6 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;
......@@ -46,9 +45,7 @@ internal static class ExpressionGenerator
}
private static ExpressionSyntax GenerateNullLiteral()
{
return SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);
}
=> SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);
internal static ExpressionSyntax GenerateExpression(
ITypeSymbol type,
......@@ -97,7 +94,7 @@ private static ExpressionSyntax GenerateNullLiteral()
return type == null || type.IsReferenceType || type.IsPointerType() || type.IsNullable()
? GenerateNullLiteral()
: SyntaxFactory.DefaultExpression(type.GenerateTypeSyntax());
: (ExpressionSyntax)CSharpSyntaxGenerator.Instance.DefaultExpression(type);
}
private static ExpressionSyntax GenerateBooleanLiteralExpression(bool val)
......
......@@ -53,12 +53,12 @@ internal static class ParameterGenerator
parameters: SyntaxFactory.SeparatedList(parameters));
}
internal static List<ParameterSyntax> GetParameters(
internal static ImmutableArray<ParameterSyntax> GetParameters(
IEnumerable<IParameterSymbol> parameterDefinitions,
bool isExplicit,
CodeGenerationOptions options)
{
var result = new List<ParameterSyntax>();
var result = ArrayBuilder<ParameterSyntax>.GetInstance();
var seenOptional = false;
var isFirstParam = true;
......@@ -70,7 +70,7 @@ internal static class ParameterGenerator
isFirstParam = false;
}
return result;
return result.ToImmutableAndFree();
}
internal static ParameterSyntax GetParameter(IParameterSymbol p, CodeGenerationOptions options, bool isExplicit, bool isFirstParam, bool seenOptional)
......
......@@ -134,6 +134,12 @@ internal static class CSharpCodeStyleOptions
EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_prefer_braces"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferBraces)}")});
public static readonly Option<CodeStyleOption<bool>> PreferSimpleDefaultExpression = new Option<CodeStyleOption<bool>>(
nameof(CodeStyleOptions), nameof(PreferSimpleDefaultExpression), defaultValue: CodeStyleOptions.TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[] {
EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_prefer_simple_default_expression"),
new RoamingProfileStorageLocation($"TextEditor.CSharp.Specific.{nameof(PreferSimpleDefaultExpression)}")});
public static IEnumerable<Option<CodeStyleOption<bool>>> GetCodeStyleOptions()
{
yield return UseImplicitTypeForIntrinsicTypes;
......@@ -143,6 +149,7 @@ public static IEnumerable<Option<CodeStyleOption<bool>>> GetCodeStyleOptions()
yield return PreferPatternMatchingOverAsWithNullCheck;
yield return PreferPatternMatchingOverIsWithCastCheck;
yield return PreferBraces;
yield return PreferSimpleDefaultExpression;
}
public static IEnumerable<Option<CodeStyleOption<ExpressionBodyPreference>>> GetExpressionBodyOptions()
......
......@@ -101,89 +101,73 @@ public static bool IsBeginningOfStatementContext(this SyntaxToken token)
// for ( ; ; Foo(), |
if (token.Kind() == SyntaxKind.OpenBraceToken &&
token.Parent.IsKind(SyntaxKind.Block))
switch (token.Kind())
{
return true;
}
if (token.Kind() == SyntaxKind.SemicolonToken)
{
var statement = token.GetAncestor<StatementSyntax>();
if (statement != null && !statement.IsParentKind(SyntaxKind.GlobalStatement) &&
statement.GetLastToken(includeZeroWidth: true) == token)
{
case SyntaxKind.OpenBraceToken when token.Parent.IsKind(SyntaxKind.Block):
return true;
}
}
if (token.Kind() == SyntaxKind.CloseBraceToken &&
token.Parent.IsKind(SyntaxKind.Block))
{
if (token.Parent.Parent is StatementSyntax)
{
// Most blocks that are the child of statement are places
// that we can follow with another statement. i.e.:
// if { }
// while () { }
// There are two exceptions.
// try {}
// do {}
if (!token.Parent.IsParentKind(SyntaxKind.TryStatement) &&
!token.Parent.IsParentKind(SyntaxKind.DoStatement))
case SyntaxKind.SemicolonToken:
var statement = token.GetAncestor<StatementSyntax>();
return statement != null && !statement.IsParentKind(SyntaxKind.GlobalStatement) &&
statement.GetLastToken(includeZeroWidth: true) == token;
case SyntaxKind.CloseBraceToken:
if (token.Parent.IsKind(SyntaxKind.Block))
{
return true;
if (token.Parent.Parent is StatementSyntax)
{
// Most blocks that are the child of statement are places
// that we can follow with another statement. i.e.:
// if { }
// while () { }
// There are two exceptions.
// try {}
// do {}
if (!token.Parent.IsParentKind(SyntaxKind.TryStatement) &&
!token.Parent.IsParentKind(SyntaxKind.DoStatement))
{
return true;
}
}
else if (
token.Parent.IsParentKind(SyntaxKind.ElseClause) ||
token.Parent.IsParentKind(SyntaxKind.FinallyClause) ||
token.Parent.IsParentKind(SyntaxKind.CatchClause) ||
token.Parent.IsParentKind(SyntaxKind.SwitchSection))
{
return true;
}
}
}
else if (
token.Parent.IsParentKind(SyntaxKind.ElseClause) ||
token.Parent.IsParentKind(SyntaxKind.FinallyClause) ||
token.Parent.IsParentKind(SyntaxKind.CatchClause) ||
token.Parent.IsParentKind(SyntaxKind.SwitchSection))
{
return true;
}
}
if (token.Kind() == SyntaxKind.CloseBraceToken &&
token.Parent.IsKind(SyntaxKind.SwitchStatement))
{
return true;
}
if (token.Parent.IsKind(SyntaxKind.SwitchStatement))
{
return true;
}
if (token.Kind() == SyntaxKind.ColonToken)
{
if (token.Parent.IsKind(SyntaxKind.CaseSwitchLabel, SyntaxKind.DefaultSwitchLabel, SyntaxKind.LabeledStatement))
{
return true;
}
}
return false;
if (token.Kind() == SyntaxKind.DoKeyword &&
token.Parent.IsKind(SyntaxKind.DoStatement))
{
return true;
}
case SyntaxKind.ColonToken:
return token.Parent.IsKind(SyntaxKind.CaseSwitchLabel,
SyntaxKind.DefaultSwitchLabel,
SyntaxKind.CasePatternSwitchLabel,
SyntaxKind.LabeledStatement);
if (token.Kind() == SyntaxKind.CloseParenToken)
{
var parent = token.Parent;
if (parent.IsKind(SyntaxKind.ForStatement) ||
parent.IsKind(SyntaxKind.ForEachStatement) ||
parent.IsKind(SyntaxKind.ForEachVariableStatement) ||
parent.IsKind(SyntaxKind.WhileStatement) ||
parent.IsKind(SyntaxKind.IfStatement) ||
parent.IsKind(SyntaxKind.LockStatement) ||
parent.IsKind(SyntaxKind.UsingStatement) ||
parent.IsKind(SyntaxKind.FixedStatement))
{
case SyntaxKind.DoKeyword when token.Parent.IsKind(SyntaxKind.DoStatement):
return true;
}
}
if (token.Kind() == SyntaxKind.ElseKeyword)
{
return true;
case SyntaxKind.CloseParenToken:
var parent = token.Parent;
return parent.IsKind(SyntaxKind.ForStatement) ||
parent.IsKind(SyntaxKind.ForEachStatement) ||
parent.IsKind(SyntaxKind.ForEachVariableStatement) ||
parent.IsKind(SyntaxKind.WhileStatement) ||
parent.IsKind(SyntaxKind.IfStatement) ||
parent.IsKind(SyntaxKind.LockStatement) ||
parent.IsKind(SyntaxKind.UsingStatement) ||
parent.IsKind(SyntaxKind.FixedStatement);
case SyntaxKind.ElseKeyword:
return true;
}
return false;
......
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.CSharp.Extensions
{
internal static class DefaultExpressionSyntaxExtensions
{
private static readonly LiteralExpressionSyntax s_defaultLiteralExpression = SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression);
public static bool CanReplaceWithDefaultLiteral(
this DefaultExpressionSyntax defaultExpression,
CSharpParseOptions parseOptions,
OptionSet options,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
if (parseOptions.LanguageVersion < LanguageVersion.CSharp7_1 ||
!options.GetOption(CSharpCodeStyleOptions.PreferSimpleDefaultExpression).Value)
{
return false;
}
// Using the speculation analyzer can be slow. Check for common cases first before
// trying the expensive path.
return CanReplaceWithDefaultLiteralFast(defaultExpression, semanticModel, cancellationToken) ??
CanReplaceWithDefaultLiteralSlow(defaultExpression, semanticModel, cancellationToken);
}
private static bool? CanReplaceWithDefaultLiteralFast(DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
{
if (defaultExpression.IsParentKind(SyntaxKind.EqualsValueClause))
{
var equalsValueClause = (EqualsValueClauseSyntax)defaultExpression.Parent;
var typeSyntax = GetTypeSyntax(equalsValueClause);
if (typeSyntax != null)
{
if (typeSyntax.IsVar)
{
// If we have: var v = default(CancellationToken); then we can't simplify this.
return false;
}
var entityType = semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type;
var defaultType = semanticModel.GetTypeInfo(defaultExpression.Type, cancellationToken).Type;
if (entityType != null && entityType.Equals(defaultType))
{
// We have a simple case of "CancellationToken c = default(CancellationToken)".
// We can just simplify without having to do any additional analysis.
return true;
}
}
}
return null;
}
private static TypeSyntax GetTypeSyntax(EqualsValueClauseSyntax equalsValueClause)
{
if (equalsValueClause.IsParentKind(SyntaxKind.VariableDeclarator) &&
equalsValueClause.Parent.IsParentKind(SyntaxKind.VariableDeclaration))
{
var declaration = (VariableDeclarationSyntax)equalsValueClause.Parent.Parent;
return declaration.Type;
}
else if (equalsValueClause.IsParentKind(SyntaxKind.Parameter))
{
var parameter = (ParameterSyntax)equalsValueClause.Parent;
return parameter.Type;
}
return null;
}
private static bool CanReplaceWithDefaultLiteralSlow(DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
{
var speculationAnalyzer = new SpeculationAnalyzer(
defaultExpression, s_defaultLiteralExpression, semanticModel,
cancellationToken,
skipVerificationForReplacedNode: false,
failOnOverloadResolutionFailuresInOriginalCode: true);
return !speculationAnalyzer.ReplacementChangesSemantics();
}
}
}
\ No newline at end of file
......@@ -4,16 +4,13 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Simplification
......@@ -31,7 +28,8 @@ internal partial class CSharpSimplificationService : AbstractSimplificationServi
new CSharpParenthesesReducer(),
new CSharpEscapingReducer(),
new CSharpMiscellaneousReducer(),
new CSharpInferredMemberNameReducer());
new CSharpInferredMemberNameReducer(),
new CSharpDefaultExpressionReducer());
public CSharpSimplificationService() : base(s_reducers)
{
......
......@@ -18,6 +18,7 @@ protected abstract class AbstractReductionRewriter : CSharpSyntaxRewriter, IRedu
{
private readonly ObjectPool<IReductionRewriter> _pool;
protected CSharpParseOptions ParseOptions { get; private set; }
private OptionSet _optionSet;
private CancellationToken _cancellationToken;
private SemanticModel _semanticModel;
......@@ -33,14 +34,16 @@ protected abstract class AbstractReductionRewriter : CSharpSyntaxRewriter, IRedu
protected AbstractReductionRewriter(ObjectPool<IReductionRewriter> pool)
=> _pool = pool;
public void Initialize(OptionSet optionSet, CancellationToken cancellationToken)
public void Initialize(ParseOptions parseOptions, OptionSet optionSet, CancellationToken cancellationToken)
{
ParseOptions = (CSharpParseOptions)parseOptions;
_optionSet = optionSet;
_cancellationToken = cancellationToken;
}
public void Dispose()
{
ParseOptions = null;
_optionSet = null;
_cancellationToken = CancellationToken.None;
_processedParentNodes.Clear();
......
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Simplification
{
internal partial class CSharpDefaultExpressionReducer
{
private class Rewriter : AbstractReductionRewriter
{
public Rewriter(ObjectPool<IReductionRewriter> pool)
: base(pool)
{
_simplifyDefaultExpression = SimplifyDefaultExpression;
}
private readonly Func<DefaultExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode> _simplifyDefaultExpression;
private SyntaxNode SimplifyDefaultExpression(
DefaultExpressionSyntax node,
SemanticModel semanticModel,
OptionSet optionSet,
CancellationToken cancellationToken)
{
if (node.CanReplaceWithDefaultLiteral(ParseOptions, optionSet, semanticModel, cancellationToken))
{
return SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression)
.WithTriviaFrom(node);
}
return node;
}
public override SyntaxNode VisitDefaultExpression(DefaultExpressionSyntax node)
{
return SimplifyNode(
node,
newNode: base.VisitDefaultExpression(node),
parentNode: node.Parent,
simplifier: _simplifyDefaultExpression);
}
}
}
}
\ No newline at end of file
// 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 Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Simplification
{
internal partial class CSharpDefaultExpressionReducer : AbstractCSharpReducer
{
private static readonly ObjectPool<IReductionRewriter> s_pool = new ObjectPool<IReductionRewriter>(
() => new Rewriter(s_pool));
public CSharpDefaultExpressionReducer() : base(s_pool)
{
}
}
}
\ No newline at end of file
......@@ -100,6 +100,7 @@ public CSharpMiscellaneousReducer() : base(s_pool)
return parenthesizedLambda;
}
private static readonly Func<BlockSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode> s_simplifyBlock = SimplifyBlock;
private static SyntaxNode SimplifyBlock(
......
......@@ -23,8 +23,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Utilities
/// the syntax replacement doesn't break the semantics of any parenting nodes of the original expression.
/// </summary>
internal class SpeculationAnalyzer : AbstractSpeculationAnalyzer<
SyntaxNode, ExpressionSyntax, TypeSyntax, AttributeSyntax,
ArgumentSyntax, CommonForEachStatementSyntax, ThrowStatementSyntax, SemanticModel, Conversion>
ExpressionSyntax,
TypeSyntax,
AttributeSyntax,
ArgumentSyntax,
CommonForEachStatementSyntax,
ThrowStatementSyntax,
Conversion>
{
/// <summary>
/// Creates a semantic analyzer for speculative syntax replacement.
......
......@@ -14,6 +14,7 @@ public sealed partial class Match<TNode>
private const double EpsilonDistance = 0.00001;
private const double MatchingDistance1 = 0.25;
private const double MatchingDistance2 = 0.5;
private const double MatchingDistance3 = 0.75;
private const double MaxDistance = 1.0;
private readonly TreeComparer<TNode> _comparer;
......@@ -153,6 +154,7 @@ private void ComputeMatchForLabel(int label, List<TNode> s1, List<TNode> s2)
ComputeMatchForLabel(s1, s2, tiedToAncestor, EpsilonDistance); // almost exact match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance1); // ok match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance2); // ok match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance3); // ok match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MaxDistance); // any match
}
......
......@@ -73,7 +73,7 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
/// Produces a <see cref="SymbolTreeInfo"/> for a given <see cref="PortableExecutableReference"/>.
/// Note: will never return null;
/// </summary>
public static Task<SymbolTreeInfo> GetInfoForMetadataReferenceAsync(
public static async Task<SymbolTreeInfo> GetInfoForMetadataReferenceAsync(
Solution solution,
PortableExecutableReference reference,
Checksum checksum,
......@@ -83,7 +83,7 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
var metadataId = GetMetadataIdNoThrow(reference);
if (metadataId == null)
{
return Task.FromResult(CreateEmpty(checksum));
return CreateEmpty(checksum);
}
// Try to acquire the data outside the lock. That way we can avoid any sort of
......@@ -92,17 +92,21 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
// the lock is not being held most of the time).
if (s_metadataIdToInfo.TryGetValue(metadataId, out var infoTask))
{
return infoTask;
var info = await infoTask.ConfigureAwait(false);
if (info.Checksum == checksum)
{
return info;
}
}
var metadata = GetMetadataNoThrow(reference);
if (metadata == null)
{
return Task.FromResult(CreateEmpty(checksum));
return CreateEmpty(checksum);
}
return GetInfoForMetadataReferenceSlowAsync(
solution, reference, checksum, loadOnly, metadata, cancellationToken);
return await GetInfoForMetadataReferenceSlowAsync(
solution, reference, checksum, loadOnly, metadata, cancellationToken).ConfigureAwait(false);
}
private static async Task<SymbolTreeInfo> GetInfoForMetadataReferenceSlowAsync(
......@@ -117,7 +121,11 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
cancellationToken.ThrowIfCancellationRequested();
if (s_metadataIdToInfo.TryGetValue(metadata.Id, out var infoTask))
{
return await infoTask.ConfigureAwait(false);
var oldInfo = await infoTask.ConfigureAwait(false);
if (oldInfo.Checksum == checksum)
{
return oldInfo;
}
}
var info = await TryLoadOrCreateMetadataSymbolTreeInfoAsync(
......@@ -130,6 +138,7 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
// Cache the result in our dictionary. Store it as a completed task so that
// future callers don't need to allocate to get the result back.
infoTask = Task.FromResult(info);
s_metadataIdToInfo.Remove(metadata.Id);
s_metadataIdToInfo.Add(metadata.Id, infoTask);
return info;
......
......@@ -10,7 +10,7 @@ internal abstract partial class AbstractReducer
{
internal interface IReductionRewriter : IDisposable
{
void Initialize(OptionSet optionSet, CancellationToken cancellationToken);
void Initialize(ParseOptions parseOptions, OptionSet optionSet, CancellationToken cancellationToken);
SyntaxNodeOrToken VisitNodeOrToken(SyntaxNodeOrToken nodeOrTokenToReduce, SemanticModel semanticModel, bool simplifyAllDescendants);
......
......@@ -191,7 +191,7 @@ protected virtual SyntaxNode TransformReducedNode(SyntaxNode reducedNode, Syntax
using (var rewriter = reducer.GetOrCreateRewriter())
{
rewriter.Initialize(optionSet, cancellationToken);
rewriter.Initialize(document.Project.ParseOptions, optionSet, cancellationToken);
do
{
......@@ -228,7 +228,7 @@ protected virtual SyntaxNode TransformReducedNode(SyntaxNode reducedNode, Syntax
if (this.CanNodeBeSimplifiedWithoutSpeculation(nodeOrToken.AsNode()))
{
// Since this node cannot be speculated, we are replacing the Document with the changes and get a new SemanticModel
SyntaxAnnotation marker = new SyntaxAnnotation();
var marker = new SyntaxAnnotation();
var newRoot = root.ReplaceNode(nodeOrToken.AsNode(), currentNode.WithAdditionalAnnotations(marker));
var newDocument = document.WithSyntaxRoot(newRoot);
semanticModelForReduce = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
......
......@@ -17,30 +17,34 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
/// It uses the original tree's semantic model to create a speculative semantic model and verifies that
/// the syntax replacement doesn't break the semantics of any parenting nodes of the original expression.
/// </summary>
internal abstract class AbstractSpeculationAnalyzer<TSyntaxNode, TExpressionSyntax, TTypeSyntax, TAttributeSyntax,
TArgumentSyntax, TForEachStatementSyntax, TThrowStatementSyntax, TSemanticModel, TConversion>
where TSyntaxNode : SyntaxNode
where TExpressionSyntax : TSyntaxNode
internal abstract class AbstractSpeculationAnalyzer<
TExpressionSyntax,
TTypeSyntax,
TAttributeSyntax,
TArgumentSyntax,
TForEachStatementSyntax,
TThrowStatementSyntax,
TConversion>
where TExpressionSyntax : SyntaxNode
where TTypeSyntax : TExpressionSyntax
where TAttributeSyntax : TSyntaxNode
where TArgumentSyntax : TSyntaxNode
where TForEachStatementSyntax : TSyntaxNode
where TThrowStatementSyntax : TSyntaxNode
where TSemanticModel : SemanticModel
where TAttributeSyntax : SyntaxNode
where TArgumentSyntax : SyntaxNode
where TForEachStatementSyntax : SyntaxNode
where TThrowStatementSyntax : SyntaxNode
where TConversion : struct
{
private readonly TExpressionSyntax _expression;
private readonly TExpressionSyntax _newExpressionForReplace;
private readonly TSemanticModel _semanticModel;
private readonly SemanticModel _semanticModel;
private readonly CancellationToken _cancellationToken;
private readonly bool _skipVerificationForReplacedNode;
private readonly bool _failOnOverloadResolutionFailuresInOriginalCode;
private readonly bool _isNewSemanticModelSpeculativeModel;
private TSyntaxNode _lazySemanticRootOfOriginalExpression;
private SyntaxNode _lazySemanticRootOfOriginalExpression;
private TExpressionSyntax _lazyReplacedExpression;
private TSyntaxNode _lazySemanticRootOfReplacedExpression;
private TSemanticModel _lazySpeculativeSemanticModel;
private SyntaxNode _lazySemanticRootOfReplacedExpression;
private SemanticModel _lazySpeculativeSemanticModel;
/// <summary>
/// Creates a semantic analyzer for speculative syntax replacement.
......@@ -60,7 +64,7 @@ internal abstract class AbstractSpeculationAnalyzer<TSyntaxNode, TExpressionSynt
public AbstractSpeculationAnalyzer(
TExpressionSyntax expression,
TExpressionSyntax newExpression,
TSemanticModel semanticModel,
SemanticModel semanticModel,
CancellationToken cancellationToken,
bool skipVerificationForReplacedNode = false,
bool failOnOverloadResolutionFailuresInOriginalCode = false)
......@@ -88,7 +92,7 @@ internal abstract class AbstractSpeculationAnalyzer<TSyntaxNode, TExpressionSynt
/// field initializer, default parameter initializer or type syntax node.
/// It serves as the root node for all semantic analysis for this syntax replacement.
/// </summary>
public TSyntaxNode SemanticRootOfOriginalExpression
public SyntaxNode SemanticRootOfOriginalExpression
{
get
{
......@@ -105,7 +109,7 @@ public TSyntaxNode SemanticRootOfOriginalExpression
/// <summary>
/// Semantic model for the syntax tree corresponding to <see cref="OriginalExpression"/>
/// </summary>
public TSemanticModel OriginalSemanticModel => _semanticModel;
public SemanticModel OriginalSemanticModel => _semanticModel;
/// <summary>
/// Node which replaces the <see cref="OriginalExpression"/>.
......@@ -126,7 +130,7 @@ public TExpressionSyntax ReplacedExpression
/// This node is used as the argument to the GetSpeculativeSemanticModel API and serves as the root node for all
/// semantic analysis of the speculated tree.
/// </summary>
public TSyntaxNode SemanticRootOfReplacedExpression
public SyntaxNode SemanticRootOfReplacedExpression
{
get
{
......@@ -138,7 +142,7 @@ public TSyntaxNode SemanticRootOfReplacedExpression
/// <summary>
/// Speculative semantic model used for analyzing the semantics of the new tree.
/// </summary>
public TSemanticModel SpeculativeSemanticModel
public SemanticModel SpeculativeSemanticModel
{
get
{
......@@ -149,9 +153,9 @@ public TSemanticModel SpeculativeSemanticModel
public CancellationToken CancellationToken => _cancellationToken;
protected abstract TSyntaxNode GetSemanticRootForSpeculation(TExpressionSyntax expression);
protected abstract SyntaxNode GetSemanticRootForSpeculation(TExpressionSyntax expression);
protected virtual TSyntaxNode GetSemanticRootOfReplacedExpression(TSyntaxNode semanticRootOfOriginalExpression, TExpressionSyntax annotatedReplacedExpression)
protected virtual SyntaxNode GetSemanticRootOfReplacedExpression(SyntaxNode semanticRootOfOriginalExpression, TExpressionSyntax annotatedReplacedExpression)
{
return semanticRootOfOriginalExpression.ReplaceNode(this.OriginalExpression, annotatedReplacedExpression);
}
......@@ -171,19 +175,19 @@ private void EnsureReplacedExpressionAndSemanticRoot()
}
[Conditional("DEBUG")]
protected abstract void ValidateSpeculativeSemanticModel(TSemanticModel speculativeSemanticModel, TSyntaxNode nodeToSpeculate);
protected abstract void ValidateSpeculativeSemanticModel(SemanticModel speculativeSemanticModel, SyntaxNode nodeToSpeculate);
private void EnsureSpeculativeSemanticModel()
{
if (_lazySpeculativeSemanticModel == null)
{
TSyntaxNode nodeToSpeculate = this.SemanticRootOfReplacedExpression;
SyntaxNode nodeToSpeculate = this.SemanticRootOfReplacedExpression;
_lazySpeculativeSemanticModel = CreateSpeculativeSemanticModel(this.SemanticRootOfOriginalExpression, nodeToSpeculate, _semanticModel);
ValidateSpeculativeSemanticModel(_lazySpeculativeSemanticModel, nodeToSpeculate);
}
}
protected abstract TSemanticModel CreateSpeculativeSemanticModel(TSyntaxNode originalNode, TSyntaxNode nodeToSpeculate, TSemanticModel semanticModel);
protected abstract SemanticModel CreateSpeculativeSemanticModel(SyntaxNode originalNode, SyntaxNode nodeToSpeculate, SemanticModel semanticModel);
#region Semantic comparison helpers
......@@ -254,7 +258,7 @@ private bool ImplicitConversionsAreCompatible(TExpressionSyntax originalExpressi
protected abstract bool ConversionsAreCompatible(SemanticModel model1, TExpressionSyntax expression1, SemanticModel model2, TExpressionSyntax expression2);
protected abstract bool ConversionsAreCompatible(TExpressionSyntax originalExpression, ITypeSymbol originalTargetType, TExpressionSyntax newExpression, ITypeSymbol newTargetType);
protected bool SymbolsAreCompatible(TSyntaxNode originalNode, TSyntaxNode newNode, bool requireNonNullSymbols = false)
protected bool SymbolsAreCompatible(SyntaxNode originalNode, SyntaxNode newNode, bool requireNonNullSymbols = false)
{
Debug.Assert(originalNode != null);
Debug.Assert(this.SemanticRootOfOriginalExpression.DescendantNodesAndSelf().Contains(originalNode));
......@@ -408,9 +412,9 @@ public bool ReplacementChangesSemantics()
skipVerificationForCurrentNode: _skipVerificationForReplacedNode);
}
protected abstract bool IsParenthesizedExpression(TSyntaxNode node);
protected abstract bool IsParenthesizedExpression(SyntaxNode node);
protected bool ReplacementChangesSemantics(TSyntaxNode currentOriginalNode, TSyntaxNode currentReplacedNode, TSyntaxNode originalRoot, bool skipVerificationForCurrentNode)
protected bool ReplacementChangesSemantics(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode originalRoot, bool skipVerificationForCurrentNode)
{
if (this.SpeculativeSemanticModel == null)
{
......@@ -418,7 +422,7 @@ protected bool ReplacementChangesSemantics(TSyntaxNode currentOriginalNode, TSyn
return true;
}
TSyntaxNode previousOriginalNode = null, previousReplacedNode = null;
SyntaxNode previousOriginalNode = null, previousReplacedNode = null;
while (true)
{
......@@ -435,8 +439,8 @@ protected bool ReplacementChangesSemantics(TSyntaxNode currentOriginalNode, TSyn
previousOriginalNode = currentOriginalNode;
previousReplacedNode = currentReplacedNode;
currentOriginalNode = (TSyntaxNode)currentOriginalNode.Parent;
currentReplacedNode = (TSyntaxNode)currentReplacedNode.Parent;
currentOriginalNode = currentOriginalNode.Parent;
currentReplacedNode = currentReplacedNode.Parent;
skipVerificationForCurrentNode = skipVerificationForCurrentNode && IsParenthesizedExpression(currentReplacedNode);
}
......@@ -458,9 +462,9 @@ public bool SymbolsForOriginalAndReplacedNodesAreCompatible()
return SymbolsAreCompatible(this.OriginalExpression, this.ReplacedExpression, requireNonNullSymbols: true);
}
protected abstract bool ReplacementChangesSemanticsForNodeLanguageSpecific(TSyntaxNode currentOriginalNode, TSyntaxNode currentReplacedNode, TSyntaxNode previousOriginalNode, TSyntaxNode previousReplacedNode);
protected abstract bool ReplacementChangesSemanticsForNodeLanguageSpecific(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode previousOriginalNode, SyntaxNode previousReplacedNode);
private bool ReplacementChangesSemanticsForNode(TSyntaxNode currentOriginalNode, TSyntaxNode currentReplacedNode, TSyntaxNode previousOriginalNode, TSyntaxNode previousReplacedNode)
private bool ReplacementChangesSemanticsForNode(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode previousOriginalNode, SyntaxNode previousReplacedNode)
{
Debug.Assert(previousOriginalNode == null || previousOriginalNode.Parent == currentOriginalNode);
Debug.Assert(previousReplacedNode == null || previousReplacedNode.Parent == currentReplacedNode);
......@@ -524,7 +528,7 @@ private bool ReplacementBreaksAttribute(TAttributeSyntax attribute, TAttributeSy
protected abstract TExpressionSyntax GetForEachStatementExpression(TForEachStatementSyntax forEachStatement);
protected abstract bool IsForEachTypeInferred(TForEachStatementSyntax forEachStatement, TSemanticModel semanticModel);
protected abstract bool IsForEachTypeInferred(TForEachStatementSyntax forEachStatement, SemanticModel semanticModel);
private bool ReplacementBreaksForEachStatement(TForEachStatementSyntax forEachStatement, TForEachStatementSyntax newForEachStatement)
{
......@@ -637,7 +641,7 @@ private bool ReplacementBreaksTypeResolution(TTypeSyntax type, TTypeSyntax newTy
return symbol != null && !SymbolsAreCompatible(symbol, newSymbol);
}
protected abstract bool IsInvocableExpression(TSyntaxNode node);
protected abstract bool IsInvocableExpression(SyntaxNode node);
private static bool IsDelegateInvoke(ISymbol symbol)
{
......@@ -750,7 +754,7 @@ private bool ReplacementBreaksInvocableExpression(TExpressionSyntax expression,
ISymbol newSymbol,
TExpressionSyntax originalInvocationExpression,
TExpressionSyntax newInvocationExpression,
TSemanticModel speculativeSemanticModel)
SemanticModel speculativeSemanticModel)
{
// If this is an interface member, we have to be careful. In general,
// we have to treat an interface member as incompatible with the new member
......@@ -855,7 +859,7 @@ private static bool IsEffectivelySealedClass(ITypeSymbol type)
return false;
}
private bool IsReceiverNonUniquePossibleValueTypeParam(TExpressionSyntax invocation, TSemanticModel semanticModel)
private bool IsReceiverNonUniquePossibleValueTypeParam(TExpressionSyntax invocation, SemanticModel semanticModel)
{
var receiver = GetReceiver(invocation);
if (receiver != null)
......@@ -873,7 +877,7 @@ private bool IsReceiverNonUniquePossibleValueTypeParam(TExpressionSyntax invocat
// Returns true if the given receiver expression for an invocation represents a unique copy of the underlying object
// that is not referenced by any other variable.
// For example, if the receiver expression is an invocation, object-creation, element-access or member-access expression.
private static bool IsReceiverUniqueInstance(TExpressionSyntax receiver, TSemanticModel semanticModel)
private static bool IsReceiverUniqueInstance(TExpressionSyntax receiver, SemanticModel semanticModel)
{
var receiverSymbol = semanticModel.GetSymbolInfo(receiver).Symbol;
......@@ -1057,7 +1061,7 @@ private bool SymbolsHaveCompatibleParameterLists(ISymbol originalSymbol, ISymbol
}
}
protected abstract TConversion ClassifyConversion(TSemanticModel model, TExpressionSyntax expression, ITypeSymbol targetType);
protected abstract TConversion ClassifyConversion(TSemanticModel model, ITypeSymbol originalType, ITypeSymbol targetType);
protected abstract TConversion ClassifyConversion(SemanticModel model, TExpressionSyntax expression, ITypeSymbol targetType);
protected abstract TConversion ClassifyConversion(SemanticModel model, ITypeSymbol originalType, ITypeSymbol targetType);
}
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
Private ReadOnly _pool As ObjectPool(Of IReductionRewriter)
Protected CancellationToken As CancellationToken
Private _parseOptions As ParseOptions
Private _simplificationOptions As OptionSet
Private ReadOnly _processedParentNodes As HashSet(Of SyntaxNode) = New HashSet(Of SyntaxNode)()
......@@ -26,12 +27,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
_pool = pool
End Sub
Public Sub Initialize(optionSet As OptionSet, cancellationToken As CancellationToken) Implements IReductionRewriter.Initialize
Public Sub Initialize(parseOptions As ParseOptions, optionSet As OptionSet, cancellationToken As CancellationToken) Implements IReductionRewriter.Initialize
_parseOptions = parseOptions
_simplificationOptions = optionSet
cancellationToken = cancellationToken
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
_parseOptions = Nothing
_simplificationOptions = Nothing
CancellationToken = CancellationToken.None
_processedParentNodes.Clear()
......
......@@ -19,8 +19,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities
''' the syntax replacement doesn't break the semantics of any parenting nodes of the original expression.
''' </summary>
Friend Class SpeculationAnalyzer
Inherits AbstractSpeculationAnalyzer(Of SyntaxNode, ExpressionSyntax, TypeSyntax, AttributeSyntax,
ArgumentSyntax, ForEachStatementSyntax, ThrowStatementSyntax, SemanticModel, Conversion)
Inherits AbstractSpeculationAnalyzer(Of
ExpressionSyntax,
TypeSyntax,
AttributeSyntax,
ArgumentSyntax,
ForEachStatementSyntax,
ThrowStatementSyntax,
Conversion)
''' <summary>
''' Creates a semantic analyzer for speculative syntax replacement.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册