@@ -17,19 +17,21 @@ module UnusedOpens =
1717/// Range of open statement itself.
1818 Range: range
1919/// Scope on which this open declaration is applied.
20- AppliedScope: range }
20+ AppliedScope: range
21+ /// If it's prefixed with the special "global" namespace.
22+ IsGlobal: bool }
2123
2224let getOpenStatements ( openDeclarations : FSharpOpenDeclaration list ) : OpenStatement list =
2325 openDeclarations
2426|> List.choose( fun openDeclaration ->
2527match openDeclarationwith
26- | FSharpOpenDeclaration.Open( longId , modules , appliedScope ) when not ( List.isEmpty longId ) ->
28+ | FSharpOpenDeclaration.Open(( firstId :: _) as longId , modules , appliedScope ) ->
2729 Some{ Idents= modules|> List.choose( fun x -> x.TryFullName) |> Set.ofList
2830 Range=
29- let first = List.head longId
30- let last = List.last longId
31- mkRange appliedScope.FileName first.idRange.Start last.idRange.End
32- AppliedScope = appliedScope }
31+ let lastId = List.last longId
32+ mkRange appliedScope.FileName firstId.idRange.Start lastId.idRange.End
33+ AppliedScope = appliedScope
34+ IsGlobal = firstId.idText = MangledGlobalName }
3335| _ -> None// for now
3436)
3537
@@ -73,7 +75,7 @@ module UnusedOpens =
7375
7476type NamespaceUse =
7577{ Ident: string
76- Location : range }
78+ SymbolLocation : range }
7779
7880let getPartNamespace ( symbolUse : FSharpSymbolUse ) ( fullName : string ) =
7981// given a symbol range such as `Text.ISegment` and a full name of `MonoDevelop.Core.Text.ISegment`, return `MonoDevelop.Core`
@@ -137,32 +139,38 @@ module UnusedOpens =
137139else None)
138140|> List.map( fun ns ->
139141{ Ident= ns
140- Location = su.RangeAlternate}))
142+ SymbolLocation = su.RangeAlternate}))
141143
142144let getUnusedOpens ( checkFileResults : FSharpCheckFileResults , getSourceLineStr : int -> string ) : Async < range list > =
143145
144146let filter ( openStatements : OpenStatement list ) ( namespacesInUse : NamespaceUse list ) : OpenStatement list =
145147let rec filterInner acc ( openStatements : OpenStatement list ) ( seenOpenStatements : OpenStatement list ) =
146148
147- let notUsed ( os : OpenStatement ) =
148- if os.Idents |> Set.exists ( fun x -> x.StartsWith MangledGlobalName ) then false
149+ let isUsed ( openStatement : OpenStatement ) =
150+ if openStatement.IsGlobal then true
149151else
150- let notUsedAnywhere =
151- not ( namespacesInUse|> List.exists( fun nsu ->
152- rangeContainsRange os.AppliedScope nsu.Location&& os.Idents|> Set.contains nsu.Ident))
153- if notUsedAnywherethen true
152+ let usedSomewhere =
153+ namespacesInUse
154+ |> List.exists( fun namespaceUse ->
155+ let inScope = rangeContainsRange openStatement.AppliedScope namespaceUse.SymbolLocation
156+ if not inScopethen false
157+ else
158+ let identMatches = openStatement.Idents|> Set.contains namespaceUse.Ident
159+ identMatches)
160+
161+ if not usedSomewherethen false
154162else
155163let alreadySeen =
156164 seenOpenStatements
157165|> List.exists( fun seenNs ->
158166// if such open statement has already been marked as used in this or outer module, we skip it
159167// (that is, do not mark as used so far)
160- rangeContainsRange seenNs.AppliedScopeos .AppliedScope&&
161- not ( os .Idents|> Set.intersect seenNs.Idents|> Set.isEmpty))
162- alreadySeen
168+ rangeContainsRange seenNs.AppliedScopeopenStatement .AppliedScope&&
169+ not ( openStatement .Idents|> Set.intersect seenNs.Idents|> Set.isEmpty))
170+ not alreadySeen
163171
164172match openStatementswith
165- | os:: xswhen notUsed os ->
173+ | os:: xswhen not ( isUsed os ) ->
166174 filterInner( os:: acc) xs( os:: seenOpenStatements)
167175| os:: xs->
168176 filterInner acc xs( os:: seenOpenStatements)