@@ -98,19 +98,22 @@ module Commands =
9898 let rec walkPat ( pat : SynPat ) =
9999 seq {
100100 match pat with
101- | SynPat.LongIdent( longDotId = SynLongIdent ( id = idents ) ; argPats = args) ->
101+ | SynPat.LongIdent( longDotId = synLongIdent ; argPats = args) ->
102102 // Check if this is a potential case usage
103- match idents with
104- | [] -> ()
105- | [ singleIdent ] when List.contains singleIdent.idText caseNames ->
106- // Single identifier that matches a case name
107- yield singleIdent.idRange
108- | multipleIdents ->
109- // Qualified identifier (e.g., MyModule.ParseInt)
110- let lastIdent = List.last multipleIdents
111-
112- if List.contains lastIdent.idText caseNames then
113- yield lastIdent.idRange
103+ match synLongIdent with
104+ | SynLongIdent( id = idents) ->
105+ match idents with
106+ | [] -> ()
107+ | [ singleIdent ] when List.contains singleIdent.idText caseNames ->
108+ // Single identifier that matches a case name
109+ yield singleIdent.idRange
110+ | multipleIdents ->
111+ // Qualified identifier (e.g., MyModule.ParseInt)
112+ let lastIdent = List.last multipleIdents
113+
114+ if List.contains lastIdent.idText caseNames then
115+ // Return the full qualified range to match what FCS returns
116+ yield synLongIdent.Range
114117
115118 // Recursively check arguments
116119 match args with
@@ -184,11 +187,9 @@ module Commands =
184187 | SynSimplePat.Typed( pat, _, _)
185188 | SynSimplePat.Attrib( pat, _, _) ->
186189 match pat with
187- | SynSimplePat.Id( ident, _, _, _, _, _) when List.contains ident.idText caseNames ->
188- yield ident.idRange
190+ | SynSimplePat.Id( ident, _, _, _, _, _) when List.contains ident.idText caseNames -> yield ident.idRange
189191 | _ -> ()
190- | SynSimplePat.Id( ident, _, _, _, _, _) when List.contains ident.idText caseNames ->
191- yield ident.idRange
192+ | SynSimplePat.Id( ident, _, _, _, _, _) when List.contains ident.idText caseNames -> yield ident.idRange
192193 | _ -> ()
193194
194195 yield ! walkExpr body
@@ -215,6 +216,7 @@ module Commands =
215216 | Some e3 -> yield ! walkExpr e3
216217 | None -> ()
217218 | SynExpr.Paren( expr, _, _, _) -> yield ! walkExpr expr
219+ | SynExpr.Typed( expr = expr) -> yield ! walkExpr expr
218220 // Computation expressions (seq, async, task, etc.)
219221 | SynExpr.ComputationExpr( expr = expr) -> yield ! walkExpr expr
220222 // Array or list expressions
@@ -932,7 +934,14 @@ module Commands =
932934 asyncResult {
933935 let symbol = symbolUse.Symbol
934936
935- let symbolNameCore = symbol.DisplayNameCore
937+ let symbolNameCore =
938+ match symbol with
939+ | : ? FSharpMemberOrFunctionOrValue as mfv when
940+ mfv.IsActivePattern
941+ || ( mfv.DisplayName.StartsWith( " (|" ) && mfv.DisplayName.EndsWith( " |)" ))
942+ ->
943+ mfv.DisplayName.TrimStart( '(' , '|' ). TrimEnd( ')' , '|' , '_' )
944+ | _ -> symbol.DisplayNameCore
936945
937946 let tryAdjustRanges ( text : IFSACSourceText , ranges : seq < Range >) =
938947 let ranges = ranges |> Seq.map ( fun range -> range.NormalizeDriveLetterCasing())
@@ -982,11 +991,26 @@ module Commands =
982991 | : ? FSharpActivePatternCase as foundApc -> foundApc .Name = apc .Name
983992 | _ -> false )
984993
985- filtered, []
986- | : ? FSharpMemberOrFunctionOrValue as mfv when mfv .IsActivePattern ->
994+ // For partial active patterns in .fsx files, FCS may not return case usages
995+ // We walk the AST and deduplicate with what FCS found
996+ let isPartialPattern = apc.Group.IsTotal |> not
997+
998+ let caseUsageRanges =
999+ if isPartialPattern then
1000+ findPartialActivePatternCaseUsages [ apc.Name ] tyRes.GetParseResults
1001+ else
1002+ // Complete patterns - FCS handles these correctly
1003+ []
1004+
1005+ filtered, caseUsageRanges
1006+ | : ? FSharpMemberOrFunctionOrValue as mfv when
1007+ mfv.IsActivePattern
1008+ || ( mfv.DisplayName.StartsWith( " (|" ) && mfv.DisplayName.EndsWith( " |)" ))
1009+ ->
9871010 // Querying from the active pattern function declaration
9881011 // For partial active patterns like (|ParseInt|_|), include case usages in match expressions
9891012 // For complete active patterns like (|Even|Odd|), only return the function declaration
1013+ // Note: IsActivePattern is true for direct definitions, but let-bound values need DisplayName check
9901014
9911015 let patternDisplayName = mfv.DisplayName
9921016 // DisplayName includes parens: "(|ParseInt|_|)" so we need to check for "|_|)" not just "|_|"
@@ -1003,7 +1027,8 @@ module Commands =
10031027 |> Array.filter ( fun s -> not ( String.IsNullOrWhiteSpace( s)))
10041028 |> Array.toList
10051029
1006- let caseUsageRanges = findPartialActivePatternCaseUsages caseNames tyRes.GetParseResults
1030+ let caseUsageRanges =
1031+ findPartialActivePatternCaseUsages caseNames tyRes.GetParseResults
10071032
10081033 // For partial patterns, FCS doesn't include case usages in pattern matches
10091034 // We found them by walking the AST, so we return them as additional ranges
@@ -1013,7 +1038,9 @@ module Commands =
10131038 let ranges =
10141039 let baseRanges = symbolUses |> Seq.map ( fun u -> u.Range)
10151040 // Add any additional ranges we found from walking the AST for partial active patterns
1041+ // Deduplicate based on range start and end positions
10161042 Seq.append baseRanges ( Seq.ofList additionalRangesForPartialPatterns)
1043+ |> Seq.distinctBy ( fun r -> r.Start, r.End)
10171044 // Note: tryAdjustRanges is designed to only be able to fail iff `errorOnFailureToFixRange` is `true`
10181045 let! ranges = tryAdjustRanges ( text, ranges)
10191046 let ranges = dict [ ( text.FileName, Seq.toArray ranges) ]
0 commit comments