Skip to content

soft-select select camelcase matched item if user might be typing an …#80809

Merged
genlu merged 4 commits intodotnet:mainfrom
genlu:FixSpeculativeTSelection
Oct 20, 2025
Merged

soft-select select camelcase matched item if user might be typing an …#80809
genlu merged 4 commits intodotnet:mainfrom
genlu:FixSpeculativeTSelection

Conversation

@genlu
Copy link
Member

@genlu genlu commented Oct 18, 2025

…undefined type parameter

Fix #75651

@genlu genlu requested a review from a team as a code owner October 18, 2025 01:18
if (string.IsNullOrEmpty(text))
return false;

// Pattern: starts with 'T', and optionally followed by an uppercase letter
Copy link
Contributor

Choose a reason for hiding this comment

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

perhaps mention this is just a weak heuristic. But it helps given general .Net naming patterns.


spanStart = WalkOutOfGenericType(syntaxTree, spanStart, semanticModel, cancellationToken);
spanStart = WalkOutOfTupleType(syntaxTree, spanStart, cancellationToken);
spanStart = WalkOutOfRefType(syntaxTree, spanStart, cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

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

if you make these helpers into local functions, you can just rewrite this as:

spanStart = WalkOutOfGeneric(WalkOutOfTuple(WalkOutOfRef(spanStart)))

}
}

public static bool IsSpeculativeTypeParameterContext(SyntaxTree syntaxTree, int position, SemanticModel? semanticModel, bool inMemberDeclarationOnly, CancellationToken cancellationToken)
Copy link
Contributor

Choose a reason for hiding this comment

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

can you put a doc comment on what a 'Speculative type parameter context' is? at first i thought this was about SpecultiveSemanticModels :)

syntaxTree.IsGlobalMemberDeclarationContext(spanStart, SyntaxKindSet.AllGlobalMemberModifiers, cancellationToken) ||
(!inMemberDeclarationOnly && (syntaxTree.IsStatementContext(spanStart, token, cancellationToken) ||
syntaxTree.IsGlobalStatementContext(spanStart, cancellationToken) ||
syntaxTree.IsDelegateReturnTypeContext(spanStart, token)));
Copy link
Contributor

Choose a reason for hiding this comment

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

consider breaking these into individual statements.

Copy link
Contributor

Choose a reason for hiding this comment

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

with examples for each.

Copy link
Contributor

Choose a reason for hiding this comment

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

i'm finding the !inMemberDeclarationOnly portion of this hard to read/rerason out. please break out and doc.

}

return position;
return CompletionUtilities.IsSpeculativeTypeParameterContext(syntaxTree, position, context.SemanticModel, inMemberDeclarationOnly: false, cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

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

why the 'false' for 'inMemberDeclarationOnly'

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it is less likely that someone is trying to type an undeclared type parameter when they are inside method body. It is fine to provide a speculative T item there, since typing 2 characters would filter it out, but for selection, I'd want TypeBuilder to be hard selected here

public Foo()
{
    TB%%
}


internal override async Task<bool> IsSpeculativeTypeParameterContextAsync(Document document, int position, CancellationToken cancellationToken)
{
var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

doc why 'true' for inMemberDeclarationOnly

internal override async Task<bool> IsSpeculativeTypeParameterContextAsync(Document document, int position, CancellationToken cancellationToken)
{
var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
return CompletionUtilities.IsSpeculativeTypeParameterContext(syntaxTree, position, semanticModel: null, inMemberDeclarationOnly: true, cancellationToken);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: getting a semantic model is cheap. just get the semantic model here, and pass that into the helper. the helper doesn't need to take the syntaxTree then.

Copy link
Member Author

Choose a reason for hiding this comment

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

Discussed offline, keeping it as is because we'd need a frozen partial doc otherwise

@CyrusNajmabadi
Copy link
Contributor

overall i'm totally fine with this. a nd i recognize you're moving existing code. but some parts are a bit confusing. so i'd love some docs/refinement.

@genlu genlu enabled auto-merge (squash) October 20, 2025 21:25
@genlu genlu merged commit 3b5303b into dotnet:main Oct 20, 2025
24 of 25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 20, 2025
@genlu genlu deleted the FixSpeculativeTSelection branch October 20, 2025 23:53
333fred added a commit to 333fred/roslyn that referenced this pull request Oct 22, 2025
* upstream/main: (123 commits)
  Fix SafeContext of Span-valued collection expressions to match specification (dotnet#80684)
  Improve detection of invalid references for implicitly typed expression variables declared within implicit object creation expressions. (dotnet#80546)
  Add test demonstrating behavior of ToMinimalDisplayString. (dotnet#80757)
  Only set DOTNET_HOST_PATH if something was installed (dotnet#80842)
  Clean up a Razor external access service (dotnet#80830)
  Remove unused statement (dotnet#80823)
  Allow foreach on typed null enumerables (dotnet#80783)
  Update documentation for DeclaringSyntaxReferences and Locations to clarify partial members behavior (dotnet#80704)
  Fix issue converting an auto prop to a full prop when 'field' and 'initializers' are involved
  Rename childIsSimple to innerExpressionHasPrimaryPrecedence and add more test cases
  Remove placeholder WorkItem attributes from new tests
  Fix RemoveUnnecessaryParentheses to detect simple expressions in bitwise operations
  [main] Update dependencies from dotnet/arcade (dotnet#80828)
  Fix ITypeSymbol.BaseType documentation for type parameters (dotnet#80770)
  soft-select select camelcase matched item if user might be typing an undefined type parameter (dotnet#80809)
  Allow semantic tokens in Razor to be better behaved (dotnet#80815)
  Rebase
  Remove using
  Update test
  Add fix all test
  ...
@davidwengier davidwengier modified the milestones: Next, 18.3 Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

completion make it hard to use an undeclared generic type parameter as return value

3 participants