diff --git a/Classification/ColorizationService.fs b/Classification/ColorizationService.fs index b40aaa4d0a2..b60ee3b9bcc 100644 --- a/Classification/ColorizationService.fs +++ b/Classification/ColorizationService.fs @@ -40,9 +40,9 @@ type internal FSharpColorizationService asyncMaybe { do Trace.TraceInformation("{0:n3} (start) SemanticColorization", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.SemanticColorizationInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time - let! options = projectInfoManager.TryGetOptionsForDocumentOrProject(document) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = false, userOpName=userOpName) + let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = false, userOpName=userOpName) // it's crucial to not return duplicated or overlapping `ClassifiedSpan`s because Find Usages service crashes. let targetRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText) let colorizationData = checkResults.GetSemanticClassification (Some targetRange) |> Array.distinctBy fst diff --git a/CodeFix/AddOpenCodeFixProvider.fs b/CodeFix/AddOpenCodeFixProvider.fs index 92622f4fe7e..76f88464e7a 100644 --- a/CodeFix/AddOpenCodeFixProvider.fs +++ b/CodeFix/AddOpenCodeFixProvider.fs @@ -96,12 +96,12 @@ type internal FSharpAddOpenCodeFixProvider override __.RegisterCodeFixesAsync context : Task = asyncMaybe { let document = context.Document - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document let! sourceText = context.Document.GetTextAsync(context.CancellationToken) - let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, options, allowStaleResults = true, sourceText = sourceText, userOpName = userOpName) + let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText = sourceText, userOpName = userOpName) let line = sourceText.Lines.GetLineFromPosition(context.Span.End) let linePos = sourceText.Lines.GetLinePosition(context.Span.End) - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) let! symbol = asyncMaybe { diff --git a/CodeFix/ImplementInterfaceCodeFixProvider.fs b/CodeFix/ImplementInterfaceCodeFixProvider.fs index a37be23a58e..5cf5fcba215 100644 --- a/CodeFix/ImplementInterfaceCodeFixProvider.fs +++ b/CodeFix/ImplementInterfaceCodeFixProvider.fs @@ -139,12 +139,12 @@ type internal FSharpImplementInterfaceCodeFixProvider override __.RegisterCodeFixesAsync context : Task = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject context.Document + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject context.Document let cancellationToken = context.CancellationToken let! sourceText = context.Document.GetTextAsync(cancellationToken) - let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, options, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) + let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition context.Span.Start - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(context.Document.FilePath, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(context.Document.FilePath, parsingOptions) // Notice that context.Span doesn't return reliable ranges to find tokens at exact positions. // That's why we tokenize the line and try to find the last successive identifier token let tokens = Tokenizer.tokenizeLine(context.Document.Id, sourceText, context.Span.Start, context.Document.FilePath, defines) diff --git a/CodeFix/RemoveUnusedOpens.fs b/CodeFix/RemoveUnusedOpens.fs index fc6c71fb3a9..5e97220d08c 100644 --- a/CodeFix/RemoveUnusedOpens.fs +++ b/CodeFix/RemoveUnusedOpens.fs @@ -32,8 +32,8 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider let document = context.Document let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) - let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, options, checker) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) let changes = unusedOpens |> List.map (fun m -> diff --git a/CodeFix/RenameUnusedValue.fs b/CodeFix/RenameUnusedValue.fs index 7b544ca866a..710bd2244c8 100644 --- a/CodeFix/RenameUnusedValue.fs +++ b/CodeFix/RenameUnusedValue.fs @@ -54,10 +54,10 @@ type internal FSharpRenameUnusedValueCodeFixProvider // We have to use the additional check for backtickes because `IsOperatorOrBacktickedName` operates on display names // where backtickes are replaced with parens. if not (PrettyNaming.IsOperatorOrBacktickedName ident) && not (ident.StartsWith "``") then - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document - let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, allowStaleResults = true, sourceText = sourceText, userOpName=userOpName) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText = sourceText, userOpName=userOpName) let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText) - let defines = CompilerEnvironment.GetCompilationDefinesForEditing (document.FilePath, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing (document.FilePath, parsingOptions) let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, context.Span.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false) let lineText = (sourceText.Lines.GetLineFromPosition context.Span.Start).ToString() let! symbolUse = checkResults.GetSymbolUseAtLocation(m.StartLine, m.EndColumn, lineText, lexerSymbol.FullIsland, userOpName=userOpName) diff --git a/Commands/HelpContextService.fs b/Commands/HelpContextService.fs index 2c7ece30131..99bcd091c91 100644 --- a/Commands/HelpContextService.fs +++ b/Commands/HelpContextService.fs @@ -99,13 +99,13 @@ type internal FSharpHelpContextService member this.GetHelpTermAsync(document, textSpan, cancellationToken) = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) let textLine = sourceText.Lines.GetLineFromPosition(textSpan.Start) let tokens = Tokenizer.getColorizationData(document.Id, sourceText, textLine.Span, Some document.Name, defines, cancellationToken) - return! FSharpHelpContextService.GetHelpTerm(checkerProvider.Checker, sourceText, document.FilePath, options, textSpan, tokens, textVersion.GetHashCode()) + return! FSharpHelpContextService.GetHelpTerm(checkerProvider.Checker, sourceText, document.FilePath, projectOptions, textSpan, tokens, textVersion.GetHashCode()) } |> Async.map (Option.defaultValue "") |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/Commands/XmlDocCommandService.fs b/Commands/XmlDocCommandService.fs index 2af89506561..9d5c2990aec 100644 --- a/Commands/XmlDocCommandService.fs +++ b/Commands/XmlDocCommandService.fs @@ -67,9 +67,9 @@ type internal XmlDocCommandFilter // XmlDocable line #1 are 1-based, editor is 0-based let curLineNum = wpfTextView.Caret.Position.BufferPosition.GetContainingLine().LineNumber + 1 let! document = document.Value - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let sourceText = wpfTextView.TextBuffer.CurrentSnapshot.GetText() - let! parsedInput = checker.ParseDocument(document, options, sourceText, userOpName) + let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) let xmlDocables = XmlDocParser.getXmlDocables (sourceText, Some parsedInput) let xmlDocablesBelowThisLine = // +1 because looking below current line for e.g. a 'member' diff --git a/Completion/CompletionProvider.fs b/Completion/CompletionProvider.fs index f77988f2702..e30c0322b47 100644 --- a/Completion/CompletionProvider.fs +++ b/Completion/CompletionProvider.fs @@ -210,15 +210,15 @@ type internal FSharpCompletionProvider let! sourceText = context.Document.GetTextAsync(context.CancellationToken) let defines = projectInfoManager.GetCompilationDefinesForEditingDocument(document) do! Option.guard (CompletionUtils.shouldProvideCompletion(document.Id, document.FilePath, defines, sourceText, context.Position)) - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken) - let! _, _, fileCheckResults = checker.ParseAndCheckDocument(document, options, true, userOpName=userOpName) + let! _, _, fileCheckResults = checker.ParseAndCheckDocument(document, projectOptions, true, userOpName=userOpName) let getAllSymbols() = if Settings.IntelliSense.ShowAllSymbols then assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies(fileCheckResults) else [] let! results = - FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, options, + FSharpCompletionProvider.ProvideCompletionsAsyncAux(checker, sourceText, context.Position, projectOptions, document.FilePath, textVersion.GetHashCode(), getAllSymbols) context.AddItems(results) } |> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask context.CancellationToken @@ -268,8 +268,8 @@ type internal FSharpCompletionProvider let! sourceText = document.GetTextAsync(cancellationToken) let textWithItemCommitted = sourceText.WithChanges(TextChange(item.Span, nameInCode)) let line = sourceText.Lines.GetLineFromPosition(item.Span.Start) - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) - let! parsedInput = checker.ParseDocument(document, options, sourceText, userOpName) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) let fullNameIdents = fullName |> Option.map (fun x -> x.Split '.') |> Option.defaultValue [||] let insertionPoint = diff --git a/Completion/SignatureHelp.fs b/Completion/SignatureHelp.fs index 22310a9bf43..852fa7bfd56 100644 --- a/Completion/SignatureHelp.fs +++ b/Completion/SignatureHelp.fs @@ -196,7 +196,7 @@ type internal FSharpSignatureHelpProvider member this.GetItemsAsync(document, position, triggerInfo, cancellationToken) = asyncMaybe { try - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) @@ -206,7 +206,7 @@ type internal FSharpSignatureHelpProvider else None let! (results,applicableSpan,argumentIndex,argumentCount,argumentName) = - FSharpSignatureHelpProvider.ProvideMethodsAsyncAux(checkerProvider.Checker, documentationBuilder, sourceText, position, options, triggerTypedChar, document.FilePath, textVersion.GetHashCode()) + FSharpSignatureHelpProvider.ProvideMethodsAsyncAux(checkerProvider.Checker, documentationBuilder, sourceText, position, projectOptions, triggerTypedChar, document.FilePath, textVersion.GetHashCode()) let items = results |> Array.map (fun (hasParamArrayArg, doc, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) -> diff --git a/Debugging/BreakpointResolutionService.fs b/Debugging/BreakpointResolutionService.fs index 864a77e44aa..97bf920d70a 100644 --- a/Debugging/BreakpointResolutionService.fs +++ b/Debugging/BreakpointResolutionService.fs @@ -27,13 +27,8 @@ type internal FSharpBreakpointResolutionService ) = static let userOpName = "BreakpointResolution" - static member GetBreakpointLocation(checker: FSharpChecker, sourceText: SourceText, fileName: string, textSpan: TextSpan, options: FSharpProjectOptions) = + static member GetBreakpointLocation(checker: FSharpChecker, sourceText: SourceText, fileName: string, textSpan: TextSpan, parsingOptions: FSharpParsingOptions) = async { - // REVIEW: ParseFileInProject can cause FSharp.Compiler.Service to become unavailable (i.e. not responding to requests) for - // an arbitrarily long time while it parses all files prior to this one in the project (plus dependent projects if we enable - // cross-project checking in multi-project solutions). FCS will not respond to other - // requests unless this task is cancelled. We need to check that this task is cancelled in a timely way by the - // Roslyn UI machinery. let textLinePos = sourceText.Lines.GetLinePosition(textSpan.Start) let textInLine = sourceText.GetSubText(sourceText.Lines.[textLinePos.Line].Span).ToString() @@ -42,16 +37,16 @@ type internal FSharpBreakpointResolutionService else let textLineColumn = textLinePos.Character let fcsTextLineNumber = Line.fromZ textLinePos.Line // Roslyn line numbers are zero-based, FSharp.Compiler.Service line numbers are 1-based - let! parseResults = checker.ParseFileInProject(fileName, sourceText.ToString(), options, userOpName = userOpName) + let! parseResults = checker.ParseFile(fileName, sourceText.ToString(), parsingOptions, userOpName = userOpName) return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn) } interface IBreakpointResolutionService with member this.ResolveBreakpointAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken): Task = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, options) + let! range = FSharpBreakpointResolutionService.GetBreakpointLocation(checkerProvider.Checker, sourceText, document.Name, textSpan, parsingOptions) let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) return BreakpointResolutionResult.CreateSpanResult(document, span) } diff --git a/Diagnostics/DocumentDiagnosticAnalyzer.fs b/Diagnostics/DocumentDiagnosticAnalyzer.fs index 412496efa35..ffcf5c6ef83 100644 --- a/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -57,9 +57,9 @@ type internal FSharpDocumentDiagnosticAnalyzer() = hash } - static member GetDiagnostics(checker: FSharpChecker, filePath: string, sourceText: SourceText, textVersionHash: int, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = + static member GetDiagnostics(checker: FSharpChecker, filePath: string, sourceText: SourceText, textVersionHash: int, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = async { - let! parseResults = checker.ParseFileInProject(filePath, sourceText.ToString(), options, userOpName=userOpName) + let! parseResults = checker.ParseFile(filePath, sourceText.ToString(), parsingOptions, userOpName=userOpName) let! errors = async { match diagnosticType with @@ -109,11 +109,11 @@ type internal FSharpDocumentDiagnosticAnalyzer() = override this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) return! - FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), options, DiagnosticsType.Syntax) + FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Syntax) |> liftAsync } |> Async.map (Option.defaultValue ImmutableArray.Empty) @@ -122,11 +122,11 @@ type internal FSharpDocumentDiagnosticAnalyzer() = override this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = let projectInfoManager = getProjectInfoManager document asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForDocumentOrProject(document) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) return! - FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), options, DiagnosticsType.Semantic) + FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(getChecker document, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic) |> liftAsync } |> Async.map (Option.defaultValue ImmutableArray.Empty) diff --git a/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index 225a32d29e7..b0b25ca6ead 100644 --- a/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -51,7 +51,7 @@ type internal SimplifyNameDiagnosticAnalyzer() = do! Option.guard Settings.CodeFixes.SimplifyName do Trace.TraceInformation("{0:n3} (start) SimplifyName", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.SimplifyNameInitialDelay |> liftAsync - let! options = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) + let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) let! textVersion = document.GetTextVersionAsync(cancellationToken) let textVersionHash = textVersion.GetHashCode() let! _ = guard.WaitAsync(cancellationToken) |> Async.AwaitTask |> liftAsync @@ -61,7 +61,7 @@ type internal SimplifyNameDiagnosticAnalyzer() = | _ -> let! sourceText = document.GetTextAsync() let checker = getChecker document - let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = true, userOpName=userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = true, userOpName=userOpName) let! symbolUses = checkResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync let mutable result = ResizeArray() let symbolUses = diff --git a/Diagnostics/UnusedDeclarationsAnalyzer.fs b/Diagnostics/UnusedDeclarationsAnalyzer.fs index a0466dd4ff4..cb541cac322 100644 --- a/Diagnostics/UnusedDeclarationsAnalyzer.fs +++ b/Diagnostics/UnusedDeclarationsAnalyzer.fs @@ -103,10 +103,10 @@ type internal UnusedDeclarationsAnalyzer() = do Trace.TraceInformation("{0:n3} (start) UnusedDeclarationsAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.UnusedDeclarationsAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time match getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) with - | Some options -> + | Some (_parsingOptions, projectOptions) -> let! sourceText = document.GetTextAsync() let checker = getChecker document - let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) + let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) let! allSymbolUsesInFile = checkResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync let unusedRanges = getUnusedDeclarationRanges allSymbolUsesInFile (isScriptFile document.FilePath) return diff --git a/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 58226fb8f1e..0dcb5c9da5d 100644 --- a/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -173,10 +173,10 @@ type internal UnusedOpensDiagnosticAnalyzer() = asyncMaybe { do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) do! Async.Sleep DefaultTuning.UnusedOpensAnalyzerInitialDelay |> liftAsync // be less intrusive, give other work priority most of the time - let! options = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) + let! _parsingOptions, projectOptions = getProjectInfoManager(document).TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync() let checker = getChecker document - let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, options, checker) + let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) return unusedOpens diff --git a/DocumentHighlights/DocumentHighlightsService.fs b/DocumentHighlights/DocumentHighlightsService.fs index e4829fd4764..354c41759dd 100644 --- a/DocumentHighlights/DocumentHighlightsService.fs +++ b/DocumentHighlights/DocumentHighlightsService.fs @@ -76,12 +76,12 @@ type internal FSharpDocumentHighlightsService [] (checkerP interface IDocumentHighlightsService with member __.GetDocumentHighlightsAsync(document, position, _documentsToSearch, cancellationToken) : Task> = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) let! spans = FSharpDocumentHighlightsService.GetDocumentHighlights(checkerProvider.Checker, document.Id, sourceText, document.FilePath, - position, defines, options, textVersion.GetHashCode()) + position, defines, projectOptions, textVersion.GetHashCode()) let highlightSpans = spans |> Array.map (fun span -> diff --git a/Formatting/BraceMatchingService.fs b/Formatting/BraceMatchingService.fs index 700768a20c9..7b795f0cc82 100644 --- a/Formatting/BraceMatchingService.fs +++ b/Formatting/BraceMatchingService.fs @@ -18,9 +18,9 @@ type internal FSharpBraceMatchingService static let defaultUserOpName = "BraceMatching" - static member GetBraceMatchingResult(checker: FSharpChecker, sourceText, fileName, options, position: int, userOpName: string) = + static member GetBraceMatchingResult(checker: FSharpChecker, sourceText, fileName, parsingOptions: FSharpParsingOptions, position: int, userOpName: string) = async { - let! matchedBraces = checker.MatchBraces(fileName, sourceText.ToString(), options, userOpName) + let! matchedBraces = checker.MatchBraces(fileName, sourceText.ToString(), parsingOptions, userOpName) let isPositionInRange range = match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with | None -> false @@ -33,9 +33,9 @@ type internal FSharpBraceMatchingService interface IBraceMatcher with member this.FindBracesAsync(document, position, cancellationToken) = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, options, position, defaultUserOpName) + let! (left, right) = FSharpBraceMatchingService.GetBraceMatchingResult(checkerProvider.Checker, sourceText, document.Name, parsingOptions, position, defaultUserOpName) let! leftSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, left) let! rightSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, right) return BraceMatchingResult(leftSpan, rightSpan) diff --git a/Formatting/EditorFormattingService.fs b/Formatting/EditorFormattingService.fs index 0abbd0abddf..d4b1b24ebf6 100644 --- a/Formatting/EditorFormattingService.fs +++ b/Formatting/EditorFormattingService.fs @@ -23,7 +23,7 @@ type internal FSharpEditorFormattingService projectInfoManager: FSharpProjectOptionsManager ) = - static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, projectOptions: FSharpProjectOptions option, position: int) = + static member GetFormattingChanges(documentId: DocumentId, sourceText: SourceText, filePath: string, checker: FSharpChecker, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option, position: int) = // Logic for determining formatting changes: // If first token on the current line is a closing brace, // match the indent with the indent on the line that opened it @@ -34,11 +34,11 @@ type internal FSharpEditorFormattingService // (this is what C# does) do! Option.guard (indentStyle = FormattingOptions.IndentStyle.Smart) - let! projectOptions = projectOptions + let! parsingOptions, _projectOptions = options let line = sourceText.Lines.[sourceText.Lines.IndexOf position] - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, projectOptions.OtherOptions |> List.ofArray) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, parsingOptions) let tokens = Tokenizer.tokenizeLine(documentId, sourceText, line.Start, filePath, defines) @@ -50,7 +50,7 @@ type internal FSharpEditorFormattingService x.Tag <> FSharpTokenTag.LINE_COMMENT) let! (left, right) = - FSharpBraceMatchingService.GetBraceMatchingResult(checker, sourceText, filePath, projectOptions, position, "FormattingService") + FSharpBraceMatchingService.GetBraceMatchingResult(checker, sourceText, filePath, parsingOptions, position, "FormattingService") if right.StartColumn = firstMeaningfulToken.LeftColumn then // Replace the indentation on this line with the indentation of the left bracket diff --git a/Formatting/IndentationService.fs b/Formatting/IndentationService.fs index 4fa71c024fb..23afe5131ce 100644 --- a/Formatting/IndentationService.fs +++ b/Formatting/IndentationService.fs @@ -23,7 +23,7 @@ type internal FSharpIndentationService static member IsSmartIndentEnabled (options: Microsoft.CodeAnalysis.Options.OptionSet) = options.GetOption(FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName) = FormattingOptions.IndentStyle.Smart - static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, projectOptions: FSharpProjectOptions option): Option = + static member GetDesiredIndentation(documentId: DocumentId, sourceText: SourceText, filePath: string, lineNumber: int, tabSize: int, indentStyle: FormattingOptions.IndentStyle, options: (FSharpParsingOptions * FSharpProjectOptions) option): Option = // Match indentation with previous line let rec tryFindPreviousNonEmptyLine l = @@ -36,8 +36,8 @@ type internal FSharpIndentationService tryFindPreviousNonEmptyLine (l - 1) let rec tryFindLastNonWhitespaceOrCommentToken (line: TextLine) = maybe { - let! projectOptions = projectOptions - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, projectOptions.OtherOptions |> Seq.toList) + let! parsingOptions, _projectOptions = options + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, parsingOptions) let tokens = Tokenizer.tokenizeLine(documentId, sourceText, line.Start, filePath, defines) return! diff --git a/InlineRename/InlineRenameService.fs b/InlineRename/InlineRenameService.fs index d2f804ebe55..89e9d6a8f2d 100644 --- a/InlineRename/InlineRenameService.fs +++ b/InlineRename/InlineRenameService.fs @@ -167,10 +167,10 @@ type internal InlineRenameService interface IEditorInlineRenameService with member __.GetRenameInfoAsync(document: Document, position: int, cancellationToken: CancellationToken) : Task = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList) - return! InlineRenameService.GetInlineRenameInfo(checkerProvider.Checker, projectInfoManager, document, sourceText, position, defines, options) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) + return! InlineRenameService.GetInlineRenameInfo(checkerProvider.Checker, projectInfoManager, document, sourceText, position, defines, projectOptions) } |> Async.map (Option.defaultValue FailureInlineRenameInfo.Instance) |> RoslynHelpers.StartAsyncAsTask(cancellationToken) diff --git a/LanguageService/FSharpCheckerExtensions.fs b/LanguageService/FSharpCheckerExtensions.fs index 7eb2616f283..2d6b877fee9 100644 --- a/LanguageService/FSharpCheckerExtensions.fs +++ b/LanguageService/FSharpCheckerExtensions.fs @@ -15,14 +15,14 @@ type CheckResults = | StillRunning of Async<(FSharpParseFileResults * FSharpCheckFileResults) option> type FSharpChecker with - member checker.ParseDocument(document: Document, options: FSharpProjectOptions, sourceText: string, userOpName: string) = + member checker.ParseDocument(document: Document, parsingOptions: FSharpParsingOptions, sourceText: string, userOpName: string) = asyncMaybe { - let! fileParseResults = checker.ParseFileInProject(document.FilePath, sourceText, options, userOpName=userOpName) |> liftAsync + let! fileParseResults = checker.ParseFile(document.FilePath, sourceText, parsingOptions, userOpName=userOpName) |> liftAsync return! fileParseResults.ParseTree } - member checker.ParseDocument(document: Document, options: FSharpProjectOptions, sourceText: SourceText, userOpName: string) = - checker.ParseDocument(document, options, sourceText=sourceText.ToString(), userOpName=userOpName) + member checker.ParseDocument(document: Document, parsingOptions: FSharpParsingOptions, sourceText: SourceText, userOpName: string) = + checker.ParseDocument(document, parsingOptions, sourceText=sourceText.ToString(), userOpName=userOpName) member checker.ParseAndCheckDocument(filePath: string, textVersionHash: int, sourceText: string, options: FSharpProjectOptions, allowStaleResults: bool, userOpName: string) = let parseAndCheckFile = diff --git a/LanguageService/LanguageService.fs b/LanguageService/LanguageService.fs index 29658d69a56..311e7ba928c 100644 --- a/LanguageService/LanguageService.fs +++ b/LanguageService/LanguageService.fs @@ -101,11 +101,11 @@ type internal FSharpProjectOptionsManager ) = // A table of information about projects, excluding single-file projects. - let projectTable = ConcurrentDictionary>() + let projectTable = ConcurrentDictionary>() // A table of information about single-file projects. Currently we only need the load time of each such file, plus // the original options for editing - let singleFileProjectTable = ConcurrentDictionary() + let singleFileProjectTable = ConcurrentDictionary() // Accumulate sources and references for each project file let projectInfo = new ConcurrentDictionary() @@ -128,7 +128,7 @@ type internal FSharpProjectOptionsManager member this.RefreshInfoForProjectsThatReferenceThisProject(projectId: ProjectId) = // Search the projectTable for things to refresh - for KeyValue(otherProjectId, ((referencedProjectIds, _options), refresh)) in projectTable.ToArray() do + for KeyValue(otherProjectId, ((referencedProjectIds, _parsingOptions, _options), refresh)) in projectTable.ToArray() do for referencedProjectId in referencedProjectIds do if referencedProjectId = projectId then projectTable.[otherProjectId] <- (refresh true, refresh) @@ -143,7 +143,7 @@ type internal FSharpProjectOptionsManager /// Get the exact options for a single-file script member this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, fileContents, workspace: Workspace) = async { let extraProjectInfo = Some(box workspace) - let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject + let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject |> Option.map snd if SourceFile.MustBeSingleFileProject(fileName) then // NOTE: we don't use a unique stamp for single files, instead comparing options structurally. // This is because we repeatedly recompute the options. @@ -153,37 +153,42 @@ type internal FSharpProjectOptionsManager // compiled and #r will refer to files on disk let referencedProjectFileNames = [| |] let site = ProjectSitesAndFiles.CreateProjectSiteForScript(fileName, referencedProjectFileNames, options) - return ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject,site,fileName,options.ExtraProjectInfo,serviceProvider, true) + let deps, projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject,site,fileName,options.ExtraProjectInfo,serviceProvider, true) + let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) + return (deps, parsingOptions, projectOptions) else let site = ProjectSitesAndFiles.ProjectSiteOfSingleFile(fileName) - return ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject,site,fileName,extraProjectInfo,serviceProvider, true) + let deps, projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject,site,fileName,extraProjectInfo,serviceProvider, true) + let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) + return (deps, parsingOptions, projectOptions) } /// Update the info for a project in the project table member this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId: ProjectId, site: IProjectSite, userOpName) = this.AddOrUpdateProject(projectId, (fun isRefresh -> let extraProjectInfo = Some(box workspace) - let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject - let referencedProjects, options = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) + let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject |> Option.map snd + let referencedProjects, projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite(Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, site.ProjectFileName(), extraProjectInfo, serviceProvider, true) let referencedProjectIds = referencedProjects |> Array.choose tryGetOrCreateProjectId - checkerProvider.Checker.InvalidateConfiguration(options, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") - referencedProjectIds, options)) + checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen = not isRefresh, userOpName= userOpName + ".UpdateProjectInfo") + let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions) + referencedProjectIds, parsingOptions, projectOptions)) /// Get compilation defines relevant for syntax processing. /// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project /// options for a script. member this.GetCompilationDefinesForEditingDocument(document: Document) = let projectOptionsOpt = this.TryGetOptionsForProject(document.Project.Id) - let otherOptions = + let parsingOptions = match projectOptionsOpt with - | None -> [] - | Some options -> options.OtherOptions |> Array.toList - CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, otherOptions) + | None -> FSharpParsingOptions.Default + | Some (parsingOptions, _projectOptions) -> parsingOptions + CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) /// Get the options for a project member this.TryGetOptionsForProject(projectId: ProjectId) = match projectTable.TryGetValue(projectId) with - | true, ((_referencedProjects, options), _) -> Some options + | true, ((_referencedProjects, parsingOptions, projectOptions), _) -> Some (parsingOptions, projectOptions) | _ -> None /// Get the exact options for a document or project @@ -194,7 +199,7 @@ type internal FSharpProjectOptionsManager // single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze // to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date. match singleFileProjectTable.TryGetValue(projectId) with - | true, (loadTime, _) -> + | true, (loadTime, _, _) -> try let fileName = document.FilePath let! cancellationToken = Async.CancellationToken @@ -202,9 +207,9 @@ type internal FSharpProjectOptionsManager // NOTE: we don't use FCS cross-project references from scripts to projects. The projects must have been // compiled and #r will refer to files on disk. let tryGetOrCreateProjectId _ = None - let! _referencedProjectFileNames, options = this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString(), document.Project.Solution.Workspace) - this.AddOrUpdateSingleFileProject(projectId, (loadTime, options)) - return Some options + let! _referencedProjectFileNames, parsingOptions, projectOptions = this.ComputeSingleFileOptions (tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString(), document.Project.Solution.Workspace) + this.AddOrUpdateSingleFileProject(projectId, (loadTime, parsingOptions, projectOptions)) + return Some (parsingOptions, projectOptions) with ex -> Assert.Exception(ex) return None @@ -216,7 +221,7 @@ type internal FSharpProjectOptionsManager member this.TryGetOptionsForEditingDocumentOrProject(document: Document) = let projectId = document.Project.Id match singleFileProjectTable.TryGetValue(projectId) with - | true, (_loadTime, originalOptions) -> Some originalOptions + | true, (_loadTime, parsingOptions, originalOptions) -> Some (parsingOptions, originalOptions) | _ -> this.TryGetOptionsForProject(projectId) member this.ProvideProjectSiteProvider(project:Project) = @@ -301,6 +306,8 @@ type internal FSharpProjectOptionsManager | true, value -> value | _ -> [||], [||], [||] + member __.Checker = checkerProvider.Checker + // Used to expose FSharpChecker/ProjectInfo manager to diagnostic providers // Diagnostic providers can be executed in environment that does not use MEF so they can rely only // on services exposed by the workspace @@ -574,8 +581,8 @@ type let projectDisplayName = projectDisplayNameOf projectFileName let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName) - let _referencedProjectFileNames, options = projectInfoManager.ComputeSingleFileOptions (tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents, workspace) |> Async.RunSynchronously - projectInfoManager.AddOrUpdateSingleFileProject(projectId, (loadTime, options)) + let _referencedProjectFileNames, parsingOptions, projectOptions = projectInfoManager.ComputeSingleFileOptions (tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents, workspace) |> Async.RunSynchronously + projectInfoManager.AddOrUpdateSingleFileProject(projectId, (loadTime, parsingOptions, projectOptions)) if isNull (workspace.ProjectTracker.GetProject projectId) then let projectContextFactory = package.ComponentModel.GetService(); diff --git a/LanguageService/SymbolHelpers.fs b/LanguageService/SymbolHelpers.fs index dfe76098b80..15995d015f0 100644 --- a/LanguageService/SymbolHelpers.fs +++ b/LanguageService/SymbolHelpers.fs @@ -30,10 +30,10 @@ module internal SymbolHelpers = let textLine = sourceText.Lines.GetLineFromPosition(position) let textLinePos = sourceText.Lines.GetLinePosition(position) let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document.FilePath, textVersionHash, sourceText.ToString(), options, allowStaleResults = true, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document.FilePath, textVersionHash, sourceText.ToString(), projectOptions, allowStaleResults = true, userOpName = userOpName) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, userOpName=userOpName) let! symbolUses = checkFileResults.GetUsesOfSymbolInFile(symbolUse.Symbol) |> liftAsync return symbolUses @@ -59,8 +59,8 @@ module internal SymbolHelpers = |> Seq.map (fun project -> async { match projectInfoManager.TryGetOptionsForProject(project.Id) with - | Some options -> - let! projectCheckResults = checker.ParseAndCheckProject(options, userOpName = userOpName) + | Some (_parsingOptions, projectOptions) -> + let! projectCheckResults = checker.ParseAndCheckProject(projectOptions, userOpName = userOpName) return! projectCheckResults.GetUsesOfSymbol(symbol) | None -> return [||] }) @@ -103,10 +103,10 @@ module internal SymbolHelpers = let! sourceText = document.GetTextAsync(cancellationToken) let originalText = sourceText.ToString(symbolSpan) do! Option.guard (originalText.Length > 0) - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, options.OtherOptions |> Seq.toList) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.Name, parsingOptions) let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, symbolSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false) - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, allowStaleResults = true, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition(symbolSpan.Start) let textLinePos = sourceText.Lines.GetLinePosition(symbolSpan.Start) let fcsTextLineNumber = Line.fromZ textLinePos.Line diff --git a/Navigation/FindUsagesService.fs b/Navigation/FindUsagesService.fs index b964f1d2eff..e3479737db0 100644 --- a/Navigation/FindUsagesService.fs +++ b/Navigation/FindUsagesService.fs @@ -51,11 +51,11 @@ type internal FSharpFindUsagesService asyncMaybe { let! sourceText = document.GetTextAsync(context.CancellationToken) |> Async.AwaitTask |> liftAsync let checker = checkerProvider.Checker - let! options = projectInfoManager.TryGetOptionsForDocumentOrProject(document) - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document) + let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, sourceText = sourceText, allowStaleResults = true, userOpName = userOpName) let textLine = sourceText.Lines.GetLineFromPosition(position).ToString() let lineNumber = sourceText.Lines.GetLinePosition(position).Line + 1 - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.FilePath, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.FilePath, parsingOptions) let! symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false) let! symbolUse = checkFileResults.GetSymbolUseAtLocation(lineNumber, symbol.Ident.idRange.EndColumn, textLine, symbol.FullIsland, userOpName=userOpName) @@ -112,8 +112,8 @@ type internal FSharpFindUsagesService projectsToCheck |> Seq.map (fun project -> asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForProject(project.Id) - let! projectCheckResults = checker.ParseAndCheckProject(options, userOpName = userOpName) |> liftAsync + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForProject(project.Id) + let! projectCheckResults = checker.ParseAndCheckProject(projectOptions, userOpName = userOpName) |> liftAsync return! projectCheckResults.GetUsesOfSymbol(symbolUse.Symbol) |> liftAsync } |> Async.map (Option.defaultValue [||])) |> Async.Parallel diff --git a/Navigation/GoToDefinitionService.fs b/Navigation/GoToDefinitionService.fs index 9925058fcfd..7707b8a2554 100644 --- a/Navigation/GoToDefinitionService.fs +++ b/Navigation/GoToDefinitionService.fs @@ -57,8 +57,8 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP /// Helper function that is used to determine the navigation strategy to apply, can be tuned towards signatures or implementation files. let findSymbolHelper (originDocument: Document, originRange: range, sourceText: SourceText, preferSignature: bool) : Async = asyncMaybe { - let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject originDocument - let defines = CompilerEnvironment.GetCompilationDefinesForEditing (originDocument.FilePath, projectOptions.OtherOptions |> Seq.toList) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject originDocument + let defines = CompilerEnvironment.GetCompilationDefinesForEditing (originDocument.FilePath, parsingOptions) let! originTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, originRange) let position = originTextSpan.Start let! lexerSymbol = Tokenizer.getSymbolAtPosition (originDocument.Id, sourceText, position, originDocument.FilePath, defines, SymbolLookupKind.Greedy, false) @@ -67,7 +67,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP let fcsTextLineNumber = Line.fromZ textLinePos.Line let lineText = (sourceText.Lines.GetLineFromPosition position).ToString() - let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument,projectOptions,allowStaleResults=true,sourceText=sourceText, userOpName = userOpName) + let! _, _, checkFileResults = checker.ParseAndCheckDocument (originDocument, projectOptions, allowStaleResults=true,sourceText=sourceText, userOpName = userOpName) let idRange = lexerSymbol.Ident.idRange let! fsSymbolUse = checkFileResults.GetSymbolUseAtLocation (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland, userOpName=userOpName) let symbol = fsSymbolUse.Symbol @@ -79,7 +79,7 @@ type internal GoToDefinition(checker: FSharpChecker, projectInfoManager: FSharpP if not (File.Exists fsfilePath) then return! None else let! implDoc = originDocument.Project.Solution.TryGetDocumentFromPath fsfilePath let! implSourceText = implDoc.GetTextAsync () - let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject implDoc + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject implDoc let! _, _, checkFileResults = checker.ParseAndCheckDocument (implDoc, projectOptions, allowStaleResults=true, sourceText=implSourceText, userOpName = userOpName) let! symbolUses = checkFileResults.GetUsesOfSymbolInFile symbol |> liftAsync let! implSymbol = symbolUses |> Array.tryHead @@ -295,9 +295,9 @@ type internal FSharpGoToDefinitionService /// at the provided position in the document. member __.FindDefinitionsTask(originDocument: Document, position: int, cancellationToken: CancellationToken) = asyncMaybe { - let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject originDocument + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject originDocument let! sourceText = originDocument.GetTextAsync () |> liftTaskAsync - let defines = CompilerEnvironment.GetCompilationDefinesForEditing (originDocument.FilePath, projectOptions.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing (originDocument.FilePath, parsingOptions) let textLine = sourceText.Lines.GetLineFromPosition position let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line @@ -382,7 +382,7 @@ type internal FSharpGoToDefinitionService let! implDocument = originDocument.Project.Solution.TryGetDocumentFromPath implFilePath let! implVersion = implDocument.GetTextVersionAsync () |> liftTaskAsync let! implSourceText = implDocument.GetTextAsync () |> liftTaskAsync - let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject implDocument + let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject implDocument let! targetRange = gotoDefinition.FindSymbolDeclarationInFile(targetSymbolUse, implFilePath, implSourceText.ToString(), projectOptions, implVersion.GetHashCode()) diff --git a/Navigation/NavigateToSearchService.fs b/Navigation/NavigateToSearchService.fs index d84202eac73..a1cee3bff49 100644 --- a/Navigation/NavigateToSearchService.fs +++ b/Navigation/NavigateToSearchService.fs @@ -187,11 +187,11 @@ type internal FSharpNavigateToSearchService let itemsByDocumentId = ConditionalWeakTable() - let getNavigableItems(document: Document, options: FSharpProjectOptions) = + let getNavigableItems(document: Document, parsingOptions: FSharpParsingOptions) = async { let! cancellationToken = Async.CancellationToken let! sourceText = document.GetTextAsync(cancellationToken) |> Async.AwaitTask - let! parseResults = checkerProvider.Checker.ParseFileInProject(document.FilePath, sourceText.ToString(), options) + let! parseResults = checkerProvider.Checker.ParseFile(document.FilePath, sourceText.ToString(), parsingOptions) return match parseResults.ParseTree |> Option.map NavigateTo.getNavigableItems with | Some items -> @@ -206,7 +206,7 @@ type internal FSharpNavigateToSearchService | None -> [||] } - let getCachedIndexedNavigableItems(document: Document, options: FSharpProjectOptions) = + let getCachedIndexedNavigableItems(document: Document, parsingOptions: FSharpParsingOptions) = async { let! cancellationToken = Async.CancellationToken let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask @@ -215,7 +215,7 @@ type internal FSharpNavigateToSearchService | true, (oldTextVersionHash, items) when oldTextVersionHash = textVersionHash -> return items | _ -> - let! items = getNavigableItems(document, options) + let! items = getNavigableItems(document, parsingOptions) let indexedItems = Index.build items itemsByDocumentId.Remove(document.Id) |> ignore itemsByDocumentId.Add(document.Id, (textVersionHash, indexedItems)) @@ -233,10 +233,10 @@ type internal FSharpNavigateToSearchService interface INavigateToSearchService with member __.SearchProjectAsync(project, searchPattern, cancellationToken) : Task> = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForProject(project.Id) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForProject(project.Id) let! items = project.Documents - |> Seq.map (fun document -> getCachedIndexedNavigableItems(document, options)) + |> Seq.map (fun document -> getCachedIndexedNavigableItems(document, parsingOptions)) |> Async.Parallel |> liftAsync @@ -265,8 +265,8 @@ type internal FSharpNavigateToSearchService member __.SearchDocumentAsync(document, searchPattern, cancellationToken) : Task> = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForDocumentOrProject(document) - let! items = getCachedIndexedNavigableItems(document, options) |> liftAsync + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForDocumentOrProject(document) + let! items = getCachedIndexedNavigableItems(document, parsingOptions) |> liftAsync return items.Find(searchPattern) } |> Async.map (Option.defaultValue [||]) diff --git a/Navigation/NavigationBarItemService.fs b/Navigation/NavigationBarItemService.fs index 7e0fdac0def..34fad074bac 100644 --- a/Navigation/NavigationBarItemService.fs +++ b/Navigation/NavigationBarItemService.fs @@ -32,9 +32,9 @@ type internal FSharpNavigationBarItemService interface INavigationBarItemService with member __.GetItemsAsync(document, cancellationToken) : Task> = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let! parsedInput = checkerProvider.Checker.ParseDocument(document, options, sourceText=sourceText, userOpName=userOpName) + let! parsedInput = checkerProvider.Checker.ParseDocument(document, parsingOptions, sourceText=sourceText, userOpName=userOpName) let navItems = NavigationImpl.getNavigation parsedInput let rangeToTextSpan range = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) return diff --git a/QuickInfo/QuickInfoProvider.fs b/QuickInfo/QuickInfoProvider.fs index 1324602ffb2..8e4a6fa82a0 100644 --- a/QuickInfo/QuickInfoProvider.fs +++ b/QuickInfo/QuickInfoProvider.fs @@ -55,8 +55,8 @@ module private FSharpQuickInfo = let extLineText = (extSourceText.Lines.GetLineFromPosition extSpan.Start).ToString() // project options need to be retrieved because the signature file could be in another project - let! extProjectOptions = projectInfoManager.TryGetOptionsForProject extDocId.ProjectId - let extDefines = CompilerEnvironment.GetCompilationDefinesForEditing (extDocument.FilePath, List.ofSeq extProjectOptions.OtherOptions) + let! extParsingOptions, extProjectOptions = projectInfoManager.TryGetOptionsForProject extDocId.ProjectId + let extDefines = CompilerEnvironment.GetCompilationDefinesForEditing (extDocument.FilePath, extParsingOptions) let! extLexerSymbol = Tokenizer.getSymbolAtPosition(extDocId, extSourceText, extSpan.Start, declRange.FileName, extDefines, SymbolLookupKind.Greedy, true) let! _, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, sourceText=extSourceText, userOpName = userOpName) @@ -91,8 +91,8 @@ module private FSharpQuickInfo = asyncMaybe { let! sourceText = document.GetTextAsync cancellationToken - let! projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document - let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.FilePath, projectOptions.OtherOptions |> Seq.toList) + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document + let defines = CompilerEnvironment.GetCompilationDefinesForEditing(document.FilePath, parsingOptions) let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true) let idRange = lexerSymbol.Ident.idRange let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText=sourceText, userOpName = userOpName) @@ -170,12 +170,12 @@ type internal FSharpQuickInfoProvider let xmlMemberIndexService = serviceProvider.GetService(typeof) :?> IVsXMLMemberIndexService let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService, serviceProvider.DTE) - static member ProvideQuickInfo(checker: FSharpChecker, documentId: DocumentId, sourceText: SourceText, filePath: string, position: int, options: FSharpProjectOptions, textVersionHash: int) = + static member ProvideQuickInfo(checker: FSharpChecker, documentId: DocumentId, sourceText: SourceText, filePath: string, position: int, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, textVersionHash: int) = asyncMaybe { let! _, _, checkFileResults = checker.ParseAndCheckDocument (filePath, textVersionHash, sourceText.ToString(), options, allowStaleResults = true, userOpName = FSharpQuickInfo.userOpName) let textLine = sourceText.Lines.GetLineFromPosition position let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based - let defines = CompilerEnvironment.GetCompilationDefinesForEditing (filePath, options.OtherOptions |> Seq.toList) + let defines = CompilerEnvironment.GetCompilationDefinesForEditing (filePath, parsingOptions) let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true) let! res = checkFileResults.GetStructuredToolTipText (textLineNumber, symbol.Ident.idRange.EndColumn, textLine.ToString(), symbol.FullIsland, FSharpTokenTag.IDENT, userOpName=FSharpQuickInfo.userOpName) |> liftAsync match res with diff --git a/Structure/BlockStructureService.fs b/Structure/BlockStructureService.fs index 68a41f19e6d..865165665a3 100644 --- a/Structure/BlockStructureService.fs +++ b/Structure/BlockStructureService.fs @@ -148,9 +148,9 @@ type internal FSharpBlockStructureService(checker: FSharpChecker, projectInfoMan override __.GetBlockStructureAsync(document, cancellationToken) : Task = asyncMaybe { - let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! sourceText = document.GetTextAsync(cancellationToken) - let! parsedInput = checker.ParseDocument(document, options, sourceText, userOpName) + let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) return createBlockSpans sourceText parsedInput |> Seq.toImmutableArray } |> Async.map (Option.defaultValue ImmutableArray<_>.Empty)