@@ -9,11 +9,14 @@ open Microsoft.FSharp.Compiler.Range
99
1010module UnusedOpens =
1111open Microsoft.FSharp .Compiler .PrettyNaming
12+ open Microsoft.FSharp .Compiler .AbstractIL .Internal .Library
1213
1314/// Represents single open statement.
1415type OpenStatement =
1516{ /// Full namespace or module identifier as it's presented in source code.
1617 Idents: Set < string >
18+ /// Modules.
19+ Modules: FSharpEntity list
1720/// Range of open statement itself.
1821 Range: range
1922/// Scope on which this open declaration is applied.
@@ -27,6 +30,7 @@ module UnusedOpens =
2730match openDeclarationwith
2831| FSharpOpenDeclaration.Open(( firstId:: _) as longId, modules, appliedScope) ->
2932 Some{ Idents= modules|> List.choose( fun x -> x.TryFullName) |> Set.ofList
33+ Modules= modules
3034 Range=
3135let lastId = List.last longId
3236 mkRange appliedScope.FileName firstId.idRange.Start lastId.idRange.End
@@ -118,14 +122,18 @@ module UnusedOpens =
118122{ SymbolUse: FSharpSymbolUse
119123 FullNames: string [][] }
120124
121- let getNamespacesInUse ( getSourceLineStr : int -> string ) ( symbolUses : FSharpSymbolUse []) : NamespaceUse list =
125+ type SymbolUse =
126+ { SymbolUse: FSharpSymbolUse
127+ RequiredPrefix: string }
128+
129+ let getSymbolUses ( getSourceLineStr : int -> string ) ( symbolUses : FSharpSymbolUse []) : SymbolUse [] =
122130let importantSymbolUses =
123131 symbolUses
124132|> Array.filter( fun ( symbolUse : FSharpSymbolUse ) ->
125- not symbolUse.IsFromDefinition&&
126- match symbolUse.Symbolwith
127- | :? FSharpEntityas e-> not e.IsNamespace
128- | _ -> true
133+ not symbolUse.IsFromDefinition
134+ //&& match symbolUse.Symbol with
135+ // | :? FSharpEntity as e -> not e.IsNamespace
136+ // | _ -> true
129137)
130138
131139let symbolUsesWithFullNames : SymbolUseWithFullNames [] =
@@ -207,58 +215,59 @@ module UnusedOpens =
207215{ SymbolUse= symbolUse
208216 FullNames= fullNames})
209217
210- let outerSymbolUses =
211- symbolUsesWithFullNames
212- |> Seq.sortBy( fun x -> - x.SymbolUse.RangeAlternate.EndColumn)
213- |> Seq.fold( fun ( prev , acc ) next ->
214- match prevwith
215- | Some prev->
216- if prev.FullNames
217- |> Array.exists( fun prevFullName ->
218- next.FullNames
219- |> Array.exists( fun nextFullName ->
220- nextFullName.Length< prevFullName.Length
221- && prevFullName|> Microsoft.FSharp.Compiler.AbstractIL.Internal.Library.Array.startsWith nextFullName)) then
222- Some prev, acc
223- else Some next, next:: acc
224- | None-> Some next, next:: acc)
225- ( None, [])
226- |> snd
227- |> List.map( fun x -> x.SymbolUse)
228- |> List.rev
218+ // let outerSymbolUses =
219+ // symbolUsesWithFullNames
220+ // |> Seq.sortBy (fun x -> -x.SymbolUse.RangeAlternate.EndColumn)
221+ // |> Seq.fold (fun (prev, acc) next ->
222+ // match prev with
223+ // | Some prev ->
224+ // if prev.FullNames
225+ // |> Array.exists (fun prevFullName ->
226+ // next.FullNames
227+ // |> Array.exists (fun nextFullName ->
228+ // nextFullName.Length < prevFullName.Length
229+ // && prevFullName |> Microsoft.FSharp.Compiler.AbstractIL.Internal.Library.Array.startsWith nextFullName)) then
230+ // Some prev, acc
231+ // else Some next, next :: acc
232+ // | None -> Some next, next :: acc)
233+ // (None, [])
234+ // |> snd
235+ // |> List.map (fun x -> x.SymbolUse)
236+ // |> List.rev
229237
230- outerSymbolUses
231- |> List.collect( fun su ->
232- let lineStr = getSourceLineStr su.RangeAlternate.StartLine
233- let partialName = QuickParse.GetPartialLongNameEx( lineStr, su.RangeAlternate.EndColumn- 1 )
234- let qualifier = partialName.QualifyingIdents|> String.concat" ."
235- getPossibleNamespaces getSourceLineStr su
236- |> List.distinct
237- |> List.choose( fun ns ->
238- if qualifier= " " then Some ns
239- elif ns= qualifierthen None
240- elif ns.EndsWith qualifierthen Some ns.[..( ns.Length- qualifier.Length) - 2 ]
241- else None)
242- |> List.map( fun ns ->
243- { Ident= ns
244- SymbolLocation= su.RangeAlternate}))
238+ symbolUsesWithFullNames
239+ |> Array.collect( fun su ->
240+ let lineStr = getSourceLineStr su.SymbolUse.RangeAlternate.StartLine
241+ let partialName = QuickParse.GetPartialLongNameEx( lineStr, su.SymbolUse.RangeAlternate.EndColumn- 1 )
242+ let suffix = partialName.QualifyingIdents@ [ partialName.PartialIdent] |> List.toArray
243+ su.FullNames
244+ |> Array.choose( fun fullName ->
245+ if fullName= suffixthen None
246+ elif fullName|> Array.endsWith suffixthen Some( su.SymbolUse, fullName.[..( fullName.Length- suffix.Length) - 2 ])
247+ else None)
248+ |> Array.map( fun ( su , prefix ) ->
249+ { SymbolUse= su
250+ RequiredPrefix= prefix|> String.concat" ." }))
245251
246252let getUnusedOpens ( checkFileResults : FSharpCheckFileResults , getSourceLineStr : int -> string ) : Async < range list > =
247253
248- let filter ( openStatements : OpenStatement list ) ( namespacesInUse : NamespaceUse list ) : OpenStatement list =
254+ let filter ( openStatements : OpenStatement list ) ( symbolUses : SymbolUse [] ): OpenStatement list =
249255let rec filterInner acc ( openStatements : OpenStatement list ) ( seenOpenStatements : OpenStatement list ) =
250256
251257let isUsed ( openStatement : OpenStatement ) =
252258if openStatement.IsGlobalthen true
253259else
254- let usedSomewhere =
255- namespacesInUse
256- |> List .exists( fun namespaceUse ->
257- let inScope = rangeContainsRange openStatement.AppliedScopenamespaceUse.SymbolLocation
260+ let usedSomewhere =
261+ symbolUses
262+ |> Array .exists( fun symbolUse ->
263+ let inScope = rangeContainsRange openStatement.AppliedScopesymbolUse.SymbolUse.RangeAlternate
258264if not inScopethen false
265+ elif not ( openStatement.Idents|> Set.contains symbolUse.RequiredPrefix) then false
259266else
260- let identMatches = openStatement.Idents|> Set.contains namespaceUse.Ident
261- identMatches)
267+ openStatement.Modules
268+ |> List.exists( fun m ->
269+ m.PublicNestedEntities
270+ |> Seq.exists( fun ent -> ent.IsEffectivelySameAs symbolUse.SymbolUse.Symbol)))
262271
263272if not usedSomewherethen false
264273else
@@ -281,8 +290,9 @@ module UnusedOpens =
281290 filterInner[] openStatements[]
282291
283292async {
284- let! symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile()
285- let namespacesInUse = getNamespacesInUse getSourceLineStr symbolUses
293+ let! fsharpSymbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile()
294+ let symbolUses = getSymbolUses getSourceLineStr fsharpSymbolUses
295+ //let namespacesInUse = getNamespacesInUse getSourceLineStr symbolUses
286296let openStatements = getOpenStatements checkFileResults.OpenDeclarations
287- return filter openStatementsnamespacesInUse |> List.map( fun os -> os.Range)
297+ return filter openStatementssymbolUses |> List.map( fun os -> os.Range)
288298}