Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add inferred type name hints #118

Open
wants to merge 58 commits into
base: net211
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ea0c37b
Update InferredTypeCodeVisionProvider.fs
saul Mar 30, 2020
cef15fa
Split into PipeChainCodeVisionProvider
saul Mar 30, 2020
c60867a
Create Multi line.fs.gold
saul Mar 30, 2020
73c12bb
Hook into the tooltip for the |> operator
saul Mar 30, 2020
ff0b40c
Update Multi line.fs.gold
saul Mar 30, 2020
88520c1
Add TypeHintsAdornmentProvider
saul Mar 30, 2020
c12814b
Update TypeHintsAdornmentProvider.fs
saul Mar 30, 2020
b224f68
Update TypeHintsAdornmentProvider.fs
saul Mar 30, 2020
9521a2e
Markups
saul Mar 30, 2020
d67e92c
Update TypeHintsAdornmentProvider.fs
saul Mar 30, 2020
61d3ef3
Add more tests
saul Mar 30, 2020
69145e5
Add new lines
saul Mar 30, 2020
1fa07ac
Add setting
saul Mar 31, 2020
37465f6
Update TypeHintAdornmentStage.fs
saul Mar 31, 2020
cc23ca5
Add option to 'Hide when |> is on same line as argument'
saul Apr 1, 2020
89808fe
Invalidate highlighting on type hint setting change
saul Apr 1, 2020
6a33f80
Update TypeHintAdornmentStage.fs
saul Apr 1, 2020
0418681
Update TypeHintAdornmentStage.fs
saul Apr 2, 2020
6c03c7c
Use {HideSameLine:All} in tests
saul Apr 2, 2020
2312f7b
Add InferredTypeHintHighlightingProcess
saul Apr 2, 2020
be94166
Reorganisation
saul Apr 2, 2020
a718242
Delete ReSharper.FSharp.sln.DotSettings.user
saul Apr 2, 2020
1b7ab5c
Merge branch 'net201-pipe-chain-insight' into net201-local-ref-pat-hints
saul Apr 2, 2020
1e49dea
Add tests
saul Apr 2, 2020
7647371
Put && on end of life
saul Apr 2, 2020
6e15e68
Code style
saul Apr 2, 2020
cf32c8f
Merge branch 'net201-pipe-chain-insight' into net201-local-ref-pat-hints
saul Apr 2, 2020
d2ab70e
Update InferredTypeHintStage.fs
saul Apr 2, 2020
778d7d1
More code style changes
saul Apr 2, 2020
780727d
Merge branch 'net201-pipe-chain-insight' into net201-local-ref-pat-hints
saul Apr 2, 2020
3c65b47
Merge remote-tracking branch 'upstream/net202' into net201-local-ref-…
saul Apr 29, 2020
98615c5
Merge remote-tracking branch 'upstream/net202' into net201-pipe-chain…
saul Apr 29, 2020
6dfe786
Markups
saul Apr 29, 2020
054b671
Merge branch 'net201-pipe-chain-insight' into net201-local-ref-pat-hints
saul Apr 29, 2020
008009b
Markups, add more tests
saul Apr 29, 2020
59d94b7
Add parameter name hints
saul Apr 29, 2020
e955162
Resolve todo
saul Apr 29, 2020
f26344d
Merge branch 'net202-parameter-name-hints' into net201-local-ref-pat-…
saul Apr 29, 2020
28c1297
Merge remote-tracking branch 'upstream/net202' into net201-local-ref-…
saul Apr 29, 2020
1353ac8
Revert "Merge branch 'net202-parameter-name-hints' into net201-local-…
saul Apr 29, 2020
8899fa6
Un-Fantomas
saul Apr 29, 2020
1c60fea
Delete accidentally committed file
saul Apr 29, 2020
7b7b052
Merge remote-tracking branch 'upstream/net202' into net201-local-ref-…
saul May 17, 2020
944627f
Hook into 'Type Name Hints' settings
saul May 23, 2020
f723c6a
Add more tests
saul May 23, 2020
91e6d5d
Add object expression and cast expression to tests
saul May 23, 2020
fc520a6
Merge remote-tracking branch 'upstream/net202' into net201-local-ref-…
saul May 23, 2020
7ed7095
Schedule hint-related stages after other long-running ones
auduchinok May 25, 2020
b66b010
Minor cleanup
auduchinok May 25, 2020
887b7df
Merge remote-tracking branch 'upstream/net202' into net201-local-ref-…
saul Jun 10, 2020
179406c
Markups
saul Jun 10, 2020
8b9dda5
Cleanup, safer getting pattern name
auduchinok Jun 11, 2020
296bcf6
Fix tests
auduchinok Jun 16, 2020
85c88a8
Merge remote-tracking branch 'upstream/net203' into net201-local-ref-…
saul Sep 30, 2020
9ff226e
API changes
saul Sep 30, 2020
e66d1da
Merge branch 'net203' into net201-local-ref-pat-hints
saul Oct 20, 2020
d767173
Merge branch 'net211' into net201-local-ref-pat-hints
auduchinok Jan 25, 2021
854a201
Update for newer APIs
auduchinok Jan 27, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ type FSharpScriptOptionsProvider(lifetime: Lifetime, settings: IContextBoundSett
member val CustomDefines = settings.GetValueProperty(lifetime, fun s -> s.CustomDefines)



module FSharpTypeHintOptions =
let [<Literal>] pipeReturnTypes = "Show return type hints in |> chains"

Expand Down Expand Up @@ -91,7 +90,7 @@ type FSharpOptionsPage
this.AddComboEnum((fun key -> key.LanguageVersion), FSharpScriptOptions.languageVersion, FSharpLanguageVersion.toString) |> ignore

this.AddHeader("Type hints")
let showPipeReturnTypes = this.AddBoolOption((fun key -> key.ShowPipeReturnTypes), RichText(FSharpTypeHintOptions.pipeReturnTypes), null)
this.AddBoolOption((fun key -> key.ShowPipeReturnTypes), RichText(FSharpTypeHintOptions.pipeReturnTypes), null) |> ignore
do
use _x = this.Indent()
[
Expand All @@ -100,7 +99,7 @@ type FSharpOptionsPage
|> Seq.iter (fun checkbox ->
this.AddBinding(checkbox, BindingStyle.IsEnabledProperty, (fun key -> key.ShowPipeReturnTypes), id)
)

this.AddHeader("FSharp.Compiler.Service options")
this.AddBoolOption((fun key -> key.BackgroundTypeCheck), RichText(backgroundTypeCheck), null) |> ignore

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<Compile Include="src\Daemon\Stages\FSharpVcsCodeVisionRangesProviderStage.fs" />
<Compile Include="src\Daemon\Stages\FSharpErrorsStage.fs" />
<Compile Include="src\Daemon\Stages\PipeChainTypeHintStage.fs" />
<Compile Include="src\Daemon\Stages\InferredTypeHintStage.fs" />
<Compile Include="src\Daemon\Stages\InferredTypeCodeVisionProvider.fs" />
<Compile Include="src\Daemon\Stages\FSharpSyntaxHighlightingStage.fs" />
<Compile Include="src\Daemon\UsageChecking\FSharpUsageCheckingService.fs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Stages

open System
open JetBrains.Application.Settings
open JetBrains.ProjectModel
open JetBrains.ReSharper.Daemon.Stages
open JetBrains.ReSharper.Feature.Services.InlayHints
open JetBrains.ReSharper.Feature.Services.TypeNameHints
open JetBrains.ReSharper.Plugins.FSharp
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Util
open JetBrains.ReSharper.Plugins.FSharp.Psi.Util
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Highlightings
open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.Naming
open JetBrains.ReSharper.Psi.Naming.Impl
open JetBrains.ReSharper.Psi.Tree
open JetBrains.ReSharper.Psi.Util
open JetBrains.ReSharper.Feature.Services.Daemon
open JetBrains.ReSharper.Plugins.FSharp.Daemon.Cs.Stages
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open FSharp.Compiler.SourceCodeServices

type LocalReferencePatternVisitor(fsFile: IFSharpFile, highlightingContext: TypeNameHintHighlightingContext, namingPolicyProvider, nameParser) =
inherit TreeNodeVisitor<IHighlightingConsumer>()

let isTypeEvidentFromVariableNamePrefix (typ: IType) (variableNameParts: string[]) =
if not (typ.IsBool()) then false else

if variableNameParts.Length > 0 then
let prefix = variableNameParts.[0].ToLowerInvariant()
prefix = "has" || prefix = "is"
else
false

let isEvidentFromVariableName (fsType: FSharpType) variableName =
if not highlightingContext.HideTypeNameHintsWhenTypeNameIsEvidentFromVariableName then false else

let typ = fsType.MapType(Array.empty, fsFile.GetPsiModule())
if not (typ.IsValid()) then false else

let variableNameParts = NamesHelper.GetParts(nameParser, namingPolicyProvider, variableName)
if isTypeEvidentFromVariableNamePrefix typ variableNameParts then true else

match typ.GetTypeElement() with
| null -> false
| typeElement ->

let typeName = typeElement.ShortName
String.Equals(typeName, variableName, StringComparison.OrdinalIgnoreCase) ||
not (String.IsNullOrEmpty(typeName)) &&
not (String.IsNullOrEmpty(variableName)) &&
NamesHelper.IsLike(variableNameParts, NamesHelper.GetParts(nameParser, namingPolicyProvider, typeName))

let isTypeOfPatternEvident (pattern: ISynPat) =

// v-- not evident
// x::y::z
// ^--^-- evident
let tuplePat = TuplePatNavigator.GetByPattern pattern
if isNotNull tuplePat then
let consPat = ConsPatNavigator.GetByPattern1 tuplePat
if isNull consPat then false else

// Are we nested inside another ConsPat?
let parentTuplePat = TuplePatNavigator.GetByPattern consPat
if isNull parentTuplePat then tuplePat.Patterns.IndexOf pattern <> 0 else
isNotNull (ConsPatNavigator.GetByPattern1 parentTuplePat)

else

// v-- not evident
// [x; y; z]
// ^--^-- evident
let listOrListPat = ArrayOrListPatNavigator.GetByPattern pattern
if isNotNull listOrListPat then
listOrListPat.Patterns.IndexOf pattern <> 0
saul marked this conversation as resolved.
Show resolved Hide resolved

else

false

override x.VisitNode(node, context) =
for child in node.Children() do
match child with
| :? IFSharpTreeNode as treeNode -> treeNode.Accept(x, context)
| _ -> ()

override x.VisitLocalReferencePat(localRefPat, consumer) =
let pat = localRefPat.IgnoreParentParens()
if isNotNull (TypedPatNavigator.GetByPattern(pat)) then () else

let binding = BindingNavigator.GetByHeadPattern(pat)
if isNotNull binding && isNotNull binding.ReturnTypeInfo then () else

if isTypeOfPatternEvident pat then () else

match box (localRefPat.GetFSharpSymbolUse()) with
| null -> ()
| symbolUse ->

let symbolUse = symbolUse :?> FSharpSymbolUse
match symbolUse.Symbol with
| :? FSharpMemberOrFunctionOrValue as mfv when not (isEvidentFromVariableName mfv.FullType localRefPat.ReferenceName.Identifier.Name) ->
saul marked this conversation as resolved.
Show resolved Hide resolved
let typeNameStr =
symbolUse.DisplayContext.WithShortTypeNames(true)
|> mfv.FullType.Format

let range = localRefPat.GetNavigationRange().EndOffsetRange()

// todo: TypeNameHintHighlighting can be used when RIDER-39605 is resolved
consumer.AddHighlighting(TypeHintHighlighting(typeNameStr, range))
| _ -> ()

type InferredTypeHintHighlightingProcess(fsFile, settings: IContextBoundSettingsStore, highlightingContext: TypeNameHintHighlightingContext, namingManager: NamingManager, nameParser: NameParser, daemonProcess) =
inherit FSharpDaemonStageProcessBase(fsFile, daemonProcess)

let namingPolicyProvider = namingManager.Policy.GetPolicyProvider(fsFile.Language, fsFile.GetSourceFile())

let visitor = LocalReferencePatternVisitor(fsFile, highlightingContext, namingPolicyProvider, nameParser)

let visitLetBindings (letBindings: ILetBindings) consumer =
if not highlightingContext.ShowTypeNameHintsForImplicitlyTypedVariables then () else

for binding in letBindings.Bindings do
if highlightingContext.HideTypeNameHintsForImplicitlyTypedVariablesWhenTypeIsEvident && isTypeEvident binding.Expression then () else
binding.HeadPattern.Accept(visitor, consumer)
saul marked this conversation as resolved.
Show resolved Hide resolved

override x.Execute(committer) =
let consumer = FilteringHighlightingConsumer(daemonProcess.SourceFile, fsFile, settings)
fsFile.ProcessThisAndDescendants(Processor(x, consumer))
committer.Invoke(DaemonStageResult(consumer.Highlightings))

override x.VisitLetModuleDecl(moduleDecl, consumer) =
visitLetBindings moduleDecl consumer

override x.VisitLetOrUseExpr(letOrUseExpr, consumer) =
visitLetBindings letOrUseExpr consumer

override x.VisitMemberParamDeclaration(paramDecl, consumer) =
// todo: do we need another setting for this?
if highlightingContext.ShowTypeNameHintsForImplicitlyTypedVariables then
paramDecl.Pattern.Accept(visitor, consumer)
saul marked this conversation as resolved.
Show resolved Hide resolved

override x.VisitMatchClause(matchClause, consumer) =
if highlightingContext.ShowTypeNameHintsForVarDeclarationsInPatternMatchingExpressions then
matchClause.Pattern.Accept(visitor, consumer)

override x.VisitLambdaExpr(lambdaExpr, consumer) =
if not highlightingContext.ShowTypeNameHintsForLambdaExpressionParameters then () else

for pattern in lambdaExpr.Patterns do
pattern.Accept(visitor, consumer)

[<DaemonStage(StagesBefore = [| typeof<GlobalFileStructureCollectorStage> |])>]
type InferredTypeHintStage(namingManager: NamingManager, nameParser: NameParser) =
inherit FSharpDaemonStageBase()

override x.IsSupported(sourceFile, processKind) =
processKind = DaemonProcessKind.VISIBLE_DOCUMENT &&
base.IsSupported(sourceFile, processKind) &&
not (sourceFile.LanguageType.Is<FSharpSignatureProjectFileType>())

override x.CreateStageProcess(fsFile, settings, daemonProcess) =
let highlightingContext = TypeNameHintHighlightingContext(settings)
let isEnabled =
highlightingContext.ShowTypeNameHintsForImplicitlyTypedVariables ||
highlightingContext.ShowTypeNameHintsForLambdaExpressionParameters ||
highlightingContext.ShowTypeNameHintsForVarDeclarationsInPatternMatchingExpressions

if not isEnabled then null else
InferredTypeHintHighlightingProcess(fsFile, settings, highlightingContext, namingManager, nameParser, daemonProcess) :> _
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,18 @@ let setBindingExpression (expr: IFSharpExpression) contextIndent (letBindings: #
ModificationUtil.AddChildBefore(newExpr, NewLine(expr.GetLineEnding())) |> ignore
ModificationUtil.AddChildBefore(newExpr, Whitespace(contextIndent + indentSize)) |> ignore
shiftExpr indentSize newExpr

let rec isTypeEvident (expr: IFSharpExpression) =
match expr.IgnoreInnerParens() with
| :? IObjExpr
| :? ICastExpr
| :? ILambdaExpr
| :? ILiteralExpr -> true
| :? ITupleExpr as tupleExpr ->
tupleExpr.Expressions |> Seq.forall isTypeEvident
| :? IArrayOrListExpr as arrayOrListExpr ->
match arrayOrListExpr.Expression with
| :? ISequentialExpr as seqExpr ->
isTypeEvident (seqExpr.Expressions.FirstOrDefault())
| _ -> false
| _ -> false
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let add () =
"hello there"

let l = fun () -> "hello there"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
let add () =
"hello there"

let l = fun () -> "hello there"

---------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let add x y =
x + y

let x = fun x y -> x + y
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ShowTypeNameHintsForLambdaExpressionParameters = True
let add x||(0) y||(1) =
x + y

let x = fun x||(2) y||(3) -> x + y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int
(2): ReSharper Parameter Name Hint: : int
(3): ReSharper Parameter Name Hint: : int

================
ShowTypeNameHintsForLambdaExpressionParameters = False
let add x||(0) y||(1) =
x + y

let x = fun x y -> x + y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let add x y =
15 + y

let l = fun x y -> 15 + y
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
let add x||(0) y||(1) =
15 + y

let l = fun x||(2) y||(3) -> 15 + y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : 'a
(1): ReSharper Parameter Name Hint: : int
(2): ReSharper Parameter Name Hint: : 'a
(3): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let add (x, y) =
x + y

let l = fun (x, y) -> x + y
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
let add (x||(0), y||(1)) =
x + y

let l = fun (x||(2), y||(3)) -> x + y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int
(2): ReSharper Parameter Name Hint: : int
(3): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let subtract x (y : int) =
x - y

let l = fun x (y: int) -> x - y
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ShowTypeNameHintsForImplicitlyTypedVariables = True
let subtract x||(0) (y : int) =
x - y

let l = fun x||(1) (y: int) -> x - y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int

================
ShowTypeNameHintsForImplicitlyTypedVariables = False
let subtract x (y : int) =
x - y

let l = fun x||(0) (y: int) -> x - y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let subtract (x: int, y) =
x - y

let l = fun (x: int, y) -> x - y
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ShowTypeNameHintsForImplicitlyTypedVariables = True
let subtract (x: int, y||(0)) =
x - y

let l = fun (x: int, y||(1)) -> x - y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int

================
ShowTypeNameHintsForImplicitlyTypedVariables = False
let subtract (x: int, y) =
x - y

let l = fun (x: int, y||(0)) -> x - y

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let hello () =
let localFunc x y = x + y
let l = fun x y -> x + y
()
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
let hello () =
let localFunc x||(0) y||(1) = x + y
let l = fun x||(2) y||(3) -> x + y
()

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
(1): ReSharper Parameter Name Hint: : int
(2): ReSharper Parameter Name Hint: : int
(3): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let call f x =
let y = f (12, (15, [1; 2; 3])) * 15.
x f
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let call f x||(0) =
let y||(1) = f (12, (15, [1; 2; 3])) * 15.
x f

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : (int * (int * int list) -> float) -> 'a
(1): ReSharper Parameter Name Hint: : float
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type MySingleCaseDu = MySingleCaseDu of int
let addFive (MySingleCaseDu value) =
value + 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type MySingleCaseDu = MySingleCaseDu of int
let addFive (MySingleCaseDu value||(0)) =
value + 5

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let addFive (hi) =
hi + 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let addFive (hi||(0)) =
hi + 5

---------------------------------------------------------
(0): ReSharper Parameter Name Hint: : int
Loading