Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
afa9592
Do not do full cleanup when we are formatting a new document
jasonmalinowski Jul 22, 2025
d3f2156
Allow captured primary constructor parameters to be still used in bas…
CyrusNajmabadi Jul 22, 2025
7be4c96
Fix 'this' keyword not being recomended where allowed
CyrusNajmabadi Jul 22, 2025
a3b39e8
in progress
CyrusNajmabadi Jul 22, 2025
078829b
Fix 'switch' keyword recomendations after an expression
CyrusNajmabadi Jul 22, 2025
6d868d2
Fix escaping of enum members in completion
CyrusNajmabadi Jul 22, 2025
5804e6b
Suggest proper 'Async'-suffixed name for Task-returning symbols
CyrusNajmabadi Jul 22, 2025
bc6cf84
Suggest proper 'Async'-suffixed name for Task-returning symbols (#79518)
CyrusNajmabadi Jul 22, 2025
4e6c46b
Fix escaping of enum members in completion (#79516)
CyrusNajmabadi Jul 22, 2025
c765c39
Do not do full cleanup when we are formatting a new document (#79508)
jasonmalinowski Jul 22, 2025
f5f17a7
Fix 'switch' keyword recomendations after an expression (#79515)
CyrusNajmabadi Jul 22, 2025
be70cf4
Allow captured primary constructor parameters to be still used in bas…
CyrusNajmabadi Jul 22, 2025
e85d47f
Fix auth issue in PR val builds
dibarbet Jul 22, 2025
5e104ee
Merge remote-tracking branch 'upstream/main' into thisInNameof
CyrusNajmabadi Jul 22, 2025
f8f433b
Fix
CyrusNajmabadi Jul 22, 2025
dfdacfd
Prevent auth issue in PR val builds (#79524)
dibarbet Jul 22, 2025
63bb7cb
Fix 'this' keyword not being recomended where allowed (#79514)
CyrusNajmabadi Jul 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions azure-pipelines-pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,28 +165,6 @@ extends:
displayName: Setting SourceBranchName variable
condition: succeeded()

- task: Powershell@2
name: FancyBuild
displayName: Setting FancyBuild.BuildNumber
inputs:
targetType: inline
script: |
$pull_request = Invoke-RestMethod -Uri "https://api.github.com/repos/dotnet/roslyn/pulls/${{ parameters.PRNumber }}" `
-Headers @{
"Accept" = "application/vnd.github+json";
"X-GitHub-Api-Version" = "2022-11-28"
}
$buildNumberName = "$(OriginalBuildNumber) - $($pull_request.user.login) - '$($pull_request.title)'"
$buildNumberName = $buildNumberName -replace '["/:<>\|?@*]','_'
# Maximum buildnumber length is 255 chars and we are going to append to the end to ensure we have space.
if ($buildNumberName.Length -GT 253) {
$buildNumberName = $buildNumberName.Substring(0, 253)
}
# Avoid ever ending the BuildNumber with a `.` by always appending to it.
$buildNumberName += ' #'
Write-Host "##vso[task.setvariable variable=BuildNumber;isoutput=true;isreadonly=true]$buildNumberName"
Write-Host "##vso[build.updatebuildnumber]$buildNumberName"

- task: Powershell@2
displayName: Tag PR validation build
inputs:
Expand All @@ -204,6 +182,25 @@ extends:
arguments: "-sourceBranchName $(SourceBranchName) -prNumber ${{ parameters.PRNumber }} -commitSHA ${{ parameters.CommitSHA }} -enforceLatestCommit ${{ iif(parameters.EnforceLatestCommit, '1', '0') }}"
condition: succeeded()

- task: Powershell@2
name: FancyBuild
displayName: Setting FancyBuild.BuildNumber
inputs:
targetType: inline
script: |
$authorName = git log -1 --pretty=format:"%an" ${{ parameters.CommitSHA }}

$buildNumberName = "$(OriginalBuildNumber) - $($authorName) - '${{ parameters.PRNumber }}'"
$buildNumberName = $buildNumberName -replace '["/:<>\|?@*]','_'
# Maximum buildnumber length is 255 chars and we are going to append to the end to ensure we have space.
if ($buildNumberName.Length -GT 253) {
$buildNumberName = $buildNumberName.Substring(0, 253)
}
# Avoid ever ending the BuildNumber with a `.` by always appending to it.
$buildNumberName += ' #'
Write-Host "##vso[task.setvariable variable=BuildNumber;isoutput=true;isreadonly=true]$buildNumberName"
Write-Host "##vso[build.updatebuildnumber]$buildNumberName"

- powershell: Write-Host "##vso[task.setvariable variable=VisualStudio.DropName]Products/$(System.TeamProject)/$(Build.Repository.Name)/$(SourceBranchName)/$(OriginalBuildNumber)"
displayName: Setting VisualStudio.DropName variable

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,10 @@ async Task<C> $$
}
""", "GetCAsync");

[Fact(Skip = "not yet implemented")]
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17989")]
public Task NonAsyncTaskOfT()
=> VerifyItemExistsAsync("""
using System.Threading.Tasks;
public class C
{
Task<C> $$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,19 @@ void M(object o)
}
}
""");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78800")]
public Task TestAfterReturnExpression()
=> VerifyKeywordAsync(
"""
class C
{
public static string EvaluateRangeVariable()
{
return RandomValue() $$
}

public int RandomValue() => 0;
}
""");
}
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,19 @@ void M(object o)
}
}
""");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78800")]
public Task TestAfterReturnExpression()
=> VerifyKeywordAsync(
"""
class C
{
public static string EvaluateRangeVariable()
{
return RandomValue() $$
}

public int RandomValue() => 0;
}
""");
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ internal async Task VerifyKeywordAsync(
await VerifyWorkerAsync(text, absent: false, options: scriptOptions ?? Options.Script);
}

protected async Task VerifyKeywordAsync(SourceCodeKind kind, string text)
protected async Task VerifyKeywordAsync(
SourceCodeKind kind,
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string text)
{
switch (kind)
{
Expand Down Expand Up @@ -211,7 +213,9 @@ protected async Task VerifyAbsenceAsync(
}
}

protected static string AddInsideMethod(string text, bool isAsync = false, string returnType = "void", bool topLevelStatement = false)
protected static string AddInsideMethod(
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string text,
bool isAsync = false, string returnType = "void", bool topLevelStatement = false)
{
if (topLevelStatement)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public sealed class SwitchKeywordRecommenderTests : KeywordRecommenderTests
[Fact]
public Task TestAtRoot_Interactive()
=> VerifyKeywordAsync(SourceCodeKind.Script,
@"$$");
@"$$");

[Fact]
public Task TestAfterClass_Interactive()
Expand Down Expand Up @@ -44,17 +44,17 @@ public Task TestAfterGlobalVariableDeclaration_Interactive()
[Fact]
public Task TestNotInUsingAlias()
=> VerifyAbsenceAsync(
@"using Goo = $$");
@"using Goo = $$");

[Fact]
public Task TestNotInGlobalUsingAlias()
=> VerifyAbsenceAsync(
@"global using Goo = $$");
@"global using Goo = $$");

[Fact]
public Task TestEmptyStatement()
=> VerifyKeywordAsync(AddInsideMethod(
@"$$"));
@"$$"));

[Fact]
public Task TestBeforeStatement()
Expand Down Expand Up @@ -93,7 +93,7 @@ public Task TestInsideSwitchBlock()
[Fact]
public Task TestNotAfterSwitch1()
=> VerifyAbsenceAsync(AddInsideMethod(
@"switch $$"));
@"switch $$"));

[Fact]
public async Task TestAfterExpression()
Expand All @@ -119,7 +119,7 @@ public async Task TestAfterTuple()
[Fact]
public Task TestNotAfterSwitch2()
=> VerifyAbsenceAsync(AddInsideMethod(
@"switch ($$"));
@"switch ($$"));

[Fact]
public Task TestNotInClass()
Expand Down Expand Up @@ -267,4 +267,19 @@ void M(object o)
}
}
""");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78800")]
public Task TestAfterReturnExpression()
=> VerifyKeywordAsync(
"""
class C
{
public static string EvaluateRangeVariable()
{
return RandomValue() $$
}

public int RandomValue() => 0;
}
""");
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,19 @@ void M(object o)
}
}
""");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78800")]
public Task TestAfterReturnExpression()
=> VerifyKeywordAsync(
"""
class C
{
public static string EvaluateRangeVariable()
{
return RandomValue() $$
}

public int RandomValue() => 0;
}
""");
}
Original file line number Diff line number Diff line change
Expand Up @@ -2929,6 +2929,39 @@ namespace B
End Using
End Function

<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
<WorkItem("https://github.com/dotnet/roslyn/issues/77606")>
Public Async Function CompletionEnumTypeAndValues_Escaped() As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document>
namespace A
{
public enum Colors
{
@int,
@string
}
}
namespace B
{
class Program
{
static void Main(A.Colors c)
{
switch (c)
{
case $$
}
}
} </Document>)
state.SendInvokeCompletionList()
Await state.AssertCompletionItemsContain(Function(i) i.DisplayText = "A.Colors" AndAlso i.FilterText = "Colors")
Await state.AssertCompletionItemsContain(Function(i) i.DisplayText = "A.Colors.@int" AndAlso i.FilterText = "A.Colors.@int")
Await state.AssertCompletionItemsContain(Function(i) i.DisplayText = "A.Colors.@string" AndAlso i.FilterText = "A.Colors.@string")
Await state.AssertSelectedCompletionItem("A.Colors", isHardSelected:=True)
End Using
End Function

<WorkItem("https://github.com/dotnet/roslyn/pull/49632")>
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CompletionEnumTypeSelectionSequenceTest() As Task
Expand Down Expand Up @@ -11931,6 +11964,27 @@ public class C(int x) : Base(x)
End Using
End Function

<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/78917")>
Public Async Function FilterPrimaryConstructorParameters_AllowInBaseTypeWhenCapturedAsMember() As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
public sealed class Derived(
string value)
: Base($"{val$$}")
{
public string Value { get; } = value;
}

public abstract class Base(string value);
]]>
</Document>,
languageVersion:=LanguageVersion.CSharp12)

state.SendInvokeCompletionList()
Await state.AssertCompletionItemsContain("value", displayTextSuffix:="")
End Using
End Function

<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestItemsSorted() As Task
Using state = TestStateFactory.CreateCSharpTestState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC
var sortValue = 0;
foreach (var recommender in Recommenders)
{
var names = await recommender.Value.ProvideRecommendedNamesAsync(completionContext, document, context, nameInfo, cancellationToken).ConfigureAwait(false);
var names = await recommender.Value.ProvideRecommendedNamesAsync(
completionContext, document, context, nameInfo, cancellationToken).ConfigureAwait(false);

foreach (var (name, glyph) in names)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ private static bool IsPropertyDeclaration(SyntaxToken token, SemanticModel seman
return result.Type != null;
}

private static bool IsMethodDeclaration(SyntaxToken token, SemanticModel semanticModel,
CancellationToken cancellationToken, out NameDeclarationInfo result)
private static bool IsMethodDeclaration(
SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken, out NameDeclarationInfo result)
{
result = IsLastTokenOfType<MethodDeclarationSyntax>(
token,
Expand All @@ -220,45 +220,30 @@ private static NameDeclarationInfo IsFollowingTypeOrComma<TSyntaxNode>(
Func<DeclarationModifiers, ImmutableArray<SymbolKindOrTypeKind>> possibleDeclarationComputer,
CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode
{
if (!IsPossibleTypeToken(token) && !token.IsKind(SyntaxKind.CommaToken))
{
var afterComma = token.IsKind(SyntaxKind.CommaToken);
if (!IsPossibleTypeToken(token) && !afterComma)
return default;
}

var target = token.GetAncestor<TSyntaxNode>();
if (target == null)
{
return default;
}

if (token.IsKind(SyntaxKind.CommaToken) && token.Parent != target)
{
if (afterComma && token.Parent != target)
return default;
}

var typeSyntax = typeSyntaxGetter(target);
if (typeSyntax == null)
{
return default;
}

if (!token.IsKind(SyntaxKind.CommaToken) && token != typeSyntax.GetLastToken())
{
if (!afterComma && token != typeSyntax.GetLastToken())
return default;
}

var modifiers = modifierGetter(target);
if (modifiers == null)
{
return default;
}

return new NameDeclarationInfo(
possibleDeclarationComputer(GetDeclarationModifiers(modifiers.Value)),
GetAccessibility(modifiers.Value),
GetDeclarationModifiers(modifiers.Value),
semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type,
semanticModel.GetAliasInfo(typeSyntax, cancellationToken));
return ComputeInfo(
semanticModel, possibleDeclarationComputer, typeSyntax, modifiers.Value, tryInferAsync: !afterComma, cancellationToken);
}

private static NameDeclarationInfo IsLastTokenOfType<TSyntaxNode>(
Expand Down Expand Up @@ -295,11 +280,36 @@ private static NameDeclarationInfo IsLastTokenOfType<TSyntaxNode>(

var modifiers = modifierGetter(target);

return ComputeInfo(semanticModel, possibleDeclarationComputer, typeSyntax, modifiers, tryInferAsync: true, cancellationToken);
}

private static NameDeclarationInfo ComputeInfo(
SemanticModel semanticModel,
Func<DeclarationModifiers, ImmutableArray<SymbolKindOrTypeKind>> possibleDeclarationComputer,
SyntaxNode typeSyntax,
SyntaxTokenList modifiers,
bool tryInferAsync,
CancellationToken cancellationToken)
{
var declarationModifiers = GetDeclarationModifiers(modifiers);
var possibleDeclarations = possibleDeclarationComputer(declarationModifiers);

// Treat a declaration as async if if it is explicitly marked as 'async' or if it is a method that returns a
// Task-like type. The latter ensures that even if the user didn't have an explicit 'async' modifier, we still
// name the member in an appropriate fashion (e.g. `GetCustomerAsync` for `public Task<Customer> $$`).
var type = semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type;
if (!declarationModifiers.IsAsync && tryInferAsync)
{
var knownTaskTypes = new KnownTaskTypes(semanticModel.Compilation);
if (knownTaskTypes.IsTaskLike(type))
declarationModifiers = declarationModifiers.WithAsync(true);
}

return new NameDeclarationInfo(
possibleDeclarationComputer(GetDeclarationModifiers(modifiers)),
possibleDeclarations,
GetAccessibility(modifiers),
GetDeclarationModifiers(modifiers),
semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type,
declarationModifiers,
type,
semanticModel.GetAliasInfo(typeSyntax, cancellationToken));
}

Expand Down
Loading
Loading