未验证 提交 23e22ead 编写于 作者: P Petr Pokorny 提交者: GitHub

Faster finding references (#14293)

上级 92b2b5db
......@@ -5309,17 +5309,17 @@ let CheckOneImplFile
synImplFile,
diagnosticOptions) =
let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _)) = synImplFile
let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _, _)) = synImplFile
let infoReader = InfoReader(g, amap)
cancellable {
use _ =
Activity.start "CheckDeclarations.CheckOneImplFile"
use _ =
Activity.start "CheckDeclarations.CheckOneImplFile"
[|
"fileName", fileName
"qualifiedNameOfFile", qualNameOfFile.Text
|]
let cenv =
let cenv =
cenv.Create (g, isScript, amap, thisCcu, false, Option.isSome rootSigOpt,
conditionalDefines, tcSink, (LightweightTcValForUsingInBuildMethodCall g), isInternalTestSpanStackReferring,
diagnosticOptions,
......@@ -5445,7 +5445,7 @@ let CheckOneImplFile
/// Check an entire signature file
let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring, diagnosticOptions) tcEnv (sigFile: ParsedSigFileInput) =
let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring, diagnosticOptions) tcEnv (sigFile: ParsedSigFileInput) =
cancellable {
use _ =
Activity.start "CheckDeclarations.CheckOneSigFile"
......@@ -5453,7 +5453,7 @@ let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSin
"fileName", sigFile.FileName
"qualifiedNameOfFile", sigFile.QualifiedName.Text
|]
let cenv =
let cenv =
cenv.Create
(g, false, amap, thisCcu, true, false, conditionalDefines, tcSink,
(LightweightTcValForUsingInBuildMethodCall g), isInternalTestSpanStackReferring,
......
......@@ -93,13 +93,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)) ->
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 = '_')
......@@ -244,7 +244,8 @@ let PostParseModuleImpls
isLastCompiland,
ParsedImplFile (hashDirectives, impls),
lexbuf: UnicodeLexing.Lexbuf,
tripleSlashComments: range list
tripleSlashComments: range list,
identifiers: Set<string>
) =
let othersWithSameName =
impls
......@@ -284,7 +285,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
(
......@@ -293,7 +296,8 @@ let PostParseModuleSpecs
isLastCompiland,
ParsedSigFile (hashDirectives, specs),
lexbuf: UnicodeLexing.Lexbuf,
tripleSlashComments: range list
tripleSlashComments: range list,
identifiers: Set<string>
) =
let othersWithSameName =
specs
......@@ -332,7 +336,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>>
......@@ -377,26 +381,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
......@@ -427,6 +431,28 @@ let ParseInput
try
let input =
let identStore = HashSet<string>()
let identCaptureLexer x =
let token = lexer x
match token with
| Parser.token.PERCENT_OP ident
| Parser.token.FUNKY_OPERATOR_NAME ident
| Parser.token.ADJACENT_PREFIX_OP ident
| Parser.token.PLUS_MINUS_OP ident
| Parser.token.INFIX_AMP_OP ident
| Parser.token.INFIX_STAR_DIV_MOD_OP ident
| Parser.token.PREFIX_OP ident
| Parser.token.INFIX_BAR_OP ident
| Parser.token.INFIX_AT_HAT_OP ident
| Parser.token.INFIX_COMPARE_OP ident
| Parser.token.INFIX_STAR_STAR_OP ident
| 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))
......@@ -435,19 +461,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
......@@ -519,7 +545,8 @@ let EmptyParsedInput (fileName, isLastCompiland) =
{
ConditionalDirectives = []
CodeComments = []
}
},
Set.empty
)
)
else
......@@ -535,7 +562,8 @@ let EmptyParsedInput (fileName, isLastCompiland) =
{
ConditionalDirectives = []
CodeComments = []
}
},
Set.empty
)
)
......
......@@ -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)
......
......@@ -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
......
......@@ -142,7 +142,8 @@ module IncrementalBuildSyntaxTree =
[],
[],
isLastCompiland,
{ ConditionalDirectives = []; CodeComments = [] }
{ ConditionalDirectives = []; CodeComments = [] },
Set.empty
)
)
else
......@@ -292,7 +293,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 =
......
......@@ -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
use ptr = fixed semanticClassification
b.WriteBytes(
NativePtr.ofNativeInt (NativePtr.toNativeInt ptr),
semanticClassification.Length * sizeof<SemanticClassificationItem>
)
member _.TryBuildAndReset() =
if b.Count > 0 then
......
......@@ -81,6 +81,18 @@ module Helpers =
let AreSubsumable3 ((fileName1: string, _, o1: FSharpProjectOptions), (fileName2: string, _, o2: FSharpProjectOptions)) =
(fileName1 = fileName2) && FSharpProjectOptions.UseSameProject(o1, o2)
/// If a symbol is an attribute check if given set of names contains its name without the Attribute suffix
let rec NamesContainAttribute (symbol: FSharpSymbol) names =
match symbol with
| :? FSharpMemberOrFunctionOrValue as mofov ->
mofov.DeclaringEntity
|> Option.map (fun entity -> NamesContainAttribute entity names)
|> Option.defaultValue false
| :? FSharpEntity as entity when entity.IsAttributeType && symbol.DisplayNameCore.EndsWithOrdinal "Attribute" ->
let nameWithoutAttribute = String.dropSuffix symbol.DisplayNameCore "Attribute"
names |> Set.contains nameWithoutAttribute
| _ -> false
module CompileHelpers =
let mkCompilationDiagnosticsHandlers () =
let diagnostics = ResizeArray<_>()
......@@ -1445,12 +1457,26 @@ type FSharpChecker
options: FSharpProjectOptions,
symbol: FSharpSymbol,
?canInvalidateProject: bool,
?fastCheck: bool,
?userOpName: string
) =
let canInvalidateProject = defaultArg canInvalidateProject true
let userOpName = defaultArg userOpName "Unknown"
backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
node {
if fastCheck <> Some true then
return! backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
else
let! parseResults = backgroundCompiler.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName)
if
parseResults.ParseTree.Identifiers |> Set.contains symbol.DisplayNameCore
|| parseResults.ParseTree.Identifiers |> NamesContainAttribute symbol
then
return! backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
else
return Seq.empty
}
|> Async.AwaitNodeCode
member _.GetBackgroundSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, ?userOpName) =
......
......@@ -300,12 +300,14 @@ type public FSharpChecker =
/// <param name="options">The options for the project or script, used to determine active --define conditionals and other options relevant to parsing.</param>
/// <param name="symbol">The symbol to find all uses in the file.</param>
/// <param name="canInvalidateProject">Default: true. If true, this call can invalidate the current state of project if the options have changed. If false, the current state of the project will be used.</param>
/// <param name="fastCheck">Default: false. Experimental feature that makes the operation faster.</param>
/// <param name="userOpName">An optional string used for tracing compiler operations associated with this request.</param>
member FindBackgroundReferencesInFile:
fileName: string *
options: FSharpProjectOptions *
symbol: FSharpSymbol *
?canInvalidateProject: bool *
?fastCheck: bool *
?userOpName: string ->
Async<range seq>
......
......@@ -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)
......@@ -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)
......@@ -1755,3 +1757,9 @@ type ParsedInput =
| ParsedInput.ImplFile (ParsedImplFileInput(contents = SynModuleOrNamespace (range = m) :: _))
| ParsedInput.SigFile (ParsedSigFileInput(contents = SynModuleOrNamespaceSig (range = m) :: _)) -> m
| _ -> rangeN inp.FileName 0
[<Experimental("This FCS API is experimental and subject to change.")>]
member inp.Identifiers =
match inp with
| ParsedInput.ImplFile (ParsedImplFileInput (identifiers = identifiers))
| ParsedInput.SigFile (ParsedSigFileInput (identifiers = identifiers)) -> identifiers
......@@ -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
......@@ -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
......@@ -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>
......@@ -202,6 +202,7 @@
<Compile Include="Globalization\GlobalizationTestCases.fs" />
<Compile Include="OCamlCompat\OCamlCompat.fs" />
<Compile Include="Miscellaneous\ListLiterals.fs" />
<Compile Include="Miscellaneous\SemanticClassificationKeyBuilder.fs" />
<Compile Include="Miscellaneous\XmlDoc.fs" />
<Compile Include="Signatures\TestHelpers.fs" />
<Compile Include="Signatures\ModuleOrNamespaceTests.fs" />
......
module FSharp.Compiler.ComponentTests.FSharpChecker.FindReferences
open FSharp.Compiler.CodeAnalysis
open Xunit
open FSharp.Compiler.CodeAnalysis
open FSharp.Test.ProjectGeneration
type Occurence = Definition | InType | Use
......@@ -53,7 +53,7 @@ let ``Finding usage of type via FindReference should also find it's constructors
createProject().Workflow
{
placeCursor "First" 7 11 "type MyType() =" ["MyType"]
findAllReferences "First" (fun (ranges:list<FSharp.Compiler.Text.range>) ->
findAllReferencesInFile "First" (fun (ranges:list<FSharp.Compiler.Text.range>) ->
let ranges =
ranges
|> List.sortBy (fun r -> r.StartLine)
......@@ -82,7 +82,7 @@ secondA.DoNothing(secondB)
project.Workflow
{
placeCursor "First" 7 11 "type MyType() =" ["MyType"]
findAllReferences "Second" (fun (ranges:list<FSharp.Compiler.Text.range>) ->
findAllReferencesInFile "Second" (fun (ranges:list<FSharp.Compiler.Text.range>) ->
let ranges =
ranges
|> List.sortBy (fun r -> r.StartLine)
......@@ -96,3 +96,97 @@ secondA.DoNothing(secondB)
}
[<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" true (expectNumberOfResults 5)
}
[<Fact>]
let ``We find back-ticked identifiers`` () =
SyntheticProject.Create(
{ sourceFile "First" [] with ExtraSource = "let ``foo bar`` x = x + 5" },
{ sourceFile "Second" [] with ExtraSource = "let foo x = ModuleFirst.``foo bar`` x" })
.Workflow {
placeCursor "Second" 6 35 "let foo x = ModuleFirst.``foo bar`` x" ["``foo bar``"]
findAllReferences (expectToFind [
"FileFirst.fs", 6, 4, 15
"FileSecond.fs", 6, 12, 35
])
}
[<Fact>]
let ``We find operators`` () =
SyntheticProject.Create(
{ sourceFile "First" [] with ExtraSource = "let (++) x y = x - y" },
{ sourceFile "Second" [] with ExtraSource = """
open ModuleFirst
let foo x = x ++ 4""" })
.Workflow {
placeCursor "Second" 8 16 "let foo x = x ++ 4" ["++"]
findAllReferences (expectToFind [
"FileFirst.fs", 6, 5, 7
"FileSecond.fs", 8, 14, 16
])
}
module Attributes =
let project() = SyntheticProject.Create(
{ sourceFile "First" [] with ExtraSource = "type MyAttribute() = inherit System.Attribute()" },
{ sourceFile "Second" [] with ExtraSource = """
open ModuleFirst
[<My>]
let foo x = 4""" },
{ sourceFile "Third" [] with ExtraSource = """
open ModuleFirst
[<MyAttribute>]
let foo x = 5""" })
[<Fact>]
let ``We find attributes from definition`` () =
project().Workflow {
placeCursor "First" 6 16 "type MyAttribute() = inherit System.Attribute()" ["MyAttribute"]
findAllReferences (expectToFind [
"FileFirst.fs", 6, 5, 16
"FileSecond.fs", 8, 2, 4
"FileThird.fs", 8, 2, 13
])
}
[<Fact>]
let ``We find attributes from usage`` () =
project().Workflow {
placeCursor "Second" 8 4 "[<My>]" ["My"]
findAllReferences (expectToFind [
"FileFirst.fs", 6, 5, 16
"FileSecond.fs", 8, 2, 4
"FileThird.fs", 8, 2, 13
])
}
[<Fact>]
let ``We find attributes from usage with Attribute suffix`` () =
project().Workflow {
placeCursor "Third" 8 13 "[<MyAttribute>]" ["MyAttribute"]
findAllReferences (expectToFind [
"FileFirst.fs", 6, 5, 16
"FileSecond.fs", 8, 2, 4
"FileThird.fs", 8, 2, 13
])
}
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
module FSharp.Compiler.ComponentTests.Miscellaneous.SemanticClassificationKeyStoreBuilder
open Xunit
open FSharp.Compiler.EditorServices
[<Fact>]
let ``Build empty`` () =
let sckBuilder = SemanticClassificationKeyStoreBuilder()
sckBuilder.WriteAll [||]
let res = sckBuilder.TryBuildAndReset()
Assert.Equal(None, res)
......@@ -2026,7 +2026,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
......@@ -5600,7 +5600,7 @@ FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean get_IsLastCompiland()
FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean get_IsScript()
FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean get_isScript()
FSharp.Compiler.Syntax.ParsedImplFileInput: Boolean isScript
FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.ParsedImplFileInput NewParsedImplFileInput(System.String, Boolean, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace], System.Tuple`2[System.Boolean,System.Boolean], FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia)
FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.ParsedImplFileInput NewParsedImplFileInput(System.String, Boolean, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace], System.Tuple`2[System.Boolean,System.Boolean], FSharp.Compiler.SyntaxTrivia.ParsedImplFileInputTrivia, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile QualifiedName
FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_QualifiedName()
FSharp.Compiler.Syntax.ParsedImplFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_qualifiedNameOfFile()
......@@ -5623,6 +5623,8 @@ FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpL
FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace] contents
FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace] get_Contents()
FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespace] get_contents()
FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] get_identifiers()
FSharp.Compiler.Syntax.ParsedImplFileInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] identifiers
FSharp.Compiler.Syntax.ParsedImplFileInput: System.String FileName
FSharp.Compiler.Syntax.ParsedImplFileInput: System.String ToString()
FSharp.Compiler.Syntax.ParsedImplFileInput: System.String fileName
......@@ -5654,6 +5656,8 @@ FSharp.Compiler.Syntax.ParsedInput: Int32 Tag
FSharp.Compiler.Syntax.ParsedInput: Int32 get_Tag()
FSharp.Compiler.Syntax.ParsedInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma] ScopedPragmas
FSharp.Compiler.Syntax.ParsedInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma] get_ScopedPragmas()
FSharp.Compiler.Syntax.ParsedInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] Identifiers
FSharp.Compiler.Syntax.ParsedInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] get_Identifiers()
FSharp.Compiler.Syntax.ParsedInput: System.String FileName
FSharp.Compiler.Syntax.ParsedInput: System.String ToString()
FSharp.Compiler.Syntax.ParsedInput: System.String get_FileName()
......@@ -5718,7 +5722,7 @@ FSharp.Compiler.Syntax.ParsedSigFileFragment: Int32 Tag
FSharp.Compiler.Syntax.ParsedSigFileFragment: Int32 get_Tag()
FSharp.Compiler.Syntax.ParsedSigFileFragment: System.String ToString()
FSharp.Compiler.Syntax.ParsedSigFileInput
FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.ParsedSigFileInput NewParsedSigFileInput(System.String, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig], FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia)
FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.ParsedSigFileInput NewParsedSigFileInput(System.String, FSharp.Compiler.Syntax.QualifiedNameOfFile, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ScopedPragma], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.ParsedHashDirective], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig], FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile QualifiedName
FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_QualifiedName()
FSharp.Compiler.Syntax.ParsedSigFileInput: FSharp.Compiler.Syntax.QualifiedNameOfFile get_qualifiedNameOfFile()
......@@ -5741,6 +5745,8 @@ FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpLi
FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig] contents
FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig] get_Contents()
FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynModuleOrNamespaceSig] get_contents()
FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] get_identifiers()
FSharp.Compiler.Syntax.ParsedSigFileInput: Microsoft.FSharp.Collections.FSharpSet`1[System.String] identifiers
FSharp.Compiler.Syntax.ParsedSigFileInput: System.String FileName
FSharp.Compiler.Syntax.ParsedSigFileInput: System.String ToString()
FSharp.Compiler.Syntax.ParsedSigFileInput: System.String fileName
......@@ -28,7 +28,10 @@ let private projectRoot = "test-projects"
let private defaultFunctionName = "f"
type SignatureFile = No | AutoGenerated | Custom of string
type SignatureFile =
| No
| AutoGenerated
| Custom of string
type SyntheticSourceFile =
......@@ -48,6 +51,8 @@ type SyntheticSourceFile =
member this.FileName = $"File{this.Id}.fs"
member this.SignatureFileName = $"{this.FileName}i"
member this.TypeName = $"T{this.Id}V_{this.PublicVersion}"
member this.ModuleName = $"Module{this.Id}"
member this.HasSignatureFile =
match this.SignatureFile with
......@@ -76,13 +81,12 @@ type SyntheticProject =
static member Create(?name: string) =
let name = defaultArg name $"TestProject_{Guid.NewGuid().ToString()[..7]}"
let dir = Path.GetFullPath projectRoot
{
Name = name
ProjectDir = dir ++ name
SourceFiles = []
DependsOn = []
RecursiveNamespace = false
}
{ Name = name
ProjectDir = dir ++ name
SourceFiles = []
DependsOn = []
RecursiveNamespace = false }
static member Create([<ParamArray>] sourceFiles: SyntheticSourceFile[]) =
{ SyntheticProject.Create() with SourceFiles = sourceFiles |> List.ofArray }
......@@ -151,14 +155,14 @@ module Internal =
seq {
if project.RecursiveNamespace then
$"namespace rec {project.Name}"
$"module Module{f.Id}"
$"module {f.ModuleName}"
else
$"module %s{project.Name}.Module{f.Id}"
$"module %s{project.Name}.{f.ModuleName}"
for p in project.DependsOn do
$"open {p.Name}"
$"type T{f.Id}V_{f.PublicVersion}<'a> = T{f.Id} of 'a"
$"type {f.TypeName}<'a> = T{f.Id} of 'a"
$"let {f.FunctionName} x ="
......@@ -274,7 +278,8 @@ module ProjectOperations =
let addDependency fileId f : SyntheticSourceFile =
{ f with DependsOn = fileId :: f.DependsOn }
let addSignatureFile f = { f with SignatureFile = AutoGenerated }
let addSignatureFile f =
{ f with SignatureFile = AutoGenerated }
let checkFile fileId (project: SyntheticProject) (checker: FSharpChecker) =
let file = project.Find fileId
......@@ -328,6 +333,18 @@ module ProjectOperations =
expectOk result ()
Assert.Equal<string>(oldSignature, newSignature)
let expectNumberOfResults expected (results: 'a list) =
if results.Length <> expected then
failwith $"Found {results.Length} references but expected to find {expected}"
let expectToFind expected (foundRanges: range seq) =
let actual =
foundRanges
|> Seq.map (fun r -> Path.GetFileName(r.FileName), r.StartLine, r.StartColumn, r.EndColumn)
|> Seq.sortBy (fun (file, _, _, _) -> file)
|> Seq.toArray
Assert.Equal<(string * int * int * int)[]>(expected |> Seq.toArray, actual)
let rec saveProject (p: SyntheticProject) generateSignatureFiles checker =
async {
Directory.CreateDirectory(p.ProjectDir) |> ignore
......@@ -347,17 +364,43 @@ module ProjectOperations =
let! results = checkFile file.Id project checker
let signature = getSignature results
writeFileIfChanged signatureFileName signature
| Custom signature ->
writeFileIfChanged signatureFileName signature
| Custom signature -> writeFileIfChanged signatureFileName signature
| _ -> ()
writeFileIfChanged (p.ProjectDir ++ $"{p.Name}.fsproj") (renderFsProj p)
}
type WorkflowContext =
{ Project: SyntheticProject
Signatures: Map<string, string>
Cursor : FSharp.Compiler.CodeAnalysis.FSharpSymbolUse option }
Cursor: FSharpSymbolUse option }
let SaveAndCheckProject project checker =
async {
validateFileIdsAreUnique project
do! saveProject project true checker
let! results = checker.ParseAndCheckProject(project.GetProjectOptions checker)
if not (Array.isEmpty results.Diagnostics) then
failwith $"Project {project.Name} failed initial check: \n%A{results.Diagnostics}"
let! signatures =
Async.Sequential
[ for file in project.SourceFiles do
async {
let! result = checkFile file.Id project checker
let signature = getSignature result
return file.Id, signature
} ]
return
{ Project = project
Signatures = Map signatures
Cursor = None }
}
type ProjectWorkflowBuilder(initialProject: SyntheticProject, ?checker: FSharpChecker) =
......@@ -379,37 +422,17 @@ type ProjectWorkflowBuilder(initialProject: SyntheticProject, ?checker: FSharpCh
member this.Checker = checker
member this.Yield _ =
async {
validateFileIdsAreUnique initialProject
do! saveProject initialProject true checker
let! results = checker.ParseAndCheckProject(initialProject.GetProjectOptions checker)
SaveAndCheckProject initialProject checker
if not (Array.isEmpty results.Diagnostics) then
failwith $"Project {initialProject.Name} failed initial check: \n%A{results.Diagnostics}"
let! signatures =
Async.Sequential
[ for file in initialProject.SourceFiles do
async {
let! result = checkFile file.Id initialProject checker
let signature = getSignature result
return file.Id, signature
} ]
return
{ Project = initialProject
Signatures = Map signatures
Cursor = None }
}
member this.DeleteProjectDir() =
if Directory.Exists initialProject.ProjectDir then
Directory.Delete(initialProject.ProjectDir, true)
member this.Run(workflow: Async<WorkflowContext>) =
try
Async.RunSynchronously workflow
finally
if Directory.Exists initialProject.ProjectDir then
Directory.Delete(initialProject.ProjectDir, true)
this.DeleteProjectDir()
/// Change contents of given file using `processFile` function.
/// Does not save the file to disk.
......@@ -451,51 +474,79 @@ type ProjectWorkflowBuilder(initialProject: SyntheticProject, ?checker: FSharpCh
return { ctx with Signatures = ctx.Signatures.Add(fileId, newSignature) }
}
/// Find a symbol using the provided range, mimicing placing a cursor on it in IDE scenarios
[<CustomOperation "placeCursor">]
member this.PlaceCursor(workflow: Async<WorkflowContext>, fileId, line, colAtEndOfNames, fullLine, symbolNames) =
member this.CheckFile(workflow: Async<WorkflowContext>, fileId: string, processResults) =
async {
let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let typeCheckResults = getTypeCheckResult results
let su = typeCheckResults.GetSymbolUseAtLocation(line,colAtEndOfNames,fullLine,symbolNames)
let newSignature = getSignature results
processResults typeCheckResults
return {ctx with Cursor = su}
return { ctx with Signatures = ctx.Signatures.Add(fileId, newSignature) }
}
/// Find a symbol using the provided range, mimicking placing a cursor on it in IDE scenarios
[<CustomOperation "placeCursor">]
member this.PlaceCursor(workflow: Async<WorkflowContext>, fileId, line, colAtEndOfNames, fullLine, symbolNames) =
async {
let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let typeCheckResults = getTypeCheckResult results
let su =
typeCheckResults.GetSymbolUseAtLocation(line, colAtEndOfNames, fullLine, symbolNames)
if su.IsNone then
let file = ctx.Project.Find fileId
failwith $"No symbol found in {file.FileName} at {line}:{colAtEndOfNames}\nFile contents:\n\n{renderSourceFile ctx.Project file}\n"
return { ctx with Cursor = su }
}
/// Find all references within a single file, results are provided to the 'processResults' function
[<CustomOperation "findAllReferences">]
member this.FindAllReferences(workflow: Async<WorkflowContext>, fileId: string, processResults) =
async{
[<CustomOperation "findAllReferencesInFile">]
member this.FindAllReferencesInFile(workflow: Async<WorkflowContext>, fileId: string, processResults) =
async {
let! ctx = workflow
let po = ctx.Project.GetProjectOptions checker
let s = ctx.Cursor |> Option.defaultWith (fun () -> failwith $"Please place cursor at a valid location via {nameof(this.PlaceCursor)} first")
let file = ctx.Project.Find fileId
let options = ctx.Project.GetProjectOptions checker
let symbolUse =
ctx.Cursor
|> Option.defaultWith (fun () ->
failwith $"Please place cursor at a valid location via {nameof this.PlaceCursor} first")
let file = ctx.Project.Find fileId
let absFileName = ctx.Project.ProjectDir ++ file.FileName
let! results = checker.FindBackgroundReferencesInFile(absFileName,po, s.Symbol)
let! results = checker.FindBackgroundReferencesInFile(absFileName, options, symbolUse.Symbol, fastCheck = true)
processResults (results |> Seq.toList)
return ctx
}
/// Parse and type check given file and process the results using `processResults` function.
[<CustomOperation "checkFile">]
member this.CheckFile(workflow: Async<WorkflowContext>, fileId: string, processResults) =
/// Find all references within the project, results are provided to the 'processResults' function
[<CustomOperation "findAllReferences">]
member this.FindAllReferences(workflow: Async<WorkflowContext>, processResults) =
async {
let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let typeCheckResults = getTypeCheckResult results
let options = ctx.Project.GetProjectOptions checker
let newSignature = getSignature results
let symbolUse =
ctx.Cursor
|> Option.defaultWith (fun () ->
failwith $"Please place cursor at a valid location via {nameof this.PlaceCursor} first")
processResults typeCheckResults
let! results =
[ for f in options.SourceFiles do
checker.FindBackgroundReferencesInFile(f, options, symbolUse.Symbol, fastCheck = true) ]
|> Async.Parallel
return { ctx with Signatures = ctx.Signatures.Add(fileId, newSignature) }
results |> Seq.collect id |> Seq.toList |> processResults
return ctx
}
/// Save given file to disk.
[<CustomOperation "saveFile">]
member this.SaveFile(workflow: Async<WorkflowContext>, fileId: string) =
......@@ -515,12 +566,65 @@ type ProjectWorkflowBuilder(initialProject: SyntheticProject, ?checker: FSharpCh
return ctx
}
/// Find all references to a module defined in a given file.
/// These should only be found in files that depend on this file.
///
/// Requires `enableBackgroundItemKeyStoreAndSemanticClassification` to be true in the checker.
[<CustomOperation "findAllReferencesToModuleFromFile">]
member this.FindAllReferencesToModuleFromFile(workflow, fileId, fastCheck, processResults) =
async {
let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let typeCheckResult = getTypeCheckResult results
let moduleName = (ctx.Project.Find fileId).ModuleName
let symbolUse =
typeCheckResult.GetSymbolUseAtLocation(
1,
moduleName.Length + ctx.Project.Name.Length + 8,
$"module {ctx.Project.Name}.{moduleName}",
[ moduleName ]
)
|> Option.defaultWith (fun () -> failwith "no symbol use found")
let options = ctx.Project.GetProjectOptions checker
let! results =
[ for f in options.SourceFiles do
checker.FindBackgroundReferencesInFile(f, options, symbolUse.Symbol, fastCheck = fastCheck) ]
|> Async.Parallel
results |> Seq.collect id |> Seq.toList |> processResults
return ctx
}
/// Execute a set of operations on a given synthetic project.
/// The project is saved to disk and type checked at the start.
let projectWorkflow project = ProjectWorkflowBuilder project
/// Just like ProjectWorkflowBuilder but expects a saved and checked project
/// so time is not spent on it during the benchmark.
/// Also does not delete the project at the end of a run - so it keeps working for the next iteration
type ProjectBenchmarkBuilder(initialContext: WorkflowContext, checker) =
inherit ProjectWorkflowBuilder(initialContext.Project, checker)
static member Create(initialProject, ?checker) =
async {
let checker = defaultArg checker (FSharpChecker.Create())
let! initialContext = SaveAndCheckProject initialProject checker
return ProjectBenchmarkBuilder(initialContext, checker)
}
member this.Yield _ = async.Return initialContext
member this.Run(workflow: Async<WorkflowContext>) = Async.RunSynchronously workflow
type SyntheticProject with
/// Execute a set of operations on this project.
/// The project is saved to disk and type checked at the start.
member this.Workflow = projectWorkflow this
member this.WorkflowWith checker = ProjectWorkflowBuilder(this, checker)
module FSharp.Benchmarks.BackgroundCompilerBenchmarks
open System.IO
open BenchmarkDotNet.Attributes
open FSharp.Test.ProjectGeneration
open FSharp.Compiler.CodeAnalysis
[<Literal>]
let FSharpCategory = "fsharp"
[<MemoryDiagnoser>]
[<BenchmarkCategory(FSharpCategory)>]
type BackgroundCompilerBenchmarks () =
let size = 50
let somethingToCompile = File.ReadAllText (__SOURCE_DIRECTORY__ ++ "SomethingToCompile.fs")
[<ParamsAllValues>]
member val FastFindReferences = true with get,set
[<ParamsAllValues>]
member val EmptyCache = true with get,set
member val Benchmark = Unchecked.defaultof<ProjectBenchmarkBuilder> with get, set
member this.setup(project) =
let checker = FSharpChecker.Create(
enableBackgroundItemKeyStoreAndSemanticClassification = true
)
this.Benchmark <- ProjectBenchmarkBuilder.Create(project, checker) |> Async.RunSynchronously
[<IterationSetup>]
member this.EditFirstFile_OnlyInternalChange() =
if this.EmptyCache then
this.Benchmark.Checker.InvalidateAll()
this.Benchmark.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
/// Only file at the top of the list has the reference
[<GlobalSetup(Target="FindAllReferences_BestCase")>]
member this.FindAllReferences_BestCase_Setup() =
this.setup
{ SyntheticProject.Create() with
SourceFiles = [
sourceFile $"File%03d{0}" [] |> addSignatureFile
for i in 1..size do
{ sourceFile $"File%03d{i}" [$"File%03d{i-1}"] with ExtraSource = somethingToCompile }
]
}
[<Benchmark>]
member this.FindAllReferences_BestCase() =
this.Benchmark {
findAllReferencesToModuleFromFile "File000" this.FastFindReferences (expectNumberOfResults 3)
}
/// Few files in the middle have the reference
[<GlobalSetup(Target="FindAllReferences_MediumCase")>]
member this.FindAllReferences_MediumCase_Setup() =
this.setup(
{ SyntheticProject.Create() with
SourceFiles = [
sourceFile $"File%03d{0}" [] |> addSignatureFile
for i in 1..size do
{ sourceFile $"File%03d{i}" [$"File%03d{i-1}"] with ExtraSource = somethingToCompile }
]
}
|> updateFile $"File%03d{size / 2 - 1}" (addDependency "File000")
|> updateFile $"File%03d{size / 2 }" (addDependency "File000")
|> updateFile $"File%03d{size / 2 + 1}" (addDependency "File000"))
[<Benchmark>]
member this.FindAllReferences_MediumCase() =
this.Benchmark {
findAllReferencesToModuleFromFile "File000" this.FastFindReferences (expectNumberOfResults 6)
}
/// All files have the reference, have to check everything
[<GlobalSetup(Target="FindAllReferences_WorstCase")>]
member this.FindAllReferences_WorstCase_Setup() =
this.setup
{ SyntheticProject.Create() with
SourceFiles = [
sourceFile $"File%03d{0}" [] |> addSignatureFile
for i in 1..size do
{ sourceFile $"File%03d{i}" [$"File000"] with ExtraSource = somethingToCompile }
]
}
[<Benchmark>]
member this.FindAllReferences_WorstCase() =
this.Benchmark {
findAllReferencesToModuleFromFile "File000" this.FastFindReferences (expectNumberOfResults (size + 2))
}
[<GlobalCleanup>]
member this.Cleanup() =
this.Benchmark.DeleteProjectDir()
......@@ -15,6 +15,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="BackgroundCompilerBenchmarks.fs" />
<Compile Include="SourceText.fs" />
<Compile Include="DecentlySizedStandAloneFileBenchmark.fs" />
<Compile Include="CompilerServiceBenchmarks.fs" />
......@@ -29,6 +30,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Compiler\FSharp.Compiler.Service.fsproj" />
<ProjectReference Include="..\..\..\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj" />
<ProjectReference Include="..\BenchmarkComparison\HistoricalBenchmark.fsproj" />
</ItemGroup>
......
open BenchmarkDotNet.Running
open FSharp.Compiler.Benchmarks
open BenchmarkDotNet.Configs
[<EntryPoint>]
let main args =
......
......@@ -206,7 +206,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</value>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</value>
</data>
<data name="6012" xml:space="preserve">
<value>Advanced</value>
......
......@@ -76,9 +76,8 @@ type internal InlineRenameInfo
| true, text -> text
| _ -> document.GetTextAsync(cancellationToken).Result
let symbolUses =
SymbolHelpers.getSymbolUsesInSolution(symbolUse.Symbol, declLoc, checkFileResults, document.Project.Solution)
|> Async.cache
let symbolUses ct =
SymbolHelpers.getSymbolUsesInSolution(symbolUse.Symbol, declLoc, checkFileResults, document.Project.Solution, ct)
override _.CanRename = true
override _.LocalizedErrorMessage = null
......@@ -104,7 +103,7 @@ type internal InlineRenameInfo
override _.FindRenameLocationsAsync(_, _, cancellationToken) =
async {
let! symbolUsesByDocumentId = symbolUses
let! symbolUsesByDocumentId = symbolUses cancellationToken
let! locations =
symbolUsesByDocumentId
|> Seq.map (fun (KeyValue(documentId, symbolUses)) ->
......
......@@ -3,6 +3,7 @@
namespace Microsoft.VisualStudio.FSharp.Editor
open System
open System.Collections.Concurrent
open System.Collections.Immutable
open System.Threading
open System.Threading.Tasks
......@@ -10,7 +11,6 @@ open System.Threading.Tasks
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Text
open FSharp.Compiler
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
......@@ -36,12 +36,13 @@ module internal SymbolHelpers =
return symbolUses
}
let getSymbolUsesInProjects (symbol: FSharpSymbol, projects: Project list, onFound: Document -> TextSpan -> range -> Async<unit>) =
let getSymbolUsesInProjects (symbol: FSharpSymbol, projects: Project list, onFound: Document -> TextSpan -> range -> Async<unit>, ct: CancellationToken) =
projects
|> Seq.map (fun project -> project.FindFSharpReferencesAsync(symbol, onFound, "getSymbolUsesInProjects"))
|> Async.Parallel
|> Seq.map (fun project ->
Task.Run(fun () -> project.FindFSharpReferencesAsync(symbol, onFound, "getSymbolUsesInProjects", ct)))
|> Task.WhenAll
let getSymbolUsesInSolution (symbol: FSharpSymbol, declLoc: SymbolDeclarationLocation, checkFileResults: FSharpCheckFileResults, solution: Solution) =
let getSymbolUsesInSolution (symbol: FSharpSymbol, declLoc: SymbolDeclarationLocation, checkFileResults: FSharpCheckFileResults, solution: Solution, ct: CancellationToken) =
async {
let toDict (symbolUseRanges: range seq) =
let groups =
......@@ -59,7 +60,7 @@ module internal SymbolHelpers =
let symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbol, ct)
return toDict (symbolUses |> Seq.map (fun symbolUse -> symbolUse.Range))
| SymbolDeclarationLocation.Projects (projects, isInternalToProject) ->
let symbolUseRanges = ImmutableArray.CreateBuilder()
let symbolUseRanges = ConcurrentBag()
let projects =
if isInternalToProject then projects
......@@ -73,11 +74,11 @@ module internal SymbolHelpers =
fun _ _ symbolUseRange ->
async { symbolUseRanges.Add symbolUseRange }
let! _ = getSymbolUsesInProjects (symbol, projects, onFound)
do! getSymbolUsesInProjects (symbol, projects, onFound, ct) |> Async.AwaitTask
// Distinct these down because each TFM will produce a new 'project'.
// Unless guarded by a #if define, symbols with the same range will be added N times
let symbolUseRanges = symbolUseRanges.ToArray() |> Array.distinct
let symbolUseRanges = symbolUseRanges |> Seq.distinct
return toDict symbolUseRanges
}
......@@ -115,7 +116,7 @@ module internal SymbolHelpers =
Func<_,_>(fun (cancellationToken: CancellationToken) ->
async {
let! symbolUsesByDocumentId =
getSymbolUsesInSolution(symbolUse.Symbol, declLoc, checkFileResults, document.Project.Solution)
getSymbolUsesInSolution(symbolUse.Symbol, declLoc, checkFileResults, document.Project.Solution, cancellationToken)
let mutable solution = document.Project.Solution
......
......@@ -4,9 +4,11 @@ module internal Microsoft.VisualStudio.FSharp.Editor.WorkspaceExtensions
open System
open System.Runtime.CompilerServices
open System.Threading
open System.Threading.Tasks
open Microsoft.CodeAnalysis
open FSharp.Compiler
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
[<AutoOpen>]
module private CheckerExtensions =
......@@ -183,10 +185,12 @@ type Document with
member this.FindFSharpReferencesAsync(symbol, onFound, userOpName) =
async {
let! checker, _, _, projectOptions = this.GetFSharpCompilationOptionsAsync(userOpName)
let! symbolUses = checker.FindBackgroundReferencesInFile(this.FilePath, projectOptions, symbol, canInvalidateProject = false)
let! symbolUses = checker.FindBackgroundReferencesInFile(this.FilePath, projectOptions, symbol,
canInvalidateProject = false,
fastCheck = this.Project.IsFastFindReferencesEnabled)
let! ct = Async.CancellationToken
let! sourceText = this.GetTextAsync ct |> Async.AwaitTask
for symbolUse in symbolUses do
for symbolUse in symbolUses do
match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse) with
| Some textSpan ->
do! onFound textSpan symbolUse
......@@ -215,8 +219,31 @@ type Document with
type Project with
/// Find F# references in the given project.
member this.FindFSharpReferencesAsync(symbol, onFound, userOpName) =
async {
for doc in this.Documents do
member this.FindFSharpReferencesAsync(symbol: FSharpSymbol, onFound, userOpName, ct) : Task = backgroundTask {
let declarationLocation = symbol.SignatureLocation |> Option.map Some |> Option.defaultValue symbol.DeclarationLocation
let declarationDocument = declarationLocation |> Option.bind this.Solution.TryGetDocumentFromFSharpRange
let! canSkipDocuments =
match declarationDocument with
| Some document when this.IsFastFindReferencesEnabled && document.Project = this ->
backgroundTask {
let! _, _, _, options = document.GetFSharpCompilationOptionsAsync(userOpName) |> RoslynHelpers.StartAsyncAsTask ct
return options.SourceFiles |> Seq.takeWhile ((<>) document.FilePath) |> Set
}
| _ -> Task.FromResult Set.empty
let documents = this.Documents |> Seq.filter (fun document -> not (canSkipDocuments.Contains document.FilePath))
if this.IsFastFindReferencesEnabled then
do! documents
|> Seq.map (fun doc ->
Task.Run(fun () ->
doc.FindFSharpReferencesAsync(symbol, (fun textSpan range -> onFound doc textSpan range), userOpName)
|> RoslynHelpers.StartAsyncUnitAsTask ct))
|> Task.WhenAll
else
for doc in documents do
do! doc.FindFSharpReferencesAsync(symbol, (fun textSpan range -> onFound doc textSpan range), userOpName)
}
|> RoslynHelpers.StartAsyncAsTask ct
}
......@@ -121,9 +121,8 @@ type internal FSharpFindUsagesService
// The symbol is declared in .NET framework, an external assembly or in a C# project within the solution.
// In order to find all its usages we have to check all F# projects.
| _ -> Seq.toList document.Project.Solution.Projects
let! _ = SymbolHelpers.getSymbolUsesInProjects (symbolUse.Symbol, projectsToCheck, onFound) |> liftAsync
()
let! ct = Async.CancellationToken |> liftAsync
do! SymbolHelpers.getSymbolUsesInProjects (symbolUse.Symbol, projectsToCheck, onFound, ct) |> Async.AwaitTask |> liftAsync
} |> Async.Ignore
interface IFSharpFindUsagesService with
......
......@@ -59,18 +59,20 @@ type CodeFixesOptions =
SuggestNamesForErrors = true }
[<CLIMutable>]
type LanguageServicePerformanceOptions =
type LanguageServicePerformanceOptions =
{ EnableInMemoryCrossProjectReferences: bool
AllowStaleCompletionResults: bool
TimeUntilStaleCompletion: int
EnableParallelCheckingWithSignatureFiles: bool
EnableParallelReferenceResolution: bool }
EnableParallelReferenceResolution: bool
EnableFastFindReferences: bool }
static member Default =
{ EnableInMemoryCrossProjectReferences = true
AllowStaleCompletionResults = true
TimeUntilStaleCompletion = 2000 // In ms, so this is 2 seconds
EnableParallelCheckingWithSignatureFiles = false
EnableParallelReferenceResolution = false }
EnableParallelReferenceResolution = false
EnableFastFindReferences = false }
[<CLIMutable>]
type AdvancedOptions =
......@@ -180,50 +182,36 @@ module EditorOptionsExtensions =
type Project with
member this.AreFSharpInMemoryCrossProjectReferencesEnabled =
member private this.GetEditorOptions f fallback =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> true
| _ -> editorOptions.LanguageServicePerformance.EnableInMemoryCrossProjectReferences
| null -> fallback
| _ -> f editorOptions
member this.AreFSharpInMemoryCrossProjectReferencesEnabled =
this.GetEditorOptions (fun o -> o.LanguageServicePerformance.EnableInMemoryCrossProjectReferences) true
member this.IsFSharpCodeFixesAlwaysPlaceOpensAtTopLevelEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.CodeFixes.AlwaysPlaceOpensAtTopLevel
this.GetEditorOptions (fun o -> o.CodeFixes.AlwaysPlaceOpensAtTopLevel) false
member this.IsFSharpCodeFixesUnusedDeclarationsEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.CodeFixes.UnusedDeclarations
this.GetEditorOptions (fun o -> o.CodeFixes.UnusedDeclarations) false
member this.IsFSharpStaleCompletionResultsEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.LanguageServicePerformance.AllowStaleCompletionResults
this.GetEditorOptions (fun o -> o.LanguageServicePerformance.AllowStaleCompletionResults) false
member this.FSharpTimeUntilStaleCompletion =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> 0
| _ -> editorOptions.LanguageServicePerformance.TimeUntilStaleCompletion
this.GetEditorOptions (fun o -> o.LanguageServicePerformance.TimeUntilStaleCompletion) 0
member this.IsFSharpCodeFixesSimplifyNameEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.CodeFixes.SimplifyName
this.GetEditorOptions (fun o -> o.CodeFixes.SimplifyName) false
member this.IsFSharpCodeFixesUnusedOpensEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.CodeFixes.UnusedOpens
this.GetEditorOptions (fun o -> o.CodeFixes.UnusedOpens) false
member this.IsFSharpBlockStructureEnabled =
let editorOptions = this.Solution.Workspace.Services.GetService<EditorOptions>()
match box editorOptions with
| null -> false
| _ -> editorOptions.Advanced.IsBlockStructureEnabled
\ No newline at end of file
this.GetEditorOptions (fun o -> o.Advanced.IsBlockStructureEnabled) false
member this.IsFastFindReferencesEnabled =
this.GetEditorOptions (fun o -> o.LanguageServicePerformance.EnableFastFindReferences) false
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -154,7 +154,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</source>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</source>
<target state="new">F# Project and Caching Performance Options;
Enable in-memory cross project references;
IntelliSense Performance Options;
......@@ -162,7 +163,8 @@ Enable stale data for IntelliSense features;
Time until stale results are used (in milliseconds);
Parallelization (requires restart);
Enable parallel type checking with signature files;
Enable parallel reference resolution</target>
Enable parallel reference resolution;
Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="PrefixValueNameWithUnderscore">
......
......@@ -64,6 +64,13 @@
Content="{x:Static local:Strings.Enable_Parallel_Reference_Resolution}"/>
</StackPanel>
</GroupBox>
<GroupBox Header="{x:Static local:Strings.Find_References_Performance}">
<StackPanel>
<CheckBox x:Name="enableFastFindReferences"
IsChecked="{Binding EnableFastFindReferences}"
Content="{x:Static local:Strings.Enable_Fast_Find_References}"/>
</StackPanel>
</GroupBox>
</StackPanel>
</ScrollViewer>
</Grid>
......
......@@ -123,6 +123,15 @@ public class Strings {
}
}
/// <summary>
/// Looks up a localized string similar to Enable fast find references &amp; rename (experimental).
/// </summary>
public static string Enable_Fast_Find_References {
get {
return ResourceManager.GetString("Enable_Fast_Find_References", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Enable in-memory cross project references.
/// </summary>
......@@ -195,6 +204,15 @@ public class Strings {
}
}
/// <summary>
/// Looks up a localized string similar to Find References Performance Options.
/// </summary>
public static string Find_References_Performance {
get {
return ResourceManager.GetString("Find_References_Performance", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Re-format indentation on paste (Experimental).
/// </summary>
......
......@@ -234,4 +234,10 @@
<data name="Show_Inline_Parameter_Name_Hints" xml:space="preserve">
<value>Display inline parameter name hints (experimental)</value>
</data>
<data name="Enable_Fast_Find_References" xml:space="preserve">
<value>Enable fast find references &amp; rename (experimental)</value>
</data>
<data name="Find_References_Performance" xml:space="preserve">
<value>Find References Performance Options</value>
</data>
</root>
\ No newline at end of file
......@@ -7,6 +7,16 @@
<target state="translated">Vždy umístit otevřené příkazy na nejvyšší úroveň</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">open-Anweisungen immer an oberster Ebene platzieren</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Colocar siempre las instrucciones open en el nivel superior</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Placer toujours les instructions open au niveau supérieur</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Inserisci sempre le istruzioni OPEN al primo livello</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Open ステートメントを常に最上位に配置する</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">항상 최상위에 open 문 배치</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Zawsze umieszczaj otwarte instrukcje na najwyższym poziomie</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Sempre coloque as instruções abertas no nível superior</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Всегда располагайте открытые операторы на верхнем уровне</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">Açık deyimleri her zaman en üst düzeye yerleştir</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">始终在顶层放置 open 语句</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
......@@ -7,6 +7,16 @@
<target state="translated">一律將 open 陳述式放在最上層</target>
<note />
</trans-unit>
<trans-unit id="Enable_Fast_Find_References">
<source>Enable fast find references &amp; rename (experimental)</source>
<target state="new">Enable fast find references &amp; rename (experimental)</target>
<note />
</trans-unit>
<trans-unit id="Find_References_Performance">
<source>Find References Performance Options</source>
<target state="new">Find References Performance Options</target>
<note />
</trans-unit>
<trans-unit id="Inline_Hints">
<source>Inline Hints</source>
<target state="new">Inline Hints</target>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册