提交 6efa3b35 编写于 作者: V Vasily Kirichenko 提交者: Kevin Ransom (msft)

Optimize simplify name analyzer (#2254)

* remove unnecessary filtering and deduplication

* write lazy early return functions for SimplifyName analyzer

* make the rest of nr lazy

add cache

* fix cache locking

* do not try to resolve ctors for non-ctor Item

* more lazyness to NameResolution

* optimize GetBestEnvForPos by indexing nameres environments (scopes) by line number

* look for best resolution env on previous line as well

* Reformat ResolveObjectConstructorPrim

* remove double hash table lookup in NotifyNameResolution

* make CurrentSink non-optional

* eliminate a list creation

* renaming

* optimize ValRef

* small optimizations

* make Ident a struct

* add MaybeLazy

* SimplifyNameDiagnosticAnalyzer should do semantic analysis, not syntax one

* remove dead code

* fix after merge

* Revert "make CurrentSink non-optional"

This reverts commit a2f791dceccf6e243232cf4858a7e49654a4c741.

# Conflicts:
#	src/fsharp/TypeChecker.fs

* Revert "optimize GetBestEnvForPos by indexing nameres environments (scopes) by line number"

This reverts commit c8edcc36e699b745dc11d118d00d6020cad9e7c1.

# Conflicts:
#	src/fsharp/vs/service.fs
#	src/fsharp/vs/service.fsi

* turn off SimplifyNameDiagnosticAnalyzer for now
上级 7755f90a
......@@ -3957,7 +3957,7 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti
| None ->
// Build up the artificial namespace if there is not a real one.
let cpath = CompPath(ILScopeRef.Local, injectedNamspace |> List.rev |> List.map (fun n -> (n,ModuleOrNamespaceKind.Namespace)) )
let newNamespace = NewModuleOrNamespace (Some cpath) taccessPublic (ident(next,rangeStartup)) XmlDoc.Empty [] (notlazy (NewEmptyModuleOrNamespaceType Namespace))
let newNamespace = NewModuleOrNamespace (Some cpath) taccessPublic (ident(next,rangeStartup)) XmlDoc.Empty [] (MaybeLazy.Strict (NewEmptyModuleOrNamespaceType Namespace))
entity.ModuleOrNamespaceType.AddModuleOrNamespaceByMutation(newNamespace)
tcImports.InjectProvidedNamespaceOrTypeIntoEntity (typeProviderEnvironment, tcConfig, m, newNamespace, next::injectedNamspace, rest, provider, st)
| [] ->
......
此差异已折叠。
......@@ -418,4 +418,5 @@ type ResolveCompletionTargets =
/// Resolve a (possibly incomplete) long identifier to a set of possible resolutions, qualified by type.
val ResolveCompletionsInType : NameResolver -> NameResolutionEnv -> ResolveCompletionTargets -> Range.range -> AccessorDomain -> bool -> TType -> Item list
val GetVisibleNamespacesAndModulesAtPoint : NameResolver -> NameResolutionEnv -> range -> AccessorDomain -> ModuleOrNamespaceRef list
\ No newline at end of file
val IsItemResolvable : NameResolver -> NameResolutionEnv -> range -> AccessorDomain -> string list -> Item -> bool
\ No newline at end of file
......@@ -3087,7 +3087,7 @@ and OptimizeModuleExpr cenv env x =
mty
and elimModSpec (mspec:ModuleOrNamespace) =
let mtyp = elimModTy mspec.ModuleOrNamespaceType
mspec.Data.entity_modul_contents <- notlazy mtyp
mspec.Data.entity_modul_contents <- MaybeLazy.Strict mtyp
let rec elimModDef x =
match x with
......
......@@ -980,7 +980,7 @@ let ensureCcuHasModuleOrNamespaceAtPath (ccu:CcuThunk) path (CompPath(_,cpath))
| (hpath::tpath),((_,mkind)::tcpath) ->
let modName = hpath.idText
if not (Map.containsKey modName mtype.AllEntitiesByCompiledAndLogicalMangledNames) then
let smodul = NewModuleOrNamespace (Some(CompPath(scoref,prior_cpath))) taccessPublic hpath xml [] (notlazy (NewEmptyModuleOrNamespaceType mkind))
let smodul = NewModuleOrNamespace (Some(CompPath(scoref,prior_cpath))) taccessPublic hpath xml [] (MaybeLazy.Strict (NewEmptyModuleOrNamespaceType mkind))
mtype.AddModuleOrNamespaceByMutation(smodul);
let modul = Map.find modName mtype.AllEntitiesByCompiledAndLogicalMangledNames
loop (prior_cpath@[(modName,Namespace)]) tpath tcpath modul
......@@ -3566,7 +3566,7 @@ end
//--------------------------------------------------------------------------
let wrapModuleOrNamespaceType id cpath mtyp =
NewModuleOrNamespace (Some cpath) taccessPublic id XmlDoc.Empty [] (notlazy mtyp)
NewModuleOrNamespace (Some cpath) taccessPublic id XmlDoc.Empty [] (MaybeLazy.Strict mtyp)
let wrapModuleOrNamespaceTypeInNamespace id cpath mtyp =
let mspec = wrapModuleOrNamespaceType id cpath mtyp
......@@ -4972,9 +4972,8 @@ and copyAndRemapAndBindTyconsAndVals g compgen tmenv tycons vs =
tcd'.entity_tycon_repr <- tcd.entity_tycon_repr |> remapTyconRepr g tmenvinner2;
tcd'.entity_tycon_abbrev <- tcd.entity_tycon_abbrev |> Option.map (remapType tmenvinner2) ;
tcd'.entity_tycon_tcaug <- tcd.entity_tycon_tcaug |> remapTyconAug tmenvinner2 ;
tcd'.entity_modul_contents <- notlazy (tcd.entity_modul_contents
|> Lazy.force
|> mapImmediateValsAndTycons lookupTycon lookupVal);
tcd'.entity_modul_contents <- MaybeLazy.Strict (tcd.entity_modul_contents.Value
|> mapImmediateValsAndTycons lookupTycon lookupVal);
tcd'.entity_exn_info <- tcd.entity_exn_info |> remapTyconExnInfo g tmenvinner2) ;
tycons',vs', tmenvinner
......@@ -7637,10 +7636,8 @@ let rec remapEntityDataToNonLocal g tmenv (d: EntityData) =
entity_tycon_abbrev = d.entity_tycon_abbrev |> Option.map (remapType tmenvinner) ;
entity_tycon_tcaug = d.entity_tycon_tcaug |> remapTyconAug tmenvinner ;
entity_modul_contents =
notlazy (d.entity_modul_contents
|> Lazy.force
|> mapImmediateValsAndTycons (remapTyconToNonLocal g tmenv)
(remapValToNonLocal g tmenv));
MaybeLazy.Strict (d.entity_modul_contents.Value
|> mapImmediateValsAndTycons (remapTyconToNonLocal g tmenv) (remapValToNonLocal g tmenv));
entity_exn_info = d.entity_exn_info |> remapTyconExnInfo g tmenvinner}
and remapTyconToNonLocal g tmenv x =
......
......@@ -436,8 +436,7 @@ let p_option f x st =
// Pickle lazy values in such a way that they can, in some future F# compiler version, be read back
// lazily. However, a lazy reader is not used in this version because the value may contain the definitions of some
// OSGN nodes.
let p_lazy p x st =
let v = Lazy.force x
let private p_lazy_impl p v st =
let fixupPos1 = st.os.Position
// We fix these up after
prim_p_int32 0 st;
......@@ -473,6 +472,12 @@ let p_lazy p x st =
st.os.FixupInt32 fixupPos6 ovalsIdx1;
st.os.FixupInt32 fixupPos7 ovalsIdx2
let p_lazy p x st =
p_lazy_impl p (Lazy.force x) st
let p_maybe_lazy p (x: MaybeLazy<_>) st =
p_lazy_impl p x.Value st
let p_hole () =
let h = ref (None : 'T pickler option)
(fun f -> h := Some f),(fun x st -> match !h with Some f -> f x st | None -> pfailwith st "p_hole: unfilled hole")
......@@ -1727,7 +1732,7 @@ and p_entity_spec_data (x:EntityData) st =
p_kind x.entity_kind st
p_int64 (x.entity_flags.PickledBits ||| (if flagBit then EntityFlags.ReservedBitForPickleFormatTyconReprFlag else 0L)) st
p_option p_cpath x.entity_cpath st
p_lazy p_modul_typ x.entity_modul_contents st
p_maybe_lazy p_modul_typ x.entity_modul_contents st
p_exnc_repr x.entity_exn_info st
p_space 1 space st
......@@ -2012,7 +2017,7 @@ and u_entity_spec_data st : EntityData =
entity_kind=x10b;
entity_flags=EntityFlags(x11);
entity_cpath=x12;
entity_modul_contents= x13;
entity_modul_contents=MaybeLazy.Lazy x13;
entity_exn_info=x14;
entity_il_repr_cache=newCache();
}
......
......@@ -1315,7 +1315,7 @@ let UpdateAccModuleOrNamespaceType cenv env f =
if cenv.compilingCanonicalFslibModuleType then
let nleref = mkNonLocalEntityRef cenv.topCcu (arrPathOfLid env.ePath)
let modul = nleref.Deref
modul.Data.entity_modul_contents <- notlazy (f true modul.ModuleOrNamespaceType)
modul.Data.entity_modul_contents <- MaybeLazy.Strict (f true modul.ModuleOrNamespaceType)
SetCurrAccumulatedModuleOrNamespaceType env (f false (GetCurrAccumulatedModuleOrNamespaceType env))
let PublishModuleDefn cenv env mspec =
......@@ -13385,13 +13385,13 @@ module MutRecBindingChecking =
let TcMutRecDefns_UpdateNSContents mutRecNSInfo =
match mutRecNSInfo with
| Some (Some (mspecNS: ModuleOrNamespace), mtypeAcc) ->
mspecNS.Data.entity_modul_contents <- notlazy !mtypeAcc
mspecNS.Data.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
| _ -> ()
/// Updates the types of the modules to contain the contents so far
let TcMutRecDefns_UpdateModuleContents mutRecNSInfo defns =
defns |> MutRecShapes.iterModules (fun (MutRecDefnsPhase2DataForModule (mtypeAcc, mspec), _) ->
mspec.Data.entity_modul_contents <- notlazy !mtypeAcc)
mspec.Data.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc)
TcMutRecDefns_UpdateNSContents mutRecNSInfo
......@@ -14344,7 +14344,7 @@ module EstablishTypeDefinitionCores =
CheckNamespaceModuleOrTypeName cenv.g id
let envForDecls, mtypeAcc = MakeInnerEnv envInitial id modKind
let mspec = NewModuleOrNamespace (Some envInitial.eCompPath) vis id (xml.ToXmlDoc()) modAttrs (notlazy (NewEmptyModuleOrNamespaceType modKind))
let mspec = NewModuleOrNamespace (Some envInitial.eCompPath) vis id (xml.ToXmlDoc()) modAttrs (MaybeLazy.Strict (NewEmptyModuleOrNamespaceType modKind))
let innerParent = Parent (mkLocalModRef mspec)
let typeNames = TypeNamesInMutRecDecls compDecls
MutRecDefnsPhase2DataForModule (mtypeAcc, mspec), (innerParent, typeNames, envForDecls)
......@@ -14385,7 +14385,7 @@ module EstablishTypeDefinitionCores =
let visOfRepr,_ = ComputeAccessAndCompPath env None id.idRange synVisOfRepr None parent
let visOfRepr = combineAccess vis visOfRepr
// If we supported nested types and modules then additions would be needed here
let lmtyp = notlazy (NewEmptyModuleOrNamespaceType ModuleOrType)
let lmtyp = MaybeLazy.Strict (NewEmptyModuleOrNamespaceType ModuleOrType)
NewTycon(cpath, id.idText, id.idRange, vis, visOfRepr, TyparKind.Type, LazyWithContext.NotLazy checkedTypars, doc.ToXmlDoc(), preferPostfix, preEstablishedHasDefaultCtor, hasSelfReferentialCtor, lmtyp)
......@@ -16101,11 +16101,11 @@ let rec TcSignatureElementNonMutRec cenv parent typeNames endm (env: TcEnv) synS
// Now typecheck the signature, accumulating and then recording the submodule description.
let id = ident (modName, id.idRange)
let mspec = NewModuleOrNamespace (Some env.eCompPath) vis id (xml.ToXmlDoc()) attribs (notlazy (NewEmptyModuleOrNamespaceType modKind))
let mspec = NewModuleOrNamespace (Some env.eCompPath) vis id (xml.ToXmlDoc()) attribs (MaybeLazy.Strict (NewEmptyModuleOrNamespaceType modKind))
let! (mtyp,_) = TcModuleOrNamespaceSignatureElementsNonMutRec cenv (Parent (mkLocalModRef mspec)) env (id,modKind,mdefs,m,xml)
mspec.Data.entity_modul_contents <- notlazy mtyp
mspec.Data.entity_modul_contents <- MaybeLazy.Strict mtyp
let scopem = unionRanges m endm
PublishModuleDefn cenv env mspec
let env = AddLocalSubModuleAndReport cenv.tcSink scopem cenv.g cenv.amap m env mspec
......@@ -16421,13 +16421,13 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv:cenv) parent typeNames scopem
// Create the new module specification to hold the accumulated results of the type of the module
// Also record this in the environment as the accumulator
let mspec = NewModuleOrNamespace (Some env.eCompPath) vis id (xml.ToXmlDoc()) modAttrs (notlazy (NewEmptyModuleOrNamespaceType modKind))
let mspec = NewModuleOrNamespace (Some env.eCompPath) vis id (xml.ToXmlDoc()) modAttrs (MaybeLazy.Strict (NewEmptyModuleOrNamespaceType modKind))
// Now typecheck.
let! mexpr, topAttrsNew, envAtEnd = TcModuleOrNamespaceElements cenv (Parent (mkLocalModRef mspec)) endm envForModule xml None mdefs
// Get the inferred type of the decls and record it in the mspec.
mspec.Data.entity_modul_contents <- notlazy !mtypeAcc
mspec.Data.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
let modDefn = TMDefRec(false,[],[ModuleOrNamespaceBinding.Module(mspec,mexpr)],m)
PublishModuleDefn cenv env mspec
let env = AddLocalSubModuleAndReport cenv.tcSink scopem cenv.g cenv.amap m env mspec
......@@ -16614,7 +16614,7 @@ and TcMutRecDefsFinish cenv defs m =
binds |> List.map ModuleOrNamespaceBinding.Binding
| MutRecShape.Module ((MutRecDefnsPhase2DataForModule(mtypeAcc, mspec), _),mdefs) ->
let mexpr = TcMutRecDefsFinish cenv mdefs m
mspec.Data.entity_modul_contents <- notlazy !mtypeAcc
mspec.Data.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
[ ModuleOrNamespaceBinding.Module(mspec,mexpr) ])
TMDefRec(true,tycons,binds,m)
......
......@@ -135,9 +135,9 @@ type ParserDetail =
// PERFORMANCE: consider making this a struct.
[<System.Diagnostics.DebuggerDisplay("{idText}")>]
[<Sealed>]
[<Struct>]
[<NoEquality; NoComparison>]
type Ident (text,range) =
type Ident (text: string, range: range) =
member x.idText = text
member x.idRange = range
override x.ToString() = text
......
......@@ -455,7 +455,7 @@ let rec ImportILTypeDef amap m scoref (cpath:CompilationPath) enc nm (tdef:ILTyp
// Make sure we reraise the original exception one occurs - see findOriginalException.
(LazyWithContext.Create((fun m -> ImportILGenericParameters amap m scoref [] tdef.GenericParams), ErrorLogger.findOriginalException))
(scoref,enc,tdef)
lazyModuleOrNamespaceTypeForNestedTypes
(MaybeLazy.Lazy lazyModuleOrNamespaceTypeForNestedTypes)
/// Import a list of (possibly nested) IL types as a new ModuleOrNamespaceType node
......@@ -474,7 +474,7 @@ and ImportILTypeDefList amap m (cpath:CompilationPath) enc items =
|> multisetDiscriminateAndMap
(fun n tgs ->
let modty = lazy (ImportILTypeDefList amap m (cpath.NestedCompPath n Namespace) enc tgs)
NewModuleOrNamespace (Some cpath) taccessPublic (mkSynId m n) XmlDoc.Empty [] modty)
NewModuleOrNamespace (Some cpath) taccessPublic (mkSynId m n) XmlDoc.Empty [] (MaybeLazy.Lazy modty))
(fun (n,info:Lazy<_>) ->
let (scoref2,_,lazyTypeDef:Lazy<ILTypeDef>) = info.Force()
ImportILTypeDef amap m scoref2 cpath enc n (lazyTypeDef.Force()))
......
......@@ -970,6 +970,17 @@ type Entity =
/// Sets the structness of a record or union type definition
member x.SetIsStructRecordOrUnion b = let x = x.Data in let flags = x.entity_flags in x.entity_flags <- EntityFlags(flags.IsPrefixDisplay, flags.IsModuleOrNamespace, flags.PreEstablishedHasDefaultConstructor, flags.HasSelfReferentialConstructor, b)
and [<RequireQualifiedAccess>] MaybeLazy<'T> =
| Strict of 'T
| Lazy of Lazy<'T>
member this.Value : 'T =
match this with
| Strict x -> x
| Lazy x -> x.Value
member this.Force() : 'T =
match this with
| Strict x -> x
| Lazy x -> x.Force()
and
[<NoEquality; NoComparison;RequireQualifiedAccess>]
......@@ -1033,7 +1044,7 @@ and
//
// MUTABILITY: only used during creation and remapping of tycons and
// when compiling fslib to fixup compiler forward references to internal items
mutable entity_modul_contents: Lazy<ModuleOrNamespaceType>
mutable entity_modul_contents: MaybeLazy<ModuleOrNamespaceType>
/// The declared documentation for the type or module
entity_xmldoc : XmlDoc
......@@ -1745,7 +1756,7 @@ and Construct =
entity_tycon_repr_accessibility = TAccess([])
entity_exn_info=TExnNone
entity_tycon_tcaug=TyconAugmentation.Create()
entity_modul_contents = lazy new ModuleOrNamespaceType(Namespace, QueueList.ofList [], QueueList.ofList [])
entity_modul_contents = MaybeLazy.Lazy (lazy new ModuleOrNamespaceType(Namespace, QueueList.ofList [], QueueList.ofList []))
// Generated types get internal accessibility
entity_accessiblity= access
entity_xmldoc = XmlDoc [||] // fetched on demand via est.fs API
......@@ -2596,7 +2607,7 @@ and NonLocalEntityRef =
Construct.NewModuleOrNamespace
(Some cpath)
(TAccess []) (ident(path.[k],m)) XmlDoc.Empty []
(notlazy (Construct.NewEmptyModuleOrNamespaceType Namespace))
(MaybeLazy.Strict (Construct.NewEmptyModuleOrNamespaceType Namespace))
entity.ModuleOrNamespaceType.AddModuleOrNamespaceByMutation(newEntity)
injectNamespacesFromIToJ newEntity (k+1)
let newEntity = injectNamespacesFromIToJ entity i
......@@ -3020,15 +3031,14 @@ and
mutable binding: NonNullSlot<Val>
/// Indicates a reference to something bound in another CCU
nlr: NonLocalValOrMemberRef }
member x.IsLocalRef = match box x.nlr with null -> true | _ -> false
member x.IsResolved = match box x.binding with null -> false | _ -> true
member x.IsLocalRef = obj.ReferenceEquals(x.nlr, null)
member x.IsResolved = not (obj.ReferenceEquals(x.binding, null))
member x.PrivateTarget = x.binding
member x.ResolvedTarget = x.binding
/// Dereference the ValRef to a Val.
member vr.Deref =
match box vr.binding with
| null ->
if obj.ReferenceEquals(vr.binding, null) then
let res =
let nlr = vr.nlr
let e = nlr.EnclosingEntity.Deref
......@@ -3038,12 +3048,11 @@ and
| Some h -> h
vr.binding <- nullableSlotFull res
res
| _ -> vr.binding
else vr.binding
/// Dereference the ValRef to a Val option.
member vr.TryDeref =
match box vr.binding with
| null ->
if obj.ReferenceEquals(vr.binding, null) then
let resOpt =
vr.nlr.EnclosingEntity.TryDeref |> Option.bind (fun e ->
e.ModuleOrNamespaceType.TryLinkVal(vr.nlr.EnclosingEntity.nlr.Ccu, vr.nlr.ItemKey))
......@@ -3052,8 +3061,7 @@ and
| Some res ->
vr.binding <- nullableSlotFull res
resOpt
| _ ->
Some vr.binding
else Some vr.binding
/// The type of the value. May be a TType_forall for a generic value.
/// May be a type variable or type containing type variables during type inference.
......@@ -4511,7 +4519,7 @@ let fullCompPathOfModuleOrNamespace (m:ModuleOrNamespace) =
CompPath(scoref,cpath@[(m.LogicalName, m.ModuleOrNamespaceType.ModuleOrNamespaceKind)])
// Can cpath2 be accessed given a right to access cpath1. That is, is cpath2 a nested type or namespace of cpath1. Note order of arguments.
let canAccessCompPathFrom (CompPath(scoref1,cpath1)) (CompPath(scoref2,cpath2)) =
let inline canAccessCompPathFrom (CompPath(scoref1,cpath1)) (CompPath(scoref2,cpath2)) =
let rec loop p1 p2 =
match p1,p2 with
| (a1,k1)::rest1, (a2,k2)::rest2 -> (a1=a2) && (k1=k2) && loop rest1 rest2
......@@ -4609,7 +4617,7 @@ let NewExn cpath (id:Ident) access repr attribs doc =
entity_pubpath=cpath |> Option.map (fun (cp:CompilationPath) -> cp.NestedPublicPath id)
entity_accessiblity=access
entity_tycon_repr_accessibility=access
entity_modul_contents = notlazy (NewEmptyModuleOrNamespaceType ModuleOrType)
entity_modul_contents = MaybeLazy.Strict (NewEmptyModuleOrNamespaceType ModuleOrType)
entity_cpath= cpath
entity_typars=LazyWithContext.NotLazy []
entity_tycon_abbrev = None
......@@ -4697,7 +4705,7 @@ let NewVal (logicalName:string,m:range,compiledName,ty,isMutable,isCompGen,arity
let NewCcuContents sref m nm mty =
NewModuleOrNamespace (Some(CompPath(sref,[]))) taccessPublic (ident(nm,m)) XmlDoc.Empty [] (notlazy mty)
NewModuleOrNamespace (Some(CompPath(sref,[]))) taccessPublic (ident(nm,m)) XmlDoc.Empty [] (MaybeLazy.Strict mty)
//--------------------------------------------------------------------------
......@@ -4719,7 +4727,7 @@ let NewModifiedTycon f (orig:Tycon) =
/// contents of the module.
let NewModifiedModuleOrNamespace f orig =
orig |> NewModifiedTycon (fun d ->
{ d with entity_modul_contents = notlazy (f (d.entity_modul_contents.Force())) })
{ d with entity_modul_contents = MaybeLazy.Strict (f (d.entity_modul_contents.Force())) })
/// Create a Val based on an existing one using the function 'f'.
/// We require that we be given the parent for the new Val.
......@@ -4774,7 +4782,7 @@ let CombineCcuContentFragments m l =
{ data1 with
entity_xmldoc = XmlDoc.Merge entity1.XmlDoc entity2.XmlDoc
entity_attribs = entity1.Attribs @ entity2.Attribs
entity_modul_contents=lazy (CombineModuleOrNamespaceTypes (path@[entity2.DemangledModuleOrNamespaceName]) entity2.Range entity1.ModuleOrNamespaceType entity2.ModuleOrNamespaceType) })
entity_modul_contents = MaybeLazy.Lazy (lazy (CombineModuleOrNamespaceTypes (path@[entity2.DemangledModuleOrNamespaceName]) entity2.Range entity1.ModuleOrNamespaceType entity2.ModuleOrNamespaceType)) })
| false,false ->
error(Error(FSComp.SR.tastDuplicateTypeDefinitionInAssembly(entity2.LogicalName, textOfPath path),entity2.Range))
| _,_ ->
......
......@@ -544,19 +544,19 @@ type TypeCheckInfo
/// Find the most precise naming environment for the given line and column
let GetBestEnvForPos cursorPos =
let bestSoFar = ref None
let mutable bestSoFar = None
// Find the most deeply nested enclosing scope that contains given position
sResolutions.CapturedEnvs |> ResizeArray.iter (fun (possm,env,ad) ->
if rangeContainsPos possm cursorPos then
match !bestSoFar with
match bestSoFar with
| Some (bestm,_,_) ->
if rangeContainsRange bestm possm then
bestSoFar := Some (possm,env,ad)
bestSoFar <- Some (possm,env,ad)
| None ->
bestSoFar := Some (possm,env,ad))
bestSoFar <- Some (possm,env,ad))
let mostDeeplyNestedEnclosingScope = !bestSoFar
let mostDeeplyNestedEnclosingScope = bestSoFar
// Look for better subtrees on the r.h.s. of the subtree to the left of where we are
// Should really go all the way down the r.h.s. of the subtree to the left of where we are
......@@ -1140,13 +1140,18 @@ type TypeCheckInfo
static let keywordTypes = Lexhelp.Keywords.keywordTypes
member x.GetVisibleNamespacesAndModulesAtPosition(cursorPos: pos) : ModuleOrNamespaceRef list =
let (nenv, ad), m = GetBestEnvForPos cursorPos
NameResolution.GetVisibleNamespacesAndModulesAtPoint ncenv nenv m ad
member x.IsRelativeNameResolvable(cursorPos: pos, plid: string list, item: Item) : bool =
let items, _, _ = GetEnvironmentLookupResolutions(cursorPos, plid, TypeNameResolutionFlag.ResolveTypeNamesToTypeRefs, true)
items |> List.exists (ItemsAreEffectivelyEqual g item)
/// Determines if a long ident is resolvable at a specific point.
ErrorScope.Protect
Range.range0
(fun () ->
/// Find items in the best naming environment.
let (nenv, ad), m = GetBestEnvForPos cursorPos
NameResolution.IsItemResolvable ncenv nenv m ad plid item)
(fun _ -> false)
//let items = NameResolution.ResolvePartialLongIdent ncenv nenv (fun _ _ -> true) m ad plid true
//items |> List.exists (ItemsAreEffectivelyEqual g item)
/// Get the auto-complete items at a location
member x.GetDeclarations (ctok, parseResultsOpt, line, lineStr, colAtEndOfNamesAndResidue, qualifyingNames, partialName, hasTextChangedSinceLastTypecheck) =
......@@ -2133,18 +2138,9 @@ type FSharpCheckFileResults(errors: FSharpErrorInfo[], scopeOptX: TypeCheckInfo
if itemOcc <> ItemOccurence.RelatedText then
yield FSharpSymbolUse(scope.TcGlobals, denv, symbol, itemOcc, m) |])
member info.GetVisibleNamespacesAndModulesAtPoint(pos: pos) : Async<ModuleOrNamespaceRef []> =
reactorOp "GetVisibleNamespacesAndModulesAtPoint" [| |] (fun ctok scope ->
DoesNotRequireCompilerThreadTokenAndCouldPossiblyBeMadeConcurrent ctok
scope.GetVisibleNamespacesAndModulesAtPosition(pos) |> List.toArray)
member info.IsRelativeNameResolvable(pos: pos, plid: string list, item: Item) : Async<bool> =
reactorOp "IsRelativeNameResolvable" true (fun ctok scope ->
DoesNotRequireCompilerThreadTokenAndCouldPossiblyBeMadeConcurrent ctok
scope.IsRelativeNameResolvable(pos, plid, item))
//----------------------------------------------------------------------------
......
......@@ -298,10 +298,8 @@ type internal FSharpCheckFileResults =
/// Get the textual usages that resolved to the given symbol throughout the file
member GetUsesOfSymbolInFile : symbol:FSharpSymbol -> Async<FSharpSymbolUse[]>
member GetVisibleNamespacesAndModulesAtPoint : pos -> Async<Tast.ModuleOrNamespaceRef[]>
/// Determines if a long ident is resolvable at a specific point.
member IsRelativeNameResolvable: cursorPos : pos * plid : string list * item: Item -> Async<bool>
/// A handle to the results of CheckFileInProject.
[<Sealed>]
type internal FSharpCheckProjectResults =
......
......@@ -17,15 +17,18 @@ open Microsoft.FSharp.Compiler.SourceCodeServices
open Microsoft.VisualStudio.FSharp.LanguageService
type private LineHash = int
type private TextVersionHash = int
//[<DiagnosticAnalyzer(FSharpCommonConstants.FSharpLanguageName)>]
// TODO Turn it on when user settings dialog is ready to switch it on and off.
// [<DiagnosticAnalyzer(FSharpCommonConstants.FSharpLanguageName)>]
type internal SimplifyNameDiagnosticAnalyzer() =
inherit DocumentDiagnosticAnalyzer()
let getProjectInfoManager (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().ProjectInfoManager
let getChecker (document: Document) = document.Project.Solution.Workspace.Services.GetService<FSharpCheckerWorkspaceService>().Checker
let getPlidLength (plid: string list) = (plid |> List.sumBy String.length) + plid.Length
static let cache = ConditionalWeakTable<DocumentId, TextVersionHash * ImmutableArray<Diagnostic>>()
static let guard = new SemaphoreSlim(1)
static let Descriptor =
DiagnosticDescriptor(
......@@ -42,75 +45,85 @@ type internal SimplifyNameDiagnosticAnalyzer() =
static member LongIdentPropertyKey = "FullName"
override __.SupportedDiagnostics = ImmutableArray.Create Descriptor
override this.AnalyzeSyntaxAsync(_, _) = Task.FromResult ImmutableArray<Diagnostic>.Empty
override this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken) =
override this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken) =
asyncMaybe {
match getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) with
| Some options ->
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = true)
let! symbolUses = checkResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync
let mutable result = ResizeArray()
let symbolUses =
symbolUses
|> Array.Parallel.map (fun symbolUse ->
let lineStr = sourceText.Lines.[Line.toZ symbolUse.RangeAlternate.StartLine].ToString()
// for `System.DateTime.Now` it returns ([|"System"; "DateTime"|], "Now")
let plid, name = QuickParse.GetPartialLongNameEx(lineStr, symbolUse.RangeAlternate.EndColumn - 1)
// `symbolUse.RangeAlternate.Start` does not point to the start of plid, it points to start of `name`,
// so we have to calculate plid's start ourselves.
let plidStartCol = symbolUse.RangeAlternate.EndColumn - name.Length - (getPlidLength plid)
symbolUse, plid, plidStartCol, name)
|> Array.filter (fun (_, plid, _, _) -> not (List.isEmpty plid))
|> Array.groupBy (fun (symbolUse, _, plidStartCol, _) -> symbolUse.RangeAlternate.StartLine, plidStartCol)
|> Array.map (fun (_, xs) -> xs |> Array.maxBy (fun (symbolUse, _, _, _) -> symbolUse.RangeAlternate.EndColumn))
for symbolUse, plid, plidStartCol, name in symbolUses do
if not symbolUse.IsFromDefinition then
let posAtStartOfName =
let r = symbolUse.RangeAlternate
if r.StartLine = r.EndLine then Range.mkPos r.StartLine (r.EndColumn - name.Length)
else r.Start
let getNecessaryPlid (plid: string list) : Async<string list> =
let rec loop (rest: string list) (current: string list) =
async {
match rest with
| [] -> return current
| headIdent :: restPlid ->
let! res = checkResults.IsRelativeNameResolvable(posAtStartOfName, current, symbolUse.Symbol.Item)
if res then return current
else return! loop restPlid (headIdent :: current)
}
loop (List.rev plid) []
let! necessaryPlid = getNecessaryPlid plid |> liftAsync
match necessaryPlid with
| necessaryPlid when necessaryPlid = plid -> ()
| necessaryPlid ->
let r = symbolUse.RangeAlternate
let necessaryPlidStartCol = r.EndColumn - name.Length - (getPlidLength necessaryPlid)
let unnecessaryRange =
Range.mkRange r.FileName (Range.mkPos r.StartLine plidStartCol) (Range.mkPos r.EndLine necessaryPlidStartCol)
let relativeName = (String.concat "." plid) + "." + name
result.Add(
Diagnostic.Create(
Descriptor,
CommonRoslynHelpers.RangeToLocation(unnecessaryRange, sourceText, document.FilePath),
properties = (dict [SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey, relativeName]).ToImmutableDictionary()))
return result.ToImmutableArray()
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let textVersionHash = textVersion.GetHashCode()
let! _ = guard.WaitAsync(cancellationToken) |> Async.AwaitTask |> liftAsync
try
match cache.TryGetValue document.Id with
| true, (oldTextVersionHash, diagnostics) when oldTextVersionHash = textVersionHash -> return diagnostics
| _ ->
let! sourceText = document.GetTextAsync()
let checker = getChecker document
let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = true)
let! symbolUses = checkResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync
let mutable result = ResizeArray()
let symbolUses =
symbolUses
|> Array.Parallel.map (fun symbolUse ->
let lineStr = sourceText.Lines.[Line.toZ symbolUse.RangeAlternate.StartLine].ToString()
// for `System.DateTime.Now` it returns ([|"System"; "DateTime"|], "Now")
let plid, name = QuickParse.GetPartialLongNameEx(lineStr, symbolUse.RangeAlternate.EndColumn - 1)
// `symbolUse.RangeAlternate.Start` does not point to the start of plid, it points to start of `name`,
// so we have to calculate plid's start ourselves.
let plidStartCol = symbolUse.RangeAlternate.EndColumn - name.Length - (getPlidLength plid)
symbolUse, plid, plidStartCol, name)
|> Array.filter (fun (_, plid, _, _) -> not (List.isEmpty plid))
|> Array.groupBy (fun (symbolUse, _, plidStartCol, _) -> symbolUse.RangeAlternate.StartLine, plidStartCol)
|> Array.map (fun (_, xs) -> xs |> Array.maxBy (fun (symbolUse, _, _, _) -> symbolUse.RangeAlternate.EndColumn))
for symbolUse, plid, plidStartCol, name in symbolUses do
if not symbolUse.IsFromDefinition then
let posAtStartOfName =
let r = symbolUse.RangeAlternate
if r.StartLine = r.EndLine then Range.mkPos r.StartLine (r.EndColumn - name.Length)
else r.Start
let getNecessaryPlid (plid: string list) : Async<string list> =
let rec loop (rest: string list) (current: string list) =
async {
match rest with
| [] -> return current
| headIdent :: restPlid ->
let! res = checkResults.IsRelativeNameResolvable(posAtStartOfName, current, symbolUse.Symbol.Item)
if res then return current
else return! loop restPlid (headIdent :: current)
}
loop (List.rev plid) []
let! necessaryPlid = getNecessaryPlid plid |> liftAsync
match necessaryPlid with
| necessaryPlid when necessaryPlid = plid -> ()
| necessaryPlid ->
let r = symbolUse.RangeAlternate
let necessaryPlidStartCol = r.EndColumn - name.Length - (getPlidLength necessaryPlid)
let unnecessaryRange =
Range.mkRange r.FileName (Range.mkPos r.StartLine plidStartCol) (Range.mkPos r.EndLine necessaryPlidStartCol)
let relativeName = (String.concat "." plid) + "." + name
result.Add(
Diagnostic.Create(
Descriptor,
CommonRoslynHelpers.RangeToLocation(unnecessaryRange, sourceText, document.FilePath),
properties = (dict [SimplifyNameDiagnosticAnalyzer.LongIdentPropertyKey, relativeName]).ToImmutableDictionary()))
let diagnostics = result.ToImmutableArray()
cache.Remove(document.Id) |> ignore
cache.Add(document.Id, (textVersionHash, diagnostics))
return diagnostics
finally guard.Release() |> ignore
| None -> return ImmutableArray.Empty
}
|> Async.map (Option.defaultValue ImmutableArray.Empty)
|> CommonRoslynHelpers.StartAsyncAsTask cancellationToken
override this.AnalyzeSemanticsAsync(_, _) = Task.FromResult ImmutableArray<Diagnostic>.Empty
interface IBuiltInAnalyzer with
member __.OpenFileOnly _ = true
member __.GetAnalyzerCategory() = DiagnosticAnalyzerCategory.SemanticDocumentAnalysis
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册