/
SemanticClassification.fs
371 lines (326 loc) · 18.6 KB
/
SemanticClassification.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace FSharp.Compiler.SourceCodeServices
open System.Diagnostics
open System.Collections.Generic
open System.Collections.Immutable
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler.Infos
open FSharp.Compiler.ErrorLogger
open FSharp.Compiler.NameResolution
open FSharp.Compiler.PrettyNaming
open FSharp.Compiler.Range
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeOps
[<RequireQualifiedAccess>]
type SemanticClassificationType =
| ReferenceType
| ValueType
| UnionCase
| UnionCaseField
| Function
| Property
| MutableVar
| Module
| Namespace
| Printf
| ComputationExpression
| IntrinsicFunction
| Enumeration
| Interface
| TypeArgument
| Operator
| DisposableType
| DisposableValue
| Method
| ExtensionMethod
| ConstructorForReferenceType
| ConstructorForValueType
| Literal
| RecordField
| MutableRecordField
| RecordFieldAsFunction
| Exception
| Field
| Event
| Delegate
| NamedArgument
| Value
| LocalValue
| Type
| TypeDef
| Plaintext
[<AutoOpen>]
module TcResolutionsExtensions =
let (|CNR|) (cnr:CapturedNameResolution) =
(cnr.Item, cnr.ItemOccurence, cnr.DisplayEnv, cnr.NameResolutionEnv, cnr.AccessorDomain, cnr.Range)
type TcResolutions with
member sResolutions.GetSemanticClassification(g: TcGlobals, amap: Import.ImportMap, formatSpecifierLocations: (range * int) [], range: range option) : struct(range * SemanticClassificationType) [] =
ErrorScope.Protect Range.range0 (fun () ->
let (|LegitTypeOccurence|_|) = function
| ItemOccurence.UseInType
| ItemOccurence.UseInAttribute
| ItemOccurence.Use _
| ItemOccurence.Binding _
| ItemOccurence.Pattern _
| ItemOccurence.Open -> Some()
| _ -> None
let (|KeywordIntrinsicValue|_|) (vref: ValRef) =
if valRefEq g g.raise_vref vref ||
valRefEq g g.reraise_vref vref ||
valRefEq g g.typeof_vref vref ||
valRefEq g g.typedefof_vref vref ||
valRefEq g g.sizeof_vref vref ||
valRefEq g g.nameof_vref vref then Some()
else None
let (|EnumCaseFieldInfo|_|) (rfinfo : RecdFieldInfo) =
match rfinfo.TyconRef.TypeReprInfo with
| TFSharpObjectRepr x ->
match x.fsobjmodel_kind with
| TTyconEnum -> Some ()
| _ -> None
| _ -> None
// Custome builders like 'async { }' are both Item.Value and Item.CustomBuilder.
// We should prefer the latter, otherwise they would not get classified as CEs.
let takeCustomBuilder (cnrs: CapturedNameResolution[]) =
assert (cnrs.Length > 0)
if cnrs.Length = 1 then
cnrs
elif cnrs.Length = 2 then
match cnrs.[0].Item, cnrs.[1].Item with
| Item.Value _, Item.CustomBuilder _ ->
[| cnrs.[1] |]
| Item.CustomBuilder _, Item.Value _ ->
[| cnrs.[0] |]
| _ ->
cnrs
else
cnrs
let resolutions =
match range with
| Some range ->
sResolutions.CapturedNameResolutions.ToArray()
|> Array.filter (fun cnr -> rangeContainsPos range cnr.Range.Start || rangeContainsPos range cnr.Range.End)
|> Array.groupBy (fun cnr -> cnr.Range)
|> Array.map (fun (_, cnrs) -> takeCustomBuilder cnrs)
|> Array.concat
| None ->
sResolutions.CapturedNameResolutions.ToArray()
let isDisposableTy (ty: TType) =
not (typeEquiv g ty g.system_IDisposable_ty) &&
protectAssemblyExplorationNoReraise false false (fun () -> Infos.ExistsHeadTypeInEntireHierarchy g amap range0 ty g.tcref_System_IDisposable)
let isDiscard (str: string) = str.StartsWith("_")
let isValRefDisposable (vref: ValRef) =
not (isDiscard vref.DisplayName) &&
// For values, we actually do want to color things if they literally are IDisposables
protectAssemblyExplorationNoReraise false false (fun () -> Infos.ExistsHeadTypeInEntireHierarchy g amap range0 vref.Type g.tcref_System_IDisposable)
let isStructTyconRef (tyconRef: TyconRef) =
let ty = generalizedTyconRef tyconRef
let underlyingTy = stripTyEqnsAndMeasureEqns g ty
isStructTy g underlyingTy
let isValRefMutable (vref: ValRef) =
// Mutable values, ref cells, and non-inref byrefs are mutable.
vref.IsMutable
|| isRefCellTy g vref.Type
|| (isByrefTy g vref.Type && not (isInByrefTy g vref.Type))
let isRecdFieldMutable (rfinfo: RecdFieldInfo) =
(rfinfo.RecdField.IsMutable && rfinfo.LiteralValue.IsNone)
|| isRefCellTy g rfinfo.RecdField.FormalType
let duplicates = HashSet<range>(Range.comparer)
let results = ImmutableArray.CreateBuilder()
let inline add m typ =
if duplicates.Add m then
results.Add struct(m, typ)
resolutions
|> Array.iter (fun cnr ->
match cnr.Item, cnr.ItemOccurence, cnr.DisplayEnv, cnr.NameResolutionEnv, cnr.AccessorDomain, cnr.Range with
| (Item.CustomBuilder _ | Item.CustomOperation _), ItemOccurence.Use, _, _, _, m ->
add m SemanticClassificationType.ComputationExpression
| (Item.Value vref), _, _, _, _, m when isValRefMutable vref ->
add m SemanticClassificationType.MutableVar
| Item.Value KeywordIntrinsicValue, ItemOccurence.Use, _, _, _, m ->
add m SemanticClassificationType.IntrinsicFunction
| (Item.Value vref), _, _, _, _, m when isFunctionTy g vref.Type ->
if isDiscard vref.DisplayName then
add m SemanticClassificationType.Plaintext
elif valRefEq g g.range_op_vref vref || valRefEq g g.range_step_op_vref vref then
add m SemanticClassificationType.Operator
elif vref.IsPropertyGetterMethod || vref.IsPropertySetterMethod then
add m SemanticClassificationType.Property
elif vref.IsMember then
add m SemanticClassificationType.Method
elif IsOperatorName vref.DisplayName then
add m SemanticClassificationType.Operator
else
add m SemanticClassificationType.Function
| (Item.Value vref), _, _, _, _, m ->
if isValRefDisposable vref then
add m SemanticClassificationType.DisposableValue
elif Option.isSome vref.LiteralValue then
add m SemanticClassificationType.Literal
elif not vref.IsCompiledAsTopLevel && not(isDiscard vref.DisplayName) then
add m SemanticClassificationType.LocalValue
else
add m SemanticClassificationType.Value
| Item.RecdField rfinfo, _, _, _, _, m ->
match rfinfo with
| EnumCaseFieldInfo ->
add m SemanticClassificationType.Enumeration
| _ ->
if isRecdFieldMutable rfinfo then
add m SemanticClassificationType.MutableRecordField
elif isFunTy g rfinfo.FieldType then
add m SemanticClassificationType.RecordFieldAsFunction
else
add m SemanticClassificationType.RecordField
| Item.AnonRecdField(_, tys, idx, m), _, _, _, _, _ ->
let ty = tys.[idx]
// It's not currently possible for anon record fields to be mutable, but they can be ref cells
if isRefCellTy g ty then
add m SemanticClassificationType.MutableRecordField
elif isFunTy g ty then
add m SemanticClassificationType.RecordFieldAsFunction
else
add m SemanticClassificationType.RecordField
| Item.Property (_, pinfo :: _), _, _, _, _, m ->
if not pinfo.IsIndexer then
add m SemanticClassificationType.Property
| Item.CtorGroup (_, minfos), _, _, _, _, m ->
match minfos with
| [] ->
add m SemanticClassificationType.ConstructorForReferenceType
| _ ->
if minfos |> List.forall (fun minfo -> isDisposableTy minfo.ApparentEnclosingType) then
add m SemanticClassificationType.DisposableType
elif minfos |> List.forall (fun minfo -> isStructTy g minfo.ApparentEnclosingType) then
add m SemanticClassificationType.ConstructorForValueType
else
add m SemanticClassificationType.ConstructorForReferenceType
| (Item.DelegateCtor _ | Item.FakeInterfaceCtor _), _, _, _, _, m ->
add m SemanticClassificationType.ConstructorForReferenceType
| Item.MethodGroup (_, minfos, _), _, _, _, _, m ->
match minfos with
| [] ->
add m SemanticClassificationType.Method
| _ ->
if minfos |> List.forall (fun minfo -> minfo.IsExtensionMember || minfo.IsCSharpStyleExtensionMember) then
add m SemanticClassificationType.ExtensionMethod
else
add m SemanticClassificationType.Method
// Special case measures for struct types
| Item.Types(_, TType_app(tyconRef, TType_measure _ :: _) :: _), LegitTypeOccurence, _, _, _, m when isStructTyconRef tyconRef ->
add m SemanticClassificationType.ValueType
| Item.Types (_, ty :: _), LegitTypeOccurence, _, _, _, m ->
let reprToClassificationType repr tcref =
match repr with
| TFSharpObjectRepr om ->
match om.fsobjmodel_kind with
| TTyconClass -> SemanticClassificationType.ReferenceType
| TTyconInterface -> SemanticClassificationType.Interface
| TTyconStruct -> SemanticClassificationType.ValueType
| TTyconDelegate _ -> SemanticClassificationType.Delegate
| TTyconEnum _ -> SemanticClassificationType.Enumeration
| TRecdRepr _
| TUnionRepr _ ->
if isStructTyconRef tcref then
SemanticClassificationType.ValueType
else
SemanticClassificationType.Type
| TILObjectRepr (TILObjectReprData (_, _, td)) ->
if td.IsClass then
SemanticClassificationType.ReferenceType
elif td.IsStruct then
SemanticClassificationType.ValueType
elif td.IsInterface then
SemanticClassificationType.Interface
elif td.IsEnum then
SemanticClassificationType.Enumeration
else
SemanticClassificationType.Delegate
| TAsmRepr _ -> SemanticClassificationType.TypeDef
| TMeasureableRepr _-> SemanticClassificationType.TypeDef
#if !NO_EXTENSIONTYPING
| TProvidedTypeExtensionPoint _-> SemanticClassificationType.TypeDef
| TProvidedNamespaceExtensionPoint _-> SemanticClassificationType.TypeDef
#endif
| TNoRepr -> SemanticClassificationType.ReferenceType
let ty = stripTyEqns g ty
if isDisposableTy ty then
add m SemanticClassificationType.DisposableType
else
match tryTcrefOfAppTy g ty with
| ValueSome tcref ->
add m (reprToClassificationType tcref.TypeReprInfo tcref)
| ValueNone ->
if isStructTupleTy g ty then
add m SemanticClassificationType.ValueType
elif isRefTupleTy g ty then
add m SemanticClassificationType.ReferenceType
elif isFunctionTy g ty then
add m SemanticClassificationType.Function
elif isTyparTy g ty then
add m SemanticClassificationType.ValueType
else
add m SemanticClassificationType.TypeDef
| (Item.TypeVar _ ), LegitTypeOccurence, _, _, _, m ->
add m SemanticClassificationType.TypeArgument
| Item.ExnCase _, LegitTypeOccurence, _, _, _, m ->
add m SemanticClassificationType.Exception
| Item.ModuleOrNamespaces (modref :: _), LegitTypeOccurence, _, _, _, m ->
if modref.IsNamespace then
add m SemanticClassificationType.Namespace
else
add m SemanticClassificationType.Module
| (Item.ActivePatternCase _ | Item.UnionCase _ | Item.ActivePatternResult _), _, _, _, _, m ->
add m SemanticClassificationType.UnionCase
| Item.UnionCaseField _, _, _, _, _, m ->
add m SemanticClassificationType.UnionCaseField
| Item.ILField _, _, _, _, _, m ->
add m SemanticClassificationType.Field
| Item.Event _, _, _, _, _, m ->
add m SemanticClassificationType.Event
| (Item.ArgName _ | Item.SetterArg _), _, _, _, _, m ->
add m SemanticClassificationType.NamedArgument
| Item.SetterArg _, _, _, _, _, m ->
add m SemanticClassificationType.Property
| Item.UnqualifiedType (tcref :: _), LegitTypeOccurence, _, _, _, m ->
if tcref.IsEnumTycon || tcref.IsILEnumTycon then
add m SemanticClassificationType.Enumeration
elif tcref.IsExceptionDecl then
add m SemanticClassificationType.Exception
elif tcref.IsFSharpDelegateTycon then
add m SemanticClassificationType.Delegate
elif tcref.IsFSharpInterfaceTycon then
add m SemanticClassificationType.Interface
elif tcref.IsFSharpStructOrEnumTycon then
add m SemanticClassificationType.ValueType
elif tcref.IsModule then
add m SemanticClassificationType.Module
elif tcref.IsNamespace then
add m SemanticClassificationType.Namespace
elif tcref.IsUnionTycon || tcref.IsRecordTycon then
if isStructTyconRef tcref then
add m SemanticClassificationType.ValueType
else
add m SemanticClassificationType.UnionCase
elif tcref.IsILTycon then
let (TILObjectReprData (_, _, tydef)) = tcref.ILTyconInfo
if tydef.IsInterface then
add m SemanticClassificationType.Interface
elif tydef.IsDelegate then
add m SemanticClassificationType.Delegate
elif tydef.IsEnum then
add m SemanticClassificationType.Enumeration
elif tydef.IsStruct then
add m SemanticClassificationType.ValueType
else
add m SemanticClassificationType.ReferenceType
| _, _, _, _, _, m ->
add m SemanticClassificationType.Plaintext)
results.AddRange(formatSpecifierLocations |> Array.map (fun (m, _) -> struct(m, SemanticClassificationType.Printf)))
results.ToArray()
)
(fun msg ->
Trace.TraceInformation(sprintf "FCS: recovering from error in GetSemanticClassification: '%s'" msg)
Array.empty)