Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4aba54b
POC
0101 Nov 10, 2022
e0b8fab
fantomas
0101 Nov 10, 2022
62124ef
benchmarks
0101 Nov 11, 2022
ec6f313
Parallel find references in VS
0101 Nov 11, 2022
420a367
Merge branch 'faster-find-reference' into benchmarks
0101 Nov 11, 2022
76ba005
Some benchmarks
0101 Nov 11, 2022
f0dd929
refactoring
0101 Nov 11, 2022
f182b3f
Enable fastFindReferences in VS
0101 Nov 14, 2022
8db1370
experimental task workflow
0101 Nov 15, 2022
7884892
Task.Run
0101 Nov 15, 2022
9463e0b
Thread-safe rename
0101 Nov 15, 2022
c60fe2d
Simplification
0101 Nov 15, 2022
e41c6b3
Merge branch 'main' into faster-find-reference
0101 Nov 21, 2022
befde7f
Fast Find References fix for backticks, operators & attributes
0101 Nov 22, 2022
72a3d45
fantomas
0101 Nov 22, 2022
d6f6126
Fast find references configurable from performance options
0101 Nov 22, 2022
abe4267
update surface area
0101 Nov 22, 2022
10caa2d
Marked ParsedInput.Identifiers as experimental
0101 Nov 22, 2022
5b6b54b
Merge remote-tracking branch 'upstream/main' into faster-find-reference
0101 Nov 22, 2022
cb57811
Refactored fast find references setting
0101 Nov 22, 2022
9b98c2e
benchmark update
0101 Nov 22, 2022
15283f6
cleanup
0101 Nov 22, 2022
6ac1e40
cleanup
0101 Nov 22, 2022
e9fbb9b
Don't look for references in documents above declaration
0101 Nov 23, 2022
b9286fa
Fix finding attributes from usage (constructor)
0101 Nov 24, 2022
e387e4f
Merge remote-tracking branch 'upstream/main' into faster-find-reference
0101 Nov 24, 2022
64cc041
Added search keywords for fast find references option
0101 Nov 24, 2022
ca366b9
Test for SemanticClassificationKeyStoreBuilder
0101 Nov 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5290,7 +5290,7 @@ let CheckOneImplFile
rootSigOpt: ModuleOrNamespaceType option,
synImplFile) =

let (ParsedImplFileInput (_, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _)) = synImplFile
let (ParsedImplFileInput (_, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _, _)) = synImplFile
let infoReader = InfoReader(g, amap)

cancellable {
Expand Down
53 changes: 35 additions & 18 deletions src/Compiler/Driver/ParseAndCheckInputs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ let PrependPathToSpec x (SynModuleOrNamespaceSig (longId, isRecursive, kind, dec

let PrependPathToInput x inp =
match inp with
| ParsedInput.ImplFile (ParsedImplFileInput (b, c, q, d, hd, impls, e, trivia)) ->
| ParsedInput.ImplFile (ParsedImplFileInput (b, c, q, d, hd, impls, e, trivia, i)) ->
Comment thread
0101 marked this conversation as resolved.
ParsedInput.ImplFile(
ParsedImplFileInput(b, c, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToImpl x) impls, e, trivia)
ParsedImplFileInput(b, c, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToImpl x) impls, e, trivia, i)
)

| ParsedInput.SigFile (ParsedSigFileInput (b, q, d, hd, specs, trivia)) ->
ParsedInput.SigFile(ParsedSigFileInput(b, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToSpec x) specs, trivia))
| ParsedInput.SigFile (ParsedSigFileInput (b, q, d, hd, specs, trivia, i)) ->
ParsedInput.SigFile(ParsedSigFileInput(b, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToSpec x) specs, trivia, i))

let IsValidAnonModuleName (modname: string) =
modname |> String.forall (fun c -> Char.IsLetterOrDigit c || c = '_')
Expand Down Expand Up @@ -243,7 +243,8 @@ let PostParseModuleImpls
isLastCompiland,
ParsedImplFile (hashDirectives, impls),
lexbuf: UnicodeLexing.Lexbuf,
tripleSlashComments: range list
tripleSlashComments: range list,
identifiers: Set<string>
) =
let othersWithSameName =
impls
Expand Down Expand Up @@ -283,7 +284,9 @@ let PostParseModuleImpls
CodeComments = codeComments
}

ParsedInput.ImplFile(ParsedImplFileInput(fileName, isScript, qualName, scopedPragmas, hashDirectives, impls, isLastCompiland, trivia))
ParsedInput.ImplFile(
ParsedImplFileInput(fileName, isScript, qualName, scopedPragmas, hashDirectives, impls, isLastCompiland, trivia, identifiers)
)

let PostParseModuleSpecs
(
Expand All @@ -292,7 +295,8 @@ let PostParseModuleSpecs
isLastCompiland,
ParsedSigFile (hashDirectives, specs),
lexbuf: UnicodeLexing.Lexbuf,
tripleSlashComments: range list
tripleSlashComments: range list,
identifiers: Set<string>
) =
let othersWithSameName =
specs
Expand Down Expand Up @@ -331,7 +335,7 @@ let PostParseModuleSpecs
CodeComments = codeComments
}

ParsedInput.SigFile(ParsedSigFileInput(fileName, qualName, scopedPragmas, hashDirectives, specs, trivia))
ParsedInput.SigFile(ParsedSigFileInput(fileName, qualName, scopedPragmas, hashDirectives, specs, trivia, identifiers))

type ModuleNamesDict = Map<string, Map<string, QualifiedNameOfFile>>

Expand Down Expand Up @@ -376,26 +380,26 @@ let DeduplicateModuleName (moduleNamesDict: ModuleNamesDict) fileName (qualNameO
let DeduplicateParsedInputModuleName (moduleNamesDict: ModuleNamesDict) input =
match input with
| ParsedInput.ImplFile implFile ->
let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, hashDirectives, modules, flags, trivia)) =
let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, hashDirectives, modules, flags, trivia, identifiers)) =
implFile

let qualNameOfFileR, moduleNamesDictR =
DeduplicateModuleName moduleNamesDict fileName qualNameOfFile

let implFileR =
ParsedImplFileInput(fileName, isScript, qualNameOfFileR, scopedPragmas, hashDirectives, modules, flags, trivia)
ParsedImplFileInput(fileName, isScript, qualNameOfFileR, scopedPragmas, hashDirectives, modules, flags, trivia, identifiers)

let inputR = ParsedInput.ImplFile implFileR
inputR, moduleNamesDictR
| ParsedInput.SigFile sigFile ->
let (ParsedSigFileInput (fileName, qualNameOfFile, scopedPragmas, hashDirectives, modules, trivia)) =
let (ParsedSigFileInput (fileName, qualNameOfFile, scopedPragmas, hashDirectives, modules, trivia, identifiers)) =
sigFile

let qualNameOfFileR, moduleNamesDictR =
DeduplicateModuleName moduleNamesDict fileName qualNameOfFile

let sigFileR =
ParsedSigFileInput(fileName, qualNameOfFileR, scopedPragmas, hashDirectives, modules, trivia)
ParsedSigFileInput(fileName, qualNameOfFileR, scopedPragmas, hashDirectives, modules, trivia, identifiers)

let inputT = ParsedInput.SigFile sigFileR
inputT, moduleNamesDictR
Expand Down Expand Up @@ -426,6 +430,17 @@ let ParseInput

try
let input =
let identStore = HashSet<string>()

let identCaptureLexer x =
Comment thread
0101 marked this conversation as resolved.
let token = lexer x

match token with
| Parser.token.IDENT ident -> identStore.Add ident |> ignore
| _ -> ()

token

if FSharpMLCompatFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
errorR (Error(FSComp.SR.buildInvalidSourceFileExtensionML fileName, rangeStartup))
Expand All @@ -434,19 +449,19 @@ let ParseInput

// Call the appropriate parser - for signature files or implementation files
if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
let impl = Parser.implementationFile lexer lexbuf
let impl = Parser.implementationFile identCaptureLexer lexbuf

let tripleSlashComments =
LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf)

PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, tripleSlashComments)
PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, tripleSlashComments, Set identStore)
elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
let intfs = Parser.signatureFile lexer lexbuf
let intfs = Parser.signatureFile identCaptureLexer lexbuf

let tripleSlashComments =
LexbufLocalXmlDocStore.ReportInvalidXmlDocPositions(lexbuf)

PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, tripleSlashComments)
PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, tripleSlashComments, Set identStore)
else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated fileName, rangeStartup))
else
Expand Down Expand Up @@ -518,7 +533,8 @@ let EmptyParsedInput (fileName, isLastCompiland) =
{
ConditionalDirectives = []
CodeComments = []
}
},
Set.empty
)
)
else
Expand All @@ -534,7 +550,8 @@ let EmptyParsedInput (fileName, isLastCompiland) =
{
ConditionalDirectives = []
CodeComments = []
}
},
Set.empty
)
)

Expand Down
14 changes: 12 additions & 2 deletions src/Compiler/Driver/ScriptClosure.fs
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,23 @@ module ScriptPreprocessClosure =
match lastParsedInput with
| Some (ParsedInput.ImplFile lastParsedImplFile) ->

let (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, _, trivia)) =
let (ParsedImplFileInput (name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, _, trivia, identifiers)) =
lastParsedImplFile

let isLastCompiland = (true, tcConfig.target.IsExe)

let lastParsedImplFileR =
ParsedImplFileInput(name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, isLastCompiland, trivia)
ParsedImplFileInput(
name,
isScript,
qualNameOfFile,
scopedPragmas,
hashDirectives,
implFileFlags,
isLastCompiland,
trivia,
identifiers
)

let lastClosureFileR =
ClosureFile(fileName, m, Some(ParsedInput.ImplFile lastParsedImplFileR), parseDiagnostics, metaDiagnostics, nowarns)
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1850,7 +1850,7 @@ type internal FsiDynamicCompiler(
let impl = SynModuleOrNamespace(prefix,false, SynModuleOrNamespaceKind.NamedModule,defs,PreXmlDoc.Empty,[],None,m, { LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.None })
let isLastCompiland = true
let isExe = false
let input = ParsedInput.ImplFile (ParsedImplFileInput (fileName,true, ComputeQualifiedNameOfFileFromUniquePath (m,prefixPath),[],[],[impl],(isLastCompiland, isExe), { ConditionalDirectives = []; CodeComments = [] }))
let input = ParsedInput.ImplFile (ParsedImplFileInput (fileName,true, ComputeQualifiedNameOfFileFromUniquePath (m,prefixPath),[],[],[impl],(isLastCompiland, isExe), { ConditionalDirectives = []; CodeComments = [] }, Set.empty))
let isIncrementalFragment = true
let istate,tcEnvAtEndOfLastInput,declaredImpls = ProcessInputs (ctok, diagnosticsLogger, istate, [input], showTypes, isIncrementalFragment, isInteractiveItExpr, prefix, m)
let tcState = istate.tcState
Expand Down
6 changes: 4 additions & 2 deletions src/Compiler/Service/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ module IncrementalBuildSyntaxTree =
[],
[],
isLastCompiland,
{ ConditionalDirectives = []; CodeComments = [] }
{ ConditionalDirectives = []; CodeComments = [] },
Set.empty
)
)
else
Expand Down Expand Up @@ -284,7 +285,8 @@ type BoundModel private (tcConfig: TcConfig,
GraphNode(node {
match! this.TypeCheck(false) with
| FullState(tcInfo, tcInfoExtras) -> return tcInfo, tcInfoExtras
| PartialState(tcInfo) -> return tcInfo, emptyTcInfoExtras
| PartialState(tcInfo) ->
return tcInfo, emptyTcInfoExtras
})

let partialGraphNode =
Expand Down
9 changes: 7 additions & 2 deletions src/Compiler/Service/SemanticClassificationKey.fs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ type SemanticClassificationKeyStoreBuilder() =
let b = BlobBuilder()

member _.WriteAll(semanticClassification: SemanticClassificationItem[]) =
use ptr = fixed semanticClassification
b.WriteBytes(NativePtr.ofNativeInt (NativePtr.toNativeInt ptr), semanticClassification.Length * sizeof<SemanticClassificationItem>)
if semanticClassification.Length > 0 then
Comment thread
0101 marked this conversation as resolved.
use ptr = fixed semanticClassification

b.WriteBytes(
NativePtr.ofNativeInt (NativePtr.toNativeInt ptr),
semanticClassification.Length * sizeof<SemanticClassificationItem>
)

member _.TryBuildAndReset() =
if b.Count > 0 then
Expand Down
9 changes: 8 additions & 1 deletion src/Compiler/Service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,7 +1362,14 @@ type FSharpChecker
let canInvalidateProject = defaultArg canInvalidateProject true
let userOpName = defaultArg userOpName "Unknown"

backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
node {
let! parseResults = backgroundCompiler.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName)

if parseResults.ParseTree.Identifiers |> Set.contains symbol.DisplayName then
return! backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
else
return Seq.empty
}
|> Async.AwaitNodeCode

member _.GetBackgroundSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, ?userOpName) =
Expand Down
11 changes: 9 additions & 2 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1680,7 +1680,8 @@ type ParsedImplFileInput =
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespace list *
flags: (bool * bool) *
trivia: ParsedImplFileInputTrivia
trivia: ParsedImplFileInputTrivia *
identifiers: Set<string>

member x.QualifiedName =
(let (ParsedImplFileInput (qualifiedNameOfFile = qualNameOfFile)) = x in qualNameOfFile)
Expand Down Expand Up @@ -1712,7 +1713,8 @@ type ParsedSigFileInput =
scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespaceSig list *
trivia: ParsedSigFileInputTrivia
trivia: ParsedSigFileInputTrivia *
identifiers: Set<string>

member x.QualifiedName =
(let (ParsedSigFileInput (qualifiedNameOfFile = qualNameOfFile)) = x in qualNameOfFile)
Expand Down Expand Up @@ -1755,3 +1757,8 @@ type ParsedInput =
| ParsedInput.ImplFile (ParsedImplFileInput(contents = SynModuleOrNamespace (range = m) :: _))
| ParsedInput.SigFile (ParsedSigFileInput(contents = SynModuleOrNamespaceSig (range = m) :: _)) -> m
| _ -> rangeN inp.FileName 0

member inp.Identifiers =
match inp with
| ParsedInput.ImplFile (ParsedImplFileInput (identifiers = identifiers))
| ParsedInput.SigFile (ParsedSigFileInput (identifiers = identifiers)) -> identifiers
9 changes: 7 additions & 2 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,8 @@ type ParsedImplFileInput =
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespace list *
flags: (bool * bool) *
trivia: ParsedImplFileInputTrivia
trivia: ParsedImplFileInputTrivia *
identifiers: Set<string>

member FileName: string

Expand Down Expand Up @@ -1918,7 +1919,8 @@ type ParsedSigFileInput =
scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespaceSig list *
trivia: ParsedSigFileInputTrivia
trivia: ParsedSigFileInputTrivia *
identifiers: Set<string>

member FileName: string

Expand Down Expand Up @@ -1952,3 +1954,6 @@ type ParsedInput =

/// Gets the #nowarn and other scoped pragmas
member ScopedPragmas: ScopedPragma list

/// Gets a set of all identifiers used in this parsed input
member Identifiers: Set<string>
24 changes: 24 additions & 0 deletions tests/FSharp.Compiler.ComponentTests/FSharpChecker/SymbolUse.fs
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,28 @@ val f: x: 'a -> TFirstV_1<'a>
checkFile "First" (fun (typeCheckResult: FSharpCheckFileResults) ->
let symbolUse = typeCheckResult.GetSymbolUseAtLocation(6, 14, "let private f3 x = x + 1", ["f3"]) |> Option.defaultWith (fun () -> failwith "no symbol use found")
Assert.False(symbolUse.IsPrivateToFile))
}

module FindReferences =


[<Fact>]
let ``Finding references in project`` () =
let size = 20

let project =
{ SyntheticProject.Create() with
SourceFiles = [
sourceFile $"File%03d{0}" [] |> addSignatureFile
for i in 1..size do
sourceFile $"File%03d{i}" [$"File%03d{i-1}"]
]
}
|> updateFile "File005" (addDependency "File000")
|> updateFile "File010" (addDependency "File000")

let checker = FSharpChecker.Create(enableBackgroundItemKeyStoreAndSemanticClassification = true)

project.WorkflowWith checker {
findAllReferencesToModuleFromFile "File000" (expectNumberOfResults 5)
}
Loading