@@ -70,118 +70,19 @@ module UnusedOpens =
7070| _ -> None// for now
7171)
7272
73- let getAutoOpenAccessPath ( ent : FSharpEntity ) =
74- // Some.Namespace+AutoOpenedModule+Entity
75-
76- // HACK: I can't see a way to get the EnclosingEntity of an Entity
77- // Some.Namespace + Some.Namespace.AutoOpenedModule are both valid
78- ent.TryFullName|> Option.bind( fun _ ->
79- if ( not ent.IsNamespace) && ent.QualifiedName.Contains" +" then
80- Some ent.QualifiedName.[ 0 .. ent.QualifiedName.IndexOf" +" - 1 ]
81- else
82- None)
83-
84- let entityNamespace ( entOpt : FSharpEntity option ) =
85- match entOptwith
86- | Some ent->
87- if ent.IsFSharpModulethen
88- [ yield Some ent.QualifiedName
89- yield Some ent.LogicalName
90- yield Some ent.AccessPath
91- yield Some ent.FullName
92- yield Some ent.DisplayName
93- yield ent.TryGetFullDisplayName()
94- if ent.HasFSharpModuleSuffixthen
95- yield Some( ent.AccessPath+ " ." + ent.DisplayName)]
96- else
97- [ yield ent.Namespace
98- yield Some ent.AccessPath
99- yield getAutoOpenAccessPath ent
100- for pathin ent.AllCompilationPathsdo
101- yield Some path
102- ]
103- | None-> []
104-
105- type NamespaceUse =
106- { Ident: string
107- ExtraNamespaces: string [] }
108-
109- let getNamespaceInUse ( fullIsland : string ) ( fullName : string ) : NamespaceUse option =
110- // given a full island such as `Text.ISegment` and a full name of `MonoDevelop.Core.Text.ISegment`, return `MonoDevelop.Core`
111- let lengthDiff = fullName.Length- fullIsland.Length- 2
112- if lengthDiff<= 0 || lengthDiff> fullName.Length- 1 then None
113- else
114- let requiredOpenNamespace = fullName.[ 0 .. lengthDiff]
115- let rest = fullName.[ lengthDiff+ 1 ..]
116- let extraNamespaces =
117- match rest.Split'.' with
118- | [||] | [|_|] -> [||]
119- | rest-> rest.[.. rest.Length- 2 ]
120- Some{ Ident= requiredOpenNamespace; ExtraNamespaces= extraNamespaces}
121-
122- let getPossibleNamespaces ( getSourceLineStr : int -> string ) ( symbolUse : FSharpSymbolUse ) : NamespaceUse [] =
123- let lineStr = getSourceLineStr symbolUse.RangeAlternate.StartLine
124- let partialName = QuickParse.GetPartialLongNameEx( lineStr, symbolUse.RangeAlternate.EndColumn- 1 )
125- if partialName.PartialIdent= " " then [||]
126- else
127- let qualifyingIsland = partialName.QualifyingIdents|> String.concat" ."
128- let fullIsland = qualifyingIsland+ partialName.PartialIdent
129- let isQualified fullName = fullName= fullIsland
130-
131- ( match symbolUsewith
132- | SymbolUse.Entity( ent, cleanFullNames) when not ( cleanFullNames|> List.exists isQualified) ->
133- Some( cleanFullNames, Some ent)
134- | SymbolUse.Field fwhen not ( isQualified f.FullName) ->
135- Some([ f.FullName], Some f.DeclaringEntity)
136- | SymbolUse.MemberFunctionOrValue mfvwhen not ( isQualified mfv.FullName) ->
137- Some([ mfv.FullName], mfv.EnclosingEntity)
138- | SymbolUse.Operator opwhen not ( isQualified op.FullName) ->
139- Some([ op.FullName], op.EnclosingEntity)
140- | SymbolUse.ActivePattern apwhen not ( isQualified ap.FullName) ->
141- Some([ ap.FullName], ap.EnclosingEntity)
142- | SymbolUse.ActivePatternCase apcwhen not ( isQualified apc.FullName) ->
143- Some([ apc.FullName], apc.Group.EnclosingEntity)
144- | SymbolUse.UnionCase ucwhen not ( isQualified uc.FullName) ->
145- Some([ uc.FullName], Some uc.ReturnType.TypeDefinition)
146- | SymbolUse.Parameter pwhen not ( isQualified p.FullName) && p.Type.HasTypeDefinition->
147- Some([ p.FullName], Some p.Type.TypeDefinition)
148- | _ -> None)
149- |> Option.map( fun ( fullNames , declaringEntity ) ->
150- [| for namein fullNamesdo
151- let partNamespace = getNamespaceInUse fullIsland name
152- yield partNamespace
153- yield !
154- entityNamespace declaringEntity
155- |> List.map( Option.bind( getNamespaceInUse qualifyingIsland))
156- |])
157- |> Option.toArray
158- |> Array.concat
159- |> Array.choose id
160- |> Array.distinct
161-
162- type SymbolUseWithFullNames =
163- { SymbolUse: FSharpSymbolUse
164- FullNames: string [][] }
165-
166- type SymbolUse =
167- { SymbolUse: FSharpSymbolUse
168- PossibleNamespaces: NamespaceUse [] }
169-
170- let getSymbolUses ( getSourceLineStr : int -> string ) ( symbolUses : FSharpSymbolUse []) : SymbolUse [] =
73+ let filterSymbolUses ( getSourceLineStr : int -> string ) ( symbolUses : FSharpSymbolUse []) : FSharpSymbolUse [] =
17174 symbolUses
172- |> Array.filter( fun ( symbolUse : FSharpSymbolUse ) ->
173- not symbolUse.IsFromDefinition//&&
174- //match symbolUse.Symbol with
175- //| :? FSharpEntity as e -> not e.IsNamespace
176- //| _ -> true
177- )
178- |> Array.map( fun su ->
179- { SymbolUse= su
180- PossibleNamespaces= getPossibleNamespaces getSourceLineStr su})
75+ |> Array.filter( fun su -> not su.IsFromDefinition)
76+ |> Array.filter( fun su ->
77+ match su.Symbolwith
78+ | :? FSharpMemberOrFunctionOrValueas fvwhen fv.IsExtensionMember-> true
79+ | _ ->
80+ let partialName = QuickParse.GetPartialLongNameEx( getSourceLineStr su.RangeAlternate.StartLine, su.RangeAlternate.EndColumn- 1 )
81+ partialName.PartialIdent<> " " && partialName.QualifyingIdents= [])
18182
18283let getUnusedOpens ( checkFileResults : FSharpCheckFileResults , getSourceLineStr : int -> string ) : Async < range list > =
18384
184- let filter ( openStatements : OpenStatement list ) ( symbolUses : SymbolUse []) : OpenStatement list =
85+ let filter ( openStatements : OpenStatement list ) ( symbolUses : FSharpSymbolUse []) : OpenStatement list =
18586let rec filterInner acc ( openStatements : OpenStatement list ) ( seenOpenStatements : OpenStatement list ) =
18687
18788let isUsed ( openStatement : OpenStatement ) =
@@ -190,13 +91,13 @@ module UnusedOpens =
19091let usedSomewhere =
19192 symbolUses
19293|> Array.exists( fun symbolUse ->
193- let inScope = rangeContainsRange openStatement.AppliedScope symbolUse.SymbolUse. RangeAlternate
94+ let inScope = rangeContainsRange openStatement.AppliedScope symbolUse.RangeAlternate
19495if not inScopethen false
195- elif openStatement.Idents|> Set.intersect symbolUse.PossibleNamespaces|> Set.isEmptythen false
96+ // elif openStatement.Idents |> Set.intersect symbolUse.PossibleNamespaces |> Set.isEmpty then false
19697else
19798let moduleSymbols = openStatement.AllChildSymbols|> Seq.toList
19899 moduleSymbols
199- |> List.exists( fun x -> x.IsEffectivelySameAs symbolUse.SymbolUse. Symbol))
100+ |> List.exists( fun x -> x.IsEffectivelySameAs symbolUse.Symbol))
200101
201102if not usedSomewherethen false
202103else
@@ -219,8 +120,8 @@ module UnusedOpens =
219120 filterInner[] openStatements[]
220121
221122async {
222- let! fsharpSymbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile()
223- let symbolUses = getSymbolUses getSourceLineStrfsharpSymbolUses
123+ let! symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile()
124+ let symbolUses = filterSymbolUses getSourceLineStrsymbolUses
224125let openStatements = getOpenStatements checkFileResults.OpenDeclarations
225126return filter openStatements symbolUses|> List.map( fun os -> os.Range)
226127}