From d3efce451ae7cb24b2695fced3e56278ea1596a7 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 8 Feb 2021 17:52:15 +0000 Subject: [PATCH 01/31] analyzers draft --- src/fsharp/CheckDeclarations.fs | 8 +- src/fsharp/CheckExpressions.fs | 2 +- src/fsharp/CompilerDiagnostics.fs | 8 +- src/fsharp/CompilerImports.fs | 36 +++++ src/fsharp/CompilerImports.fsi | 24 ++- src/fsharp/ErrorLogger.fs | 8 +- src/fsharp/ErrorLogger.fsi | 3 +- src/fsharp/ExtensionTyping.fs | 2 +- src/fsharp/FSComp.txt | 5 + .../FSharp.Compiler.Service.fsproj | 131 ++++++++-------- .../FSharp.Core/fslib-extra-pervasives.fs | 7 + .../FSharp.Core/fslib-extra-pervasives.fsi | 16 ++ src/fsharp/MethodCalls.fs | 2 +- src/fsharp/ParseAndCheckInputs.fs | 24 +-- src/fsharp/ParseAndCheckInputs.fsi | 16 +- src/fsharp/SyntaxTree.fs | 5 + src/fsharp/SyntaxTree.fsi | 3 + src/fsharp/fsc.fs | 140 ++++++++++++------ src/fsharp/fsc.fsi | 10 -- src/fsharp/fsi/fsi.fs | 4 +- src/fsharp/import.fs | 4 +- src/fsharp/service/ExternalSymbol.fsi | 8 +- src/fsharp/service/FSharpAnalyzer.fs | 123 +++++++++++++++ src/fsharp/service/FSharpAnalyzer.fsi | 71 +++++++++ src/fsharp/service/FSharpCheckerResults.fs | 81 +++++++--- src/fsharp/service/FSharpCheckerResults.fsi | 66 ++++++++- src/fsharp/service/IncrementalBuild.fs | 54 +++++-- src/fsharp/service/IncrementalBuild.fsi | 6 +- src/fsharp/service/service.fs | 133 ++++++++++------- src/fsharp/service/service.fsi | 70 +++------ src/fsharp/symbols/SymbolHelpers.fs | 17 ++- src/fsharp/symbols/SymbolHelpers.fsi | 10 ++ src/fsharp/xlf/FSComp.txt.cs.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.de.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.es.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.fr.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.it.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.ja.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.ko.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.pl.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.ru.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.tr.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 25 ++++ src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 25 ++++ .../CompilerTestHelpers.fs | 2 +- tests/service/ProjectAnalysisTests.fs | 1 + .../src/FSharp.Editor/Common/RoslynHelpers.fs | 2 +- .../Completion/CompletionProvider.fs | 2 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 3 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 5 +- .../DocComments/XMLDocumentation.fs | 10 +- .../QuickInfo/QuickInfoProvider.fs | 46 ++++-- 53 files changed, 1168 insertions(+), 325 deletions(-) create mode 100644 src/fsharp/service/FSharpAnalyzer.fs create mode 100644 src/fsharp/service/FSharpAnalyzer.fsi diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index fa31e63a708..bb7813857c4 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -5026,7 +5026,7 @@ let rec TcSignatureElementNonMutRec cenv parent typeNames endm (env: TcEnv) synS | SynModuleSigDecl.Val (vspec, m) -> let parentModule = match parent with - | ParentNone -> error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId)) + | ParentNone -> error(Error(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId)) | Parent p -> p let containerInfo = ModuleOrNamespaceContainerInfo parentModule let idvs, _ = TcAndPublishValSpec (cenv, env, containerInfo, ModuleOrMemberBinding, None, emptyUnscopedTyparEnv, vspec) @@ -5197,7 +5197,7 @@ and TcSignatureElementsMutRec cenv parent typeNames m mutRecNSInfo envInitial (d decls, (false, false) | SynModuleSigDecl.Val (vspec, _) -> - if isNamespace then error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId)) + if isNamespace then error(Error(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId)) let decls = [ MutRecShape.Lets vspec ] decls, (false, false) @@ -5281,9 +5281,9 @@ let CheckLetOrDoInNamespace binds m = | [ SynBinding (None, (SynBindingKind.StandaloneExpression | SynBindingKind.Do), false, false, [], _, _, _, None, (SynExpr.Do (SynExpr.Const (SynConst.Unit, _), _) | SynExpr.Const (SynConst.Unit, _)), _, _) ] -> () | [] -> - error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), m)) + error(Error(FSComp.SR.tcNamespaceCannotContainValues(), m)) | _ -> - error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), binds.Head.RangeOfHeadPattern)) + error(Error(FSComp.SR.tcNamespaceCannotContainValues(), binds.Head.RangeOfHeadPattern)) /// The non-mutually recursive case for a declaration let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem env synDecl = diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 9136ea7bfe4..2bd59220802 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -1200,7 +1200,7 @@ let PublishValueDefn cenv env declKind (vspec: Val) = if (declKind = ModuleOrMemberBinding) && ((GetCurrAccumulatedModuleOrNamespaceType env).ModuleOrNamespaceKind = Namespace) && (Option.isNone vspec.MemberInfo) then - errorR(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.Range)) + errorR(Error(FSComp.SR.tcNamespaceCannotContainValues(), vspec.Range)) if (declKind = ExtrinsicExtensionBinding) && ((GetCurrAccumulatedModuleOrNamespaceType env).ModuleOrNamespaceKind = Namespace) then diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index 04cf3858be1..0ecc8da47c3 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -128,7 +128,7 @@ let GetRangeOfDiagnostic(err: PhasedDiagnostic) = | LetRecEvaluatedOutOfOrder (_, _, _, m) | Error (_, m) | ErrorWithSuggestions (_, m, _, _) - | NumberedError (_, m) + | CompilerToolDiagnostic (_, m) | SyntaxError (_, m) | InternalError (_, m) | InterfaceNotRevealed(_, _, m) @@ -346,7 +346,7 @@ let GetDiagnosticNumber(err: PhasedDiagnostic) = | Error ((n, _), _) -> n | ErrorWithSuggestions ((n, _), _, _, _) -> n | Failure _ -> 192 - | NumberedError((n, _), _) -> n + | CompilerToolDiagnostic((n, _), _) -> n | IllegalFileNameChar(fileName, invalidChar) -> fst (FSComp.SR.buildUnexpectedFileNameCharacter(fileName, string invalidChar)) #if !NO_EXTENSIONTYPING | :? TypeProviderError as e -> e.Number @@ -362,7 +362,7 @@ let GetWarningLevel err = | LetRecEvaluatedOutOfOrder _ | DefensiveCopyWarning _ -> 5 - | NumberedError((n, _), _) + | CompilerToolDiagnostic((n, _), _) | ErrorWithSuggestions((n, _), _, _, _) | Error((n, _), _) -> // 1178, tcNoComparisonNeeded1, "The struct, record or union type '%s' is not structurally comparable because the type parameter %s does not satisfy the 'comparison' constraint..." @@ -1452,7 +1452,7 @@ let OutputPhasedErrorR (os: StringBuilder) (err: PhasedDiagnostic) (canSuggestNa os.Append(DecompileOpName s) |> ignore suggestNames suggestionF idText - | NumberedError ((_, s), _) -> os.Append s |> ignore + | CompilerToolDiagnostic ((_, s), _) -> os.Append s |> ignore | InternalError (s, _) diff --git a/src/fsharp/CompilerImports.fs b/src/fsharp/CompilerImports.fs index a397e7fdae5..20d362fa3c3 100644 --- a/src/fsharp/CompilerImports.fs +++ b/src/fsharp/CompilerImports.fs @@ -130,6 +130,42 @@ let WriteOptimizationData (tcGlobals, filename, inMem, ccu: CcuThunk, modulInfo) let rName = if ccu.AssemblyName = getFSharpCoreLibraryName then FSharpOptimizationDataResourceName2 else FSharpOptimizationDataResourceName PickleToResource inMem filename tcGlobals ccu (rName+ccu.AssemblyName) Optimizer.p_CcuOptimizationInfo modulInfo +let EncodeSignatureData(tcConfig: TcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, isIncrementalBuild) = + if tcConfig.GenerateSignatureData then + let resource = WriteSignatureData (tcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, isIncrementalBuild) + // The resource gets written to a file for FSharp.Core + let useDataFiles = (tcConfig.useOptimizationDataFile || tcGlobals.compilingFslib) && not isIncrementalBuild + if useDataFiles then + let sigDataFileName = (Filename.chopExtension outfile)+".sigdata" + let bytes = resource.GetBytes() + use fileStream = File.Create(sigDataFileName, bytes.Length) + bytes.CopyTo fileStream + let resources = + [ resource ] + let sigAttr = mkSignatureDataVersionAttr tcGlobals (parseILVersion Internal.Utilities.FSharpEnvironment.FSharpBinaryMetadataFormatRevision) + [sigAttr], resources + else + [], [] + +let EncodeOptimizationData(tcGlobals, tcConfig: TcConfig, outfile, exportRemapping, data, isIncrementalBuild) = + if tcConfig.GenerateOptimizationData then + let data = map2Of2 (Optimizer.RemapOptimizationInfo tcGlobals exportRemapping) data + // As with the sigdata file, the optdata gets written to a file for FSharp.Core + let useDataFiles = (tcConfig.useOptimizationDataFile || tcGlobals.compilingFslib) && not isIncrementalBuild + if useDataFiles then + let ccu, modulInfo = data + let bytes = TypedTreePickle.pickleObjWithDanglingCcus isIncrementalBuild outfile tcGlobals ccu Optimizer.p_CcuOptimizationInfo modulInfo + let optDataFileName = (Filename.chopExtension outfile)+".optdata" + File.WriteAllBytes(optDataFileName, bytes) + let (ccu, optData) = + if tcConfig.onlyEssentialOptimizationData then + map2Of2 Optimizer.AbstractOptimizationInfoToEssentials data + else + data + [ WriteOptimizationData (tcGlobals, outfile, isIncrementalBuild, ccu, optData) ] + else + [ ] + exception AssemblyNotResolved of (*originalName*) string * range exception MSBuildReferenceResolutionWarning of (*MSBuild warning code*)string * (*Message*)string * range exception MSBuildReferenceResolutionError of (*MSBuild warning code*)string * (*Message*)string * range diff --git a/src/fsharp/CompilerImports.fsi b/src/fsharp/CompilerImports.fsi index adcb466a5bf..41687660eb4 100644 --- a/src/fsharp/CompilerImports.fsi +++ b/src/fsharp/CompilerImports.fsi @@ -12,6 +12,7 @@ open FSharp.Compiler.CheckExpressions open FSharp.Compiler.CompilerConfig open FSharp.Compiler.DependencyManager open FSharp.Compiler.ErrorLogger +open FSharp.Compiler.Optimizer open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TcGlobals @@ -42,11 +43,24 @@ val IsReflectedDefinitionsResource: ILResource -> bool val GetSignatureDataResourceName: ILResource -> string -/// Write F# signature data as an IL resource -val WriteSignatureData: TcConfig * TcGlobals * Remap * CcuThunk * filename: string * inMem: bool -> ILResource - -/// Write F# optimization data as an IL resource -val WriteOptimizationData: TcGlobals * filename: string * inMem: bool * CcuThunk * Optimizer.LazyModuleInfo -> ILResource +/// Encode the F# interface data into a set of IL attributes and resources +val EncodeSignatureData: + tcConfig:TcConfig * + tcGlobals:TcGlobals * + exportRemapping:Remap * + generatedCcu: CcuThunk * + outfile: string * + isIncrementalBuild: bool + -> ILAttribute list * ILResource list + +val EncodeOptimizationData: + tcGlobals:TcGlobals * + tcConfig:TcConfig * + outfile: string * + exportRemapping:Remap * + (CcuThunk * #CcuOptimizationInfo) * + isIncrementalBuild: bool + -> ILResource list [] type ResolveAssemblyReferenceMode = diff --git a/src/fsharp/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index f73c3f9ca95..0602c668d95 100644 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -62,13 +62,13 @@ let (|StopProcessing|_|) exn = match exn with StopProcessingExn _ -> Some () | _ let StopProcessing<'T> = StopProcessingExn None -exception NumberedError of (int * string) * range with // int is e.g. 191 in FS0191 +exception CompilerToolDiagnostic of (int * string) * range with // int is e.g. 191 in FS0191 override this.Message = match this :> exn with - | NumberedError((_, msg), _) -> msg + | CompilerToolDiagnostic((_, msg), _) -> msg | _ -> "impossible" -exception Error of (int * string) * range with // int is e.g. 191 in FS0191 // eventually remove this type, it is a transitional artifact of the old unnumbered error style +exception Error of (int * string) * range with // int is e.g. 191 in FS0191 override this.Message = match this :> exn with | Error((_, msg), _) -> msg @@ -192,6 +192,8 @@ module BuildPhaseSubcategory = [] let Interactive = "interactive" [] + let Analysis = "analysis" + [] let Internal = "internal" // Compiler ICE [] diff --git a/src/fsharp/ErrorLogger.fsi b/src/fsharp/ErrorLogger.fsi index ec2e9340635..b578ae5ac66 100644 --- a/src/fsharp/ErrorLogger.fsi +++ b/src/fsharp/ErrorLogger.fsi @@ -40,7 +40,7 @@ val ( |StopProcessing|_| ): exn:exn -> unit option val StopProcessing<'T> : exn -exception NumberedError of (int * string) * range +exception CompilerToolDiagnostic of (int * string) * range exception Error of (int * string) * range @@ -108,6 +108,7 @@ module BuildPhaseSubcategory = [] val Output: string = "output" [] val Interactive: string = "interactive" [] val Internal: string = "internal" + [] val Analysis: string = "analysis" type PhasedDiagnostic = { Exception: exn diff --git a/src/fsharp/ExtensionTyping.fs b/src/fsharp/ExtensionTyping.fs index 5409fda0ab9..2d35ce762da 100644 --- a/src/fsharp/ExtensionTyping.fs +++ b/src/fsharp/ExtensionTyping.fs @@ -171,7 +171,7 @@ module internal ExtensionTyping = () ] with :? TypeProviderError as tpe -> - tpe.Iter(fun e -> errorR(NumberedError((e.Number, e.ContextualErrorMessage), m)) ) + tpe.Iter(fun e -> errorR(CompilerToolDiagnostic((e.Number, e.ContextualErrorMessage), m)) ) [] let providers = Tainted<_>.CreateAll(providerSpecs) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 160f86ef738..b612e5a8157 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1527,6 +1527,11 @@ featureWitnessPassing,"witness passing for trait constraints in F# quotations" featureInterfacesWithMultipleGenericInstantiation,"interfaces with multiple generic instantiation" 3362,tcLiteralFieldAssignmentWithArg,"Cannot assign '%s' to a value marked literal" 3363,tcLiteralFieldAssignmentNoArg,"Cannot assign a value to another value marked literal" +3365,etAnalyzerLoadFailure,"The analyzer '%s' failed to load: '%s'" +3366,etAnalyzerDoesNotHaveValidConstructor,"The analyzer '%s' doesn't have a valid constructor." +3367,etAnalyzerConstructionException,"The analyzer '%s' raised an exception during analyzer construction: '%s'." +3368,etAnalyzerTypeInitializationException,"The analyzer '%s' raised an exception during analyzer type initialization: '%s'." +3369,etAnalyzerException,"The analyzer '%s' raised an exception during analysis of file '%s': '%s'." forFormatInvalidForInterpolated,"Interpolated strings may not use '%%' format specifiers unless each is given an expression, e.g. '%%d{{1+1}}'." forFormatInvalidForInterpolated2,".NET-style format specifiers such as '{{x,3}}' or '{{x:N5}}' may not be mixed with '%%' format specifiers." forFormatInvalidForInterpolated3,"The '%%P' specifier may not be used explicitly." diff --git a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj index 4d5c1a3d1b5..fbe56795894 100644 --- a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj +++ b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj @@ -801,12 +801,6 @@ Driver\CreateILModule.fs - - Driver\fsc.fsi - - - Driver\fsc.fs - @@ -833,118 +827,117 @@ Symbols/SymbolPatterns.fs + - Service/Reactor.fsi + CodeAnalysis/Reactor.fsi - Service/Reactor.fs + CodeAnalysis/Reactor.fs - - - Service/SemanticClassification.fsi + CodeAnalysis/SemanticClassification.fsi - Service/SemanticClassification.fs + CodeAnalysis/SemanticClassification.fs - Service/ItemKey.fsi + CodeAnalysis/ItemKey.fsi - Service/ItemKey.fs + CodeAnalysis/ItemKey.fs - Service/SemanticClassificationKey.fsi + CodeAnalysis/SemanticClassificationKey.fsi - Service/SemanticClassificationKey.fs + CodeAnalysis/SemanticClassificationKey.fs - - Service/IncrementalBuild.fsi - - - Service/IncrementalBuild.fs - - - Service/ServiceCompilerDiagnostics.fsi - - - Service/ServiceCompilerDiagnostics.fs - - Service/ServiceConstants.fs + CodeAnalysis/ServiceConstants.fs - Service/ServiceDeclarationLists.fsi + CodeAnalysis/ServiceDeclarationLists.fsi - Service/ServiceDeclarationLists.fs + CodeAnalysis/ServiceDeclarationLists.fs - Service/ServiceLexing.fsi + CodeAnalysis/ServiceLexing.fsi - Service/ServiceLexing.fs + CodeAnalysis/ServiceLexing.fs - Service/ServiceParseTreeWalk.fsi + CodeAnalysis/ServiceParseTreeWalk.fsi - Service/ServiceParseTreeWalk.fs + CodeAnalysis/ServiceParseTreeWalk.fs - Service/ServiceNavigation.fsi + CodeAnalysis/ServiceNavigation.fsi - Service/ServiceNavigation.fs + CodeAnalysis/ServiceNavigation.fs - Service/ServiceParamInfoLocations.fsi + CodeAnalysis/ServiceParamInfoLocations.fsi - Service/ServiceParamInfoLocations.fs + CodeAnalysis/ServiceParamInfoLocations.fs - Service/FSharpParseFileResults.fsi + CodeAnalysis/FSharpParseFileResults.fsi - Service/FSharpParseFileResults.fs + CodeAnalysis/FSharpParseFileResults.fs - Service/ServiceParsedInputOps.fsi + CodeAnalysis/ServiceParsedInputOps.fsi - Service/ServiceParsedInputOps.fs + CodeAnalysis/ServiceParsedInputOps.fs - Service/ServiceAssemblyContent.fsi + CodeAnalysis/ServiceAssemblyContent.fsi - Service/ServiceAssemblyContent.fs - - - Service/ServiceXmlDocParser.fsi - - - Service/ServiceXmlDocParser.fs + CodeAnalysis/ServiceAssemblyContent.fs - Service/ExternalSymbol.fsi + CodeAnalysis/ExternalSymbol.fsi - Service/ExternalSymbol.fs + CodeAnalysis/ExternalSymbol.fs - Service/QuickParse.fsi + CodeAnalysis/QuickParse.fsi - Service/QuickParse.fs + CodeAnalysis/QuickParse.fs - Service/FSharpCheckerResults.fsi + CodeAnalysis/FSharpCheckerResults.fsi - Service/FSharpCheckerResults.fs + CodeAnalysis/FSharpCheckerResults.fs + + + CodeAnalysis/FSharpAnalyzer.fsi + + + CodeAnalysis/FSharpAnalyzer.fs + + + Service/fsc.fsi + + + Service/fsc.fs + + + Service/IncrementalBuild.fsi + + + Service/IncrementalBuild.fs Service/service.fsi @@ -952,23 +945,35 @@ Service/service.fs + + EditorServices/ServiceXmlDocParser.fsi + + + EditorServices/ServiceXmlDocParser.fs + + + EditorServices/ServiceCompilerDiagnostics.fsi + + + EditorServices/ServiceCompilerDiagnostics.fs + - Service/ServiceInterfaceStubGenerator.fsi + EditorServices/ServiceInterfaceStubGenerator.fsi - Service/ServiceInterfaceStubGenerator.fs + EditorServices/ServiceInterfaceStubGenerator.fs - Service/ServiceStructure.fsi + EditorServices/ServiceStructure.fsi - Service/ServiceStructure.fs + EditorServices/ServiceStructure.fs - Service/ServiceAnalysis.fsi + EditorServices/ServiceAnalysis.fsi - Service/ServiceAnalysis.fs + EditorServices/ServiceAnalysis.fs InteractiveSession/fsi.fsi diff --git a/src/fsharp/FSharp.Core/fslib-extra-pervasives.fs b/src/fsharp/FSharp.Core/fslib-extra-pervasives.fs index 7d05c29b497..a65f3db1a85 100644 --- a/src/fsharp/FSharp.Core/fslib-extra-pervasives.fs +++ b/src/fsharp/FSharp.Core/fslib-extra-pervasives.fs @@ -371,3 +371,10 @@ namespace Microsoft.FSharp.Core.CompilerServices abstract GetStaticParametersForMethod : methodWithoutArguments:MethodBase -> ParameterInfo[] abstract ApplyStaticArgumentsForMethod : methodWithoutArguments:MethodBase * methodNameWithArguments:string * staticArguments:obj[] -> MethodBase + [] + type AnalyzerAttribute() = + inherit System.Attribute() + + [] + type AnalyzerAssemblyAttribute() = + inherit System.Attribute() diff --git a/src/fsharp/FSharp.Core/fslib-extra-pervasives.fsi b/src/fsharp/FSharp.Core/fslib-extra-pervasives.fsi index c7ae3fc6cf1..d93b9fb9900 100644 --- a/src/fsharp/FSharp.Core/fslib-extra-pervasives.fsi +++ b/src/fsharp/FSharp.Core/fslib-extra-pervasives.fsi @@ -373,3 +373,19 @@ namespace Microsoft.FSharp.Core.CompilerServices /// The provided method definition corresponding to the given static parameter values abstract ApplyStaticArgumentsForMethod : methodWithoutArguments:MethodBase * methodNameWithArguments:string * staticArguments:obj[] -> MethodBase + /// Place attribute on an assembly to indicate this is an F# analyzer assembly. + [] + type AnalyzerAssemblyAttribute = + inherit System.Attribute + /// Creates an instance of the attribute + /// AnalyzerAssemblyAttribute + new : unit -> AnalyzerAssemblyAttribute + + /// Place attribute on a type to indicate this is an F# analyzer. + [] + type AnalyzerAttribute = + inherit System.Attribute + /// Creates an instance of the attribute + /// AnalyzerAttribute + new : unit -> AnalyzerAttribute + diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index a132e7c5c2d..07bd84c44f5 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -1693,7 +1693,7 @@ module ProvidedMethodCalls = | true, v -> v | _ -> let typeProviderDesignation = ExtensionTyping.DisplayNameOfTypeProvider (pe.TypeProvider, m) - error(NumberedError(FSComp.SR.etIncorrectParameterExpression(typeProviderDesignation, vRaw.Name), m)) + error(Error(FSComp.SR.etIncorrectParameterExpression(typeProviderDesignation, vRaw.Name), m)) and exprToExpr expr = let _, (resExpr, _) = exprToExprAndWitness false expr diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index 35b33ca82a5..c1f340ac7d6 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -720,7 +720,7 @@ let TypeCheckOneInputEventually (checkForErrors, tcConfig: TcConfig, tcImports: tcsRootSigs=rootSigs tcsCreatesGeneratedProvidedTypes=tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes} - return (tcEnv, EmptyTopAttrs, None, ccuSigForFile), tcState + return (tcEnv, EmptyTopAttrs, (inp, None, ccuSigForFile)), tcState | ParsedInput.ImplFile (ParsedImplFileInput (_, _, qualNameOfFile, _, _, _, _) as file) -> @@ -789,11 +789,11 @@ let TypeCheckOneInputEventually (checkForErrors, tcConfig: TcConfig, tcImports: tcsRootImpls=rootImpls tcsCcuSig=ccuSig tcsCreatesGeneratedProvidedTypes=tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes } - return (tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile), tcState + return (tcEnvAtEnd, topAttrs, (inp, Some implFile, ccuSigForFile)), tcState with e -> errorRecovery e range0 - return (tcState.TcEnvFromSignatures, EmptyTopAttrs, None, tcState.tcsCcuSig), tcState + return (tcState.TcEnvFromSignatures, EmptyTopAttrs, (inp, None, tcState.tcsCcuSig)), tcState } /// Typecheck a single file (or interactive entry into F# Interactive) @@ -805,13 +805,12 @@ let TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, pre |> Eventually.force ctok /// Finish checking multiple files (or one interactive entry into F# Interactive) -let TypeCheckMultipleInputsFinish(results, tcState: TcState) = - let tcEnvsAtEndFile, topAttrs, implFiles, ccuSigsForFiles = List.unzip4 results +let TypeCheckMultipleInputsFinish(results: (TcEnv * TopAttribs * ('T * TypedImplFile option * ModuleOrNamespaceType)) list, tcState: TcState) = + let tcEnvsAtEndFile, topAttrs, implFiles = List.unzip3 results let topAttrs = List.foldBack CombineTopAttrs topAttrs EmptyTopAttrs - let implFiles = List.choose id implFiles // This is the environment required by fsi.exe when incrementally adding definitions let tcEnvAtEndOfLastFile = (match tcEnvsAtEndFile with h :: _ -> h | _ -> tcState.TcEnvFromSignatures) - (tcEnvAtEndOfLastFile, topAttrs, implFiles, ccuSigsForFiles), tcState + (tcEnvAtEndOfLastFile, topAttrs, implFiles), tcState let TypeCheckOneInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) = eventually { @@ -822,7 +821,7 @@ let TypeCheckOneInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcI return result } -let TypeCheckClosedInputSetFinish (declaredImpls: TypedImplFile list, tcState) = +let TypeCheckClosedInputSetFinish (tcState) = // Publish the latest contents to the CCU tcState.tcsCcu.Deref.Contents <- Construct.NewCcuContents ILScopeRef.Local range0 tcState.tcsCcu.AssemblyName tcState.tcsCcuSig @@ -831,11 +830,12 @@ let TypeCheckClosedInputSetFinish (declaredImpls: TypedImplFile list, tcState) = if not (Zset.contains qualNameOfFile tcState.tcsRootImpls) then errorR(Error(FSComp.SR.buildSignatureWithoutImplementation(qualNameOfFile.Text), qualNameOfFile.Range))) - tcState, declaredImpls + tcState let TypeCheckClosedInputSet (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) = // tcEnvAtEndOfLastFile is the environment required by fsi.exe when incrementally adding definitions let results, tcState = (tcState, inputs) ||> List.mapFold (TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt)) - let (tcEnvAtEndOfLastFile, topAttrs, implFiles, _), tcState = TypeCheckMultipleInputsFinish(results, tcState) - let tcState, declaredImpls = TypeCheckClosedInputSetFinish (implFiles, tcState) - tcState, topAttrs, declaredImpls, tcEnvAtEndOfLastFile + let (tcEnvAtEndOfLastFile, topAttrs, implFiles), tcState = TypeCheckMultipleInputsFinish(results, tcState) + let tcState = TypeCheckClosedInputSetFinish (tcState) + tcState, topAttrs, implFiles, tcEnvAtEndOfLastFile + \ No newline at end of file diff --git a/src/fsharp/ParseAndCheckInputs.fsi b/src/fsharp/ParseAndCheckInputs.fsi index 21f20a056e6..101dcd31db9 100644 --- a/src/fsharp/ParseAndCheckInputs.fsi +++ b/src/fsharp/ParseAndCheckInputs.fsi @@ -90,16 +90,16 @@ val TypeCheckOneInputEventually : TcState * ParsedInput * skipImplIfSigExists: bool - -> Eventually<(TcEnv * TopAttribs * TypedImplFile option * ModuleOrNamespaceType) * TcState> + -> Eventually<(TcEnv * TopAttribs * (ParsedInput * TypedImplFile option * ModuleOrNamespaceType)) * TcState> /// Finish the checking of multiple inputs -val TypeCheckMultipleInputsFinish: (TcEnv * TopAttribs * 'T option * 'U) list * TcState -> (TcEnv * TopAttribs * 'T list * 'U list) * TcState +val TypeCheckMultipleInputsFinish: + (TcEnv * TopAttribs * ('T * TypedImplFile option * ModuleOrNamespaceType)) list * + TcState + -> (TcEnv * TopAttribs * ('T * TypedImplFile option * ModuleOrNamespaceType) list) * TcState /// Finish the checking of a closed set of inputs -val TypeCheckClosedInputSetFinish: - TypedImplFile list * - TcState - -> TcState * TypedImplFile list +val TypeCheckClosedInputSetFinish: TcState -> TcState /// Check a closed set of inputs val TypeCheckClosedInputSet: @@ -110,7 +110,7 @@ val TypeCheckClosedInputSet: TcGlobals * LongIdent option * TcState * ParsedInput list - -> TcState * TopAttribs * TypedImplFile list * TcEnv + -> TcState * TopAttribs * (ParsedInput * TypedImplFile option * ModuleOrNamespaceType) list * TcEnv /// Check a single input and finish the checking val TypeCheckOneInputAndFinishEventually : @@ -122,7 +122,7 @@ val TypeCheckOneInputAndFinishEventually : NameResolution.TcResultsSink * TcState * ParsedInput - -> Eventually<(TcEnv * TopAttribs * TypedImplFile list * ModuleOrNamespaceType list) * TcState> + -> Eventually<(TcEnv * TopAttribs * (ParsedInput * TypedImplFile option * ModuleOrNamespaceType) list) * TcState> val GetScopedPragmasForInput: input: ParsedInput -> ScopedPragma list diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 165f9bfe911..e6b2e74784f 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -1864,6 +1864,11 @@ type ParsedInput = | SigFile of ParsedSigFileInput + member inp.FileName = + match inp with + | ParsedInput.ImplFile (ParsedImplFileInput (fileName=filename)) + | ParsedInput.SigFile (ParsedSigFileInput (fileName=filename)) -> filename + member inp.Range = match inp with | ParsedInput.ImplFile (ParsedImplFileInput (modules=SynModuleOrNamespace(range=m) :: _)) diff --git a/src/fsharp/SyntaxTree.fsi b/src/fsharp/SyntaxTree.fsi index ad9e4464f09..ca18c889963 100644 --- a/src/fsharp/SyntaxTree.fsi +++ b/src/fsharp/SyntaxTree.fsi @@ -2106,5 +2106,8 @@ type ParsedInput = /// A parsed signature file | SigFile of ParsedSigFileInput + /// Gets the file name of this construct + member FileName: string + /// Gets the syntax range of this construct member Range: range diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 20a5456674a..36aa3c2b21b 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -32,6 +32,7 @@ open FSharp.Compiler.AbstractIL.ILBinaryReader open FSharp.Compiler.AccessibilityLogic open FSharp.Compiler.CheckExpressions open FSharp.Compiler.CheckDeclarations +open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CompilerConfig open FSharp.Compiler.CompilerDiagnostics open FSharp.Compiler.CompilerImports @@ -39,10 +40,12 @@ open FSharp.Compiler.CompilerOptions open FSharp.Compiler.CompilerGlobalState open FSharp.Compiler.CreateILModule open FSharp.Compiler.DependencyManager +open FSharp.Compiler.Diagnostics open FSharp.Compiler.ErrorLogger open FSharp.Compiler.IlxGen open FSharp.Compiler.InfoReader open FSharp.Compiler.IO +open FSharp.Compiler.NameResolution open FSharp.Compiler.ParseAndCheckInputs open FSharp.Compiler.OptimizeInputs open FSharp.Compiler.ScriptClosure @@ -299,42 +302,6 @@ let ProcessCommandLineFlags (tcConfigB: TcConfigBuilder, lcidFromCodePage, argv) dllFiles |> List.iter (fun f->tcConfigB.AddReferencedAssemblyByPath(rangeStartup, f)) sourceFiles -let EncodeSignatureData(tcConfig: TcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, isIncrementalBuild) = - if tcConfig.GenerateSignatureData then - let resource = WriteSignatureData (tcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, isIncrementalBuild) - // The resource gets written to a file for FSharp.Core - let useDataFiles = (tcConfig.useOptimizationDataFile || tcGlobals.compilingFslib) && not isIncrementalBuild - if useDataFiles then - let sigDataFileName = (Filename.chopExtension outfile)+".sigdata" - let bytes = resource.GetBytes() - use fileStream = File.Create(sigDataFileName, bytes.Length) - bytes.CopyTo fileStream - let resources = - [ resource ] - let sigAttr = mkSignatureDataVersionAttr tcGlobals (IL.parseILVersion Internal.Utilities.FSharpEnvironment.FSharpBinaryMetadataFormatRevision) - [sigAttr], resources - else - [], [] - -let EncodeOptimizationData(tcGlobals, tcConfig: TcConfig, outfile, exportRemapping, data, isIncrementalBuild) = - if tcConfig.GenerateOptimizationData then - let data = map2Of2 (Optimizer.RemapOptimizationInfo tcGlobals exportRemapping) data - // As with the sigdata file, the optdata gets written to a file for FSharp.Core - let useDataFiles = (tcConfig.useOptimizationDataFile || tcGlobals.compilingFslib) && not isIncrementalBuild - if useDataFiles then - let ccu, modulInfo = data - let bytes = TypedTreePickle.pickleObjWithDanglingCcus isIncrementalBuild outfile tcGlobals ccu Optimizer.p_CcuOptimizationInfo modulInfo - let optDataFileName = (Filename.chopExtension outfile)+".optdata" - File.WriteAllBytes(optDataFileName, bytes) - let (ccu, optData) = - if tcConfig.onlyEssentialOptimizationData then - map2Of2 Optimizer.AbstractOptimizationInfoToEssentials data - else - data - [ WriteOptimizationData (tcGlobals, outfile, isIncrementalBuild, ccu, optData) ] - else - [ ] - /// Write a .fsi file for the --sig option module InterfaceFileWriter = @@ -611,13 +578,101 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // Type check the inputs let inputs = inputs |> List.map fst - let tcState, topAttrs, typedAssembly, _tcEnvAtEnd = + let tcState, topAttrs, tcFileResults, tcEnvAtEnd = TypeCheck(ctok, tcConfig, tcImports, tcGlobals, errorLogger, assemblyName, NiceNameGenerator(), tcEnv0, inputs, exiter) AbortOnError(errorLogger, exiter) ReportTime tcConfig "Typechecked" - Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedAssembly, topAttrs, tcConfig, outfile, pdbfile, assemblyName, errorLogger, exiter) + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + + let sourceTexts = + [| for sourceFile in sourceFiles -> + let sourceFile = FileSystem.GetFullPathShim sourceFile + use stream = FileSystem.FileStreamReadShim sourceFile + use reader = + match tcConfig.inputCodePage with + | None -> new StreamReader(stream, true) + | Some (n: int) -> new StreamReader(stream, Encoding.GetEncoding n) + let source = reader.ReadToEnd() + sourceFile, SourceText.ofString source |] + + let projectOptions = + { + ProjectFileName = "compile.fsproj" + ProjectId = None + SourceFiles = Array.ofList sourceFiles + ReferencedProjects = [| |] //for a in tcImports.GetImportedAssemblies() -> a.FSharpViewOfMetadata.FileName |] + OtherOptions = argv + IsIncompleteTypeCheckEnvironment = true + UseScriptResolutionRules = false + LoadTime = DateTime.MaxValue + OriginalLoadReferences = [] + UnresolvedReferences = None + Stamp = None + } + + for (inp, implFileOpt, ccuSig) in tcFileResults do + + let parseResults = + FSharpParseFileResults(diagnostics = [||], + input = Some inp, + parseHadErrors = false, + dependencyFiles = [| |]) + + let checkResults = + FSharpCheckFileResults.Make + (inp.FileName, + "compile.fsproj", + tcConfig, + tcGlobals, + false, + None, + [| |], + [| |], + [| |], + [| |], + true, + ccuSig, + tcState.Ccu, + tcImports, + tcEnvAtEnd.AccessRights, + TcResolutions.Empty, + TcSymbolUses.Empty, + tcEnvAtEnd.NameEnv, + None, + implFileOpt, + [| |]) + + let ctxt = + FSharpAnalyzerCheckFileContext(sourceTexts, + inp.FileName, + projectOptions, + parseResults, + checkResults) + + for analyzer in analyzers do + let diagnostics = analyzer.OnCheckFile(ctxt, CancellationToken.None) + for diag in diagnostics do + let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) + match diag.Severity with + | FSharpDiagnosticSeverity.Error -> errorR(exn) + | FSharpDiagnosticSeverity.Warning -> warning(exn) + | FSharpDiagnosticSeverity.Info -> warning(exn) + | FSharpDiagnosticSeverity.Hidden -> () + + // TODO: run project analysis + //let ctxt = + // FSharpAnalyzerCheckProjectContext(sourceTexts, + // inp.FileName, + // projectOptions, + // parseResults, + // checkResults) + if tcConfig.typeCheckOnly then exiter.Exit 0 + + let typedImplFiles = List.choose p23 tcFileResults + + Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedImplFiles, topAttrs, tcConfig, outfile, pdbfile, assemblyName, errorLogger, exiter) /// Alternative first phase of compilation. This is for the compile-from-AST feature of FCS. /// - Import assemblies @@ -723,20 +778,21 @@ let main1OfAst let tcEnv0 = GetInitialTcEnv (assemblyName, rangeStartup, tcConfig, tcImports, tcGlobals) // Type check the inputs - let tcState, topAttrs, typedAssembly, _tcEnvAtEnd = + let tcState, topAttrs, tcFileResults, _tcEnvAtEnd = TypeCheck(ctok, tcConfig, tcImports, tcGlobals, errorLogger, assemblyName, NiceNameGenerator(), tcEnv0, inputs, exiter) AbortOnError(errorLogger, exiter) ReportTime tcConfig "Typechecked" - Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedAssembly, topAttrs, tcConfig, outfile, pdbFile, assemblyName, errorLogger, exiter) + if tcConfig.typeCheckOnly then exiter.Exit 0 + let typedImplFiles = List.choose p23 tcFileResults + + Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedImplFiles, topAttrs, tcConfig, outfile, pdbFile, assemblyName, errorLogger, exiter) /// Second phase of compilation. /// - Write the signature file, check some attributes let main2(Args (ctok, tcGlobals, tcImports: TcImports, frameworkTcImports, generatedCcu: CcuThunk, typedImplFiles, topAttrs, tcConfig: TcConfig, outfile, pdbfile, assemblyName, errorLogger, exiter: Exiter)) = - if tcConfig.typeCheckOnly then exiter.Exit 0 - generatedCcu.Contents.SetAttribs(generatedCcu.Contents.Attribs @ topAttrs.assemblyAttrs) use unwindPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.CodeGen diff --git a/src/fsharp/fsc.fsi b/src/fsharp/fsc.fsi index eac96cdb51f..1af3290a3ec 100755 --- a/src/fsharp/fsc.fsi +++ b/src/fsharp/fsc.fsi @@ -25,16 +25,6 @@ type ConsoleLoggerProvider = new : unit -> ConsoleLoggerProvider inherit ErrorLoggerProvider -/// Encode the F# interface data into a set of IL attributes and resources -val EncodeSignatureData: - tcConfig:TcConfig * - tcGlobals:TcGlobals * - exportRemapping:Remap * - generatedCcu: CcuThunk * - outfile: string * - isIncrementalBuild: bool - -> ILAttribute list * ILResource list - /// The main (non-incremental) compilation entry point used by fsc.exe val mainCompile: ctok: CompilationThreadToken * diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 839f40c0b09..705b4ebf86f 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1249,9 +1249,11 @@ type internal FsiDynamicCompiler // Typecheck. The lock stops the type checker running at the same time as the // server intellisense implementation (which is currently incomplete and #if disabled) - let (tcState:TcState),topCustomAttrs,declaredImpls,tcEnvAtEndOfLastInput = + let (tcState:TcState), topCustomAttrs, declaredImpls, tcEnvAtEndOfLastInput = lock tcLockObject (fun _ -> TypeCheckClosedInputSet(ctok, errorLogger.CheckForErrors, tcConfig, tcImports, tcGlobals, Some prefixPath, tcState, inputs)) + // TODO: run analyzers here + let declaredImpls = List.map p23 declaredImpls |> List.choose id let codegenResults, optEnv, fragName = ProcessTypedImpl(errorLogger, optEnv, tcState, tcConfig, isInteractiveItExpr, topCustomAttrs, prefixPath, isIncrementalFragment, declaredImpls, ilxGenerator) let newState, declaredImpls = ProcessCodegenResults(ctok, errorLogger, istate, optEnv, tcState, tcConfig, prefixPath, showTypes, isIncrementalFragment, fragName, declaredImpls, ilxGenerator, codegenResults) (newState, tcEnvAtEndOfLastInput, declaredImpls) diff --git a/src/fsharp/import.fs b/src/fsharp/import.fs index 0bd815b755c..089502f2c89 100644 --- a/src/fsharp/import.fs +++ b/src/fsharp/import.fs @@ -361,7 +361,7 @@ let ImportProvidedMethodBaseAsILMethodRef (env: ImportMap) (m: range) (mbase: Ta | None -> let methodName = minfo.PUntaint((fun minfo -> minfo.Name), m) let typeName = declaringGenericTypeDefn.PUntaint((fun declaringGenericTypeDefn -> declaringGenericTypeDefn.FullName), m) - error(NumberedError(FSComp.SR.etIncorrectProvidedMethod(ExtensionTyping.DisplayNameOfTypeProvider(minfo.TypeProvider, m), methodName, metadataToken, typeName), m)) + error(Error(FSComp.SR.etIncorrectProvidedMethod(ExtensionTyping.DisplayNameOfTypeProvider(minfo.TypeProvider, m), methodName, metadataToken, typeName), m)) | _ -> match mbase.OfType() with | Some cinfo when cinfo.PUntaint((fun x -> x.DeclaringType.IsGenericType), m) -> @@ -387,7 +387,7 @@ let ImportProvidedMethodBaseAsILMethodRef (env: ImportMap) (m: range) (mbase: Ta | Some found -> found.Coerce(m) | None -> let typeName = declaringGenericTypeDefn.PUntaint((fun x -> x.FullName), m) - error(NumberedError(FSComp.SR.etIncorrectProvidedConstructor(ExtensionTyping.DisplayNameOfTypeProvider(cinfo.TypeProvider, m), typeName), m)) + error(Error(FSComp.SR.etIncorrectProvidedConstructor(ExtensionTyping.DisplayNameOfTypeProvider(cinfo.TypeProvider, m), typeName), m)) | _ -> mbase let rty = diff --git a/src/fsharp/service/ExternalSymbol.fsi b/src/fsharp/service/ExternalSymbol.fsi index 8c85cddc88c..6090e713397 100644 --- a/src/fsharp/service/ExternalSymbol.fsi +++ b/src/fsharp/service/ExternalSymbol.fsi @@ -7,7 +7,7 @@ open FSharp.Compiler.AbstractIL.IL /// Represents a type in an external (non F#) assembly. [] -type FindDeclExternalType = +type public FindDeclExternalType = /// Type defined in non-F# assembly. | Type of fullName: string * genericArgs: FindDeclExternalType list @@ -22,7 +22,7 @@ type FindDeclExternalType = override ToString : unit -> string -module FindDeclExternalType = +module internal FindDeclExternalType = val internal tryOfILType : string array -> ILType -> FindDeclExternalType option /// Represents the type of a single method parameter @@ -37,7 +37,7 @@ type FindDeclExternalParam = override ToString : unit -> string -module FindDeclExternalParam = +module internal FindDeclExternalParam = val internal tryOfILType : string array -> ILType -> FindDeclExternalParam option @@ -45,7 +45,7 @@ module FindDeclExternalParam = /// Represents a symbol in an external (non F#) assembly [] -type FindDeclExternalSymbol = +type public FindDeclExternalSymbol = | Type of fullName: string | Constructor of typeName: string * args: FindDeclExternalParam list diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs new file mode 100644 index 00000000000..203ca4eca47 --- /dev/null +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +// Open up the compiler as an incremental service for parsing, +// type checking and intellisense-like environment-reporting. + +namespace FSharp.Compiler.CodeAnalysis + +open System +open System.Reflection +open System.Threading +open Internal.Utilities.Library +open FSharp.Compiler.CompilerConfig +open FSharp.Compiler.Diagnostics +open FSharp.Compiler.Text + +type FSharpAnalyzerTextChange = Range * string + +[] +type public FSharpAnalyzerCheckFileContext(sourceTexts: (string * ISourceText)[], + fileName: string, + projectOptions: FSharpProjectOptions, + parseResults: FSharpParseFileResults, + checkResults: FSharpCheckFileResults) = + let sourceTextMap = Map.ofArray sourceTexts + member _.TryGetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then Some sourceTextMap.[fileName] else None + member _.FileName = fileName + member _.ProjectOptions = projectOptions + member _.ParseFileResults = parseResults + member _.CheckFileResults = checkResults + +[] +type public FSharpAnalyzerCheckProjectContext(sourceTexts: (string * ISourceText)[], + projectOptions: FSharpProjectOptions, + checkResults: FSharpCheckProjectResults) = + let sourceTextMap = Map.ofArray sourceTexts + member _.TryGetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then Some sourceTextMap.[fileName] else None + member _.ProjectOptions = projectOptions + member _.CheckProjectResults = checkResults + +[] +type public FSharpAnalysisContext() = + class end + +/// Represents an analyzer +[] +type public FSharpAnalyzer(context:FSharpAnalysisContext) = + member _.Context = context + abstract OnCheckFile: context: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + abstract OnCheckProject: context: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFileContext * position: Position * cancellationToken: CancellationToken -> TaggedText[] option + abstract TryCodeFix: context: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + abstract FixableDiagnosticIds: string[] + + default _.OnCheckFile(_, _) = [| |] + default _.OnCheckProject(_, _) = [| |] + default _.TryAdditionalToolTip(_, _, _) = None + default _.TryCodeFix(_, _, _) = None + default _.FixableDiagnosticIds = [| |] + +module FSharpAnalyzers = + open FSharp.Compiler + open FSharp.Compiler.IO.FileSystemAutoOpens + open FSharp.Compiler.AbstractIL.IL + open FSharp.Compiler.ErrorLogger + open FSharp.Compiler.TcGlobals + open FSharp.Core.CompilerServices + open System.IO + +#if !NO_EXTENSIONTYPING + let CreateAnalyzer (analyzerType: System.Type, m) = + + if analyzerType.GetConstructor([| typeof |]) <> null then + + let ctxt = FSharpAnalysisContext() + try + Activator.CreateInstance(analyzerType, [| box ctxt|]) :?> FSharpAnalyzer |> Some + with + | :? System.Reflection.TargetInvocationException as exn -> + let exn = exn.InnerException + errorR (Error(FSComp.SR.etAnalyzerConstructionException(analyzerType.FullName, exn.ToString()), m)) + None + | :? TypeInitializationException as exn -> + let exn = exn.InnerException + errorR (Error(FSComp.SR.etAnalyzerTypeInitializationException(analyzerType.FullName, exn.ToString()), m)) + None + | exn -> + errorR (Error(FSComp.SR.etAnalyzerConstructionException(analyzerType.FullName, exn.ToString()), m)) + None + else + errorR (Error(FSComp.SR.etAnalyzerDoesNotHaveValidConstructor(analyzerType.FullName), m)) + None + + let CreateAnalyzers (analyzerPath, m:range) = + + let analyzerAssembly = + try + Assembly.UnsafeLoadFrom analyzerPath + with exn -> + error (Error(FSComp.SR.etAnalyzerLoadFailure(analyzerPath, exn.ToString()), m)) + + [ if analyzerAssembly.GetCustomAttribute(typeof) <> null then + let exportedTypes = analyzerAssembly.GetExportedTypes() + for t in exportedTypes do + let ca = t.GetCustomAttributes(typeof, true) + if ca <> null && ca.Length > 0 then + match CreateAnalyzer(t, m) with + | None -> () + | Some a -> a ] + + let ImportAnalyzers(tcConfig: TcConfig, m) = + + [ for analyzerPath in tcConfig.compilerToolPaths do + if FileSystem.SafeExists(analyzerPath) then + yield! CreateAnalyzers (analyzerPath, m) ] + + +#else + + let ImportAnalyzers(tcConfig: TcConfig, g: TcGlobals, m) : FSharpAnalyzer list = + + [ ] + +#endif diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi new file mode 100644 index 00000000000..d8ff8b4bdd2 --- /dev/null +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.CodeAnalysis + +open System +open System.Threading +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.CompilerConfig +open FSharp.Compiler.Diagnostics +open FSharp.Compiler.TcGlobals +open FSharp.Compiler.Text + +type FSharpAnalyzerTextChange = Range * string + +/// The context for an analyzer when a file is checked +[] +type public FSharpAnalyzerCheckFileContext = + + internal new: sourceTexts: (string * ISourceText)[] * fileName: string * projectOptions: FSharpProjectOptions * parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults -> FSharpAnalyzerCheckFileContext + + member TryGetFileSource: fileName: string -> ISourceText option + + member ProjectOptions: FSharpProjectOptions + + member ParseFileResults: FSharpParseFileResults + + member CheckFileResults: FSharpCheckFileResults + +/// The context for an analyzer when a project is checked +[] +type public FSharpAnalyzerCheckProjectContext = + + internal new: sourceTexts: (string * ISourceText)[] * projectOptions: FSharpProjectOptions * checkResults: FSharpCheckProjectResults -> FSharpAnalyzerCheckProjectContext + + member TryGetFileSource: fileName: string -> ISourceText option + + member ProjectOptions: FSharpProjectOptions + + member CheckProjectResults: FSharpCheckProjectResults + +/// The context for an analyzer. Currently empty. +[] +type public FSharpAnalysisContext = + class end + +/// Represents an analyzer. Inherit from this class to create an analyzer. +[] +type public FSharpAnalyzer = + + new: context: FSharpAnalysisContext -> FSharpAnalyzer + + member Context: FSharpAnalysisContext + + abstract OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + + abstract OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + + abstract TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * Position * cancellationToken: CancellationToken -> TaggedText[] option + + abstract TryCodeFix: FSharpAnalyzerCheckFileContext * FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + + abstract FixableDiagnosticIds: string[] + + default OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + default OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + default TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * Position * cancellationToken: CancellationToken -> TaggedText[] option + default TryCodeFix: FSharpAnalyzerCheckFileContext * FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + default FixableDiagnosticIds: string[] + +module internal FSharpAnalyzers = + val ImportAnalyzers: tcConfig: TcConfig * m: range -> FSharpAnalyzer list diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index c32ee9b348d..fc6d10b5159 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -53,6 +53,52 @@ open Internal.Utilities open Internal.Utilities.Collections open FSharp.Compiler.AbstractIL.ILBinaryReader +type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list + +// NOTE: may be better just to move to optional arguments here +type FSharpProjectOptions = + { + ProjectFileName: string + ProjectId: string option + SourceFiles: string[] + OtherOptions: string[] + ReferencedProjects: (string * FSharpProjectOptions)[] + IsIncompleteTypeCheckEnvironment : bool + UseScriptResolutionRules : bool + LoadTime : System.DateTime + UnresolvedReferences : FSharpUnresolvedReferencesSet option + OriginalLoadReferences: (range * string * string) list + Stamp : int64 option + } + member x.ProjectOptions = x.OtherOptions + + static member UseSameProject(options1,options2) = + match options1.ProjectId, options2.ProjectId with + | Some(projectId1), Some(projectId2) when not (String.IsNullOrWhiteSpace(projectId1)) && not (String.IsNullOrWhiteSpace(projectId2)) -> + projectId1 = projectId2 + | Some(_), Some(_) + | None, None -> options1.ProjectFileName = options2.ProjectFileName + | _ -> false + + static member AreSameForChecking(options1,options2) = + match options1.Stamp, options2.Stamp with + | Some x, Some y -> (x = y) + | _ -> + FSharpProjectOptions.UseSameProject(options1, options2) && + options1.SourceFiles = options2.SourceFiles && + options1.OtherOptions = options2.OtherOptions && + options1.UnresolvedReferences = options2.UnresolvedReferences && + options1.OriginalLoadReferences = options2.OriginalLoadReferences && + options1.ReferencedProjects.Length = options2.ReferencedProjects.Length && + Array.forall2 (fun (n1,a) (n2,b) -> + n1 = n2 && + FSharpProjectOptions.AreSameForChecking(a,b)) options1.ReferencedProjects options2.ReferencedProjects && + options1.LoadTime = options2.LoadTime + + member po.ProjectDirectory = System.IO.Path.GetDirectoryName(po.ProjectFileName) + + override this.ToString() = "FSharpProjectOptions(" + this.ProjectFileName + ")" + [] module internal FSharpCheckerResultsSettings = @@ -69,7 +115,7 @@ module internal FSharpCheckerResultsSettings = | s -> int64 s // Look for DLLs in the location of the service DLL first. - let defaultFSharpBinariesDir = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler(Some(Path.GetDirectoryName(typeof.Assembly.Location))).Value + let defaultFSharpBinariesDir = FSharpEnvironment.BinFolderOfDefaultFSharpCompiler(Some(Path.GetDirectoryName(typeof.Assembly.Location))).Value [] type FSharpSymbolUse(g:TcGlobals, denv: DisplayEnv, symbol:FSharpSymbol, itemOcc, range: range) = @@ -1759,16 +1805,16 @@ module internal ParseAndCheckFile = with e -> errorR e let mty = Construct.NewEmptyModuleOrNamespaceType ModuleOrNamespaceKind.Namespace - return Some((tcState.TcEnvFromSignatures, EmptyTopAttrs, [], [ mty ]), tcState) + return Some((tcState.TcEnvFromSignatures, EmptyTopAttrs, [(parsedMainInput, None, mty) ]), tcState) } let errors = errHandler.CollectedDiagnostics let res = match resOpt with - | Some ((tcEnvAtEnd, _, implFiles, ccuSigsForFiles), tcState) -> + | Some ((tcEnvAtEnd, _, implFiles), tcState) -> TypeCheckInfo(tcConfig, tcGlobals, - List.head ccuSigsForFiles, + (List.head implFiles |> p33), tcState.Ccu, tcImports, tcEnvAtEnd.AccessRights, @@ -1778,7 +1824,7 @@ module internal ParseAndCheckFile = sink.GetSymbolUses(), tcEnvAtEnd.NameEnv, loadClosure, - List.tryHead implFiles, + (List.tryHead implFiles |> Option.bind p23), sink.GetOpenDeclarations()) |> Result.Ok | None -> @@ -1799,16 +1845,17 @@ type FSharpProjectContext(thisCcu: CcuThunk, assemblies: FSharpAssembly list, ad [] /// A live object of this type keeps the background corresponding background builder (and type providers) alive (through reference-counting). // -// There is an important property of all the objects returned by the methods of this type: they do not require -// the corresponding background builder to be alive. That is, they are simply plain-old-data through pre-formatting of all result text. +// Note objects returned by the methods of this type do not require the corresponding background builder +// to be alive. That is, they are simply plain-old-data through pre-formatting of all result text. type FSharpCheckFileResults (filename: string, errors: FSharpDiagnostic[], scopeOptX: TypeCheckInfo option, dependencyFiles: string[], - builderX: IncrementalBuilder option, + builderX: obj option, keepAssemblyContents: bool) = + // Here 'details' keeps 'builder' alive let details = match scopeOptX with None -> None | Some scopeX -> Some (scopeX, builderX) // Run an operation that can be called from any thread @@ -1821,10 +1868,10 @@ type FSharpCheckFileResults member _.HasFullTypeCheckInfo = details.IsSome - member _.TryGetCurrentTcImports () = - match builderX with - | Some builder -> builder.TryGetCurrentTcImports () - | _ -> None + member _.TryGetCurrentTcImports () = + match details with + | None -> None + | Some (scope, _builderOpt) -> Some scope.TcImports /// Intellisense autocompletions member _.GetDeclarationListInfo(parsedFileResults, line, lineText, partialName, ?getAllEntities) = @@ -1994,7 +2041,7 @@ type FSharpCheckFileResults projectFileName, tcConfig, tcGlobals, isIncompleteTypeCheckEnvironment: bool, - builder: IncrementalBuilder, + builder: obj option, dependencyFiles, creationErrors: FSharpDiagnostic[], parseErrors: FSharpDiagnostic[], @@ -2014,7 +2061,7 @@ type FSharpCheckFileResults implFileOpt, openDeclarations) let errors = FSharpCheckFileResults.JoinErrors(isIncompleteTypeCheckEnvironment, creationErrors, parseErrors, tcErrors) - FSharpCheckFileResults (mainInputFileName, errors, Some tcFileInfo, dependencyFiles, Some builder, keepAssemblyContents) + FSharpCheckFileResults (mainInputFileName, errors, Some tcFileInfo, dependencyFiles, builder, keepAssemblyContents) static member CheckOneFile (parseResults: FSharpParseFileResults, @@ -2031,7 +2078,7 @@ type FSharpCheckFileResults reactorOps: IReactorOperations, userOpName: string, isIncompleteTypeCheckEnvironment: bool, - builder: IncrementalBuilder, + builder: obj, dependencyFiles: string[], creationErrors: FSharpDiagnostic[], parseErrors: FSharpDiagnostic[], @@ -2171,7 +2218,7 @@ type FSharpCheckProjectResults override _.ToString() = "FSharpCheckProjectResults(" + projectFileName + ")" type FsiInteractiveChecker(legacyReferenceResolver, - ops: IReactorOperations, + reactorOps: IReactorOperations, tcConfig: TcConfig, tcGlobals: TcGlobals, tcImports: TcImports, @@ -2213,7 +2260,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, (parseResults, sourceText, filename, "project", tcConfig, tcGlobals, tcImports, tcState, Map.empty, Some loadClosure, backgroundDiagnostics, - ops, userOpName, suggestNamesForErrors) + reactorOps, userOpName, suggestNamesForErrors) return match tcFileInfo with diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index 9b08ddb74b4..d8bc7848231 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -2,6 +2,7 @@ namespace FSharp.Compiler.CodeAnalysis +open System open System.Threading open Internal.Utilities.Library open FSharp.Compiler.AbstractIL.IL @@ -23,6 +24,65 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text +/// Unused in this API +type public FSharpUnresolvedReferencesSet = + internal + | FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list + +/// A set of information describing a project or script build configuration. +type public FSharpProjectOptions = + { + // Note that this may not reduce to just the project directory, because there may be two projects in the same directory. + ProjectFileName: string + + /// This is the unique identifier for the project, it is case sensitive. If it's None, will key off of ProjectFileName in our caching. + ProjectId: string option + + /// The files in the project + SourceFiles: string[] + + /// Additional command line argument options for the project. These can include additional files and references. + OtherOptions: string[] + + /// The command line arguments for the other projects referenced by this project, indexed by the + /// exact text used in the "-r:" reference in FSharpProjectOptions. + ReferencedProjects: (string * FSharpProjectOptions)[] + + /// When true, the typechecking environment is known a priori to be incomplete, for + /// example when a .fs file is opened outside of a project. In this case, the number of error + /// messages reported is reduced. + IsIncompleteTypeCheckEnvironment: bool + + /// When true, use the reference resolution rules for scripts rather than the rules for compiler. + UseScriptResolutionRules: bool + + /// Timestamp of project/script load, used to differentiate between different instances of a project load. + /// This ensures that a complete reload of the project or script type checking + /// context occurs on project or script unload/reload. + LoadTime: DateTime + + /// Unused in this API and should be 'None' when used as user-specified input + UnresolvedReferences: FSharpUnresolvedReferencesSet option + + /// Unused in this API and should be '[]' when used as user-specified input + OriginalLoadReferences: (range * string * string) list + + /// An optional stamp to uniquely identify this set of options + /// If two sets of options both have stamps, then they are considered equal + /// if and only if the stamps are equal + Stamp: int64 option + } + member internal ProjectOptions: string[] + + /// Whether the two parse options refer to the same project. + static member internal UseSameProject: options1: FSharpProjectOptions * options2: FSharpProjectOptions -> bool + + /// Compare two options sets with respect to the parts of the options that are important to building. + static member internal AreSameForChecking: options1: FSharpProjectOptions * options2: FSharpProjectOptions -> bool + + /// Compute the project directory. + member internal ProjectDirectory: string + /// Represents the use of an F# symbol from F# source code [] type public FSharpSymbolUse = @@ -254,7 +314,7 @@ type public FSharpCheckFileResults = tcConfig: TcConfig * tcGlobals: TcGlobals * isIncompleteTypeCheckEnvironment: bool * - builder: IncrementalBuilder * + builder: obj option * dependencyFiles: string[] * creationErrors: FSharpDiagnostic[] * parseErrors: FSharpDiagnostic[] * @@ -288,7 +348,7 @@ type public FSharpCheckFileResults = reactorOps: IReactorOperations * userOpName: string * isIncompleteTypeCheckEnvironment: bool * - builder: IncrementalBuilder * + builder: obj * dependencyFiles: string[] * creationErrors:FSharpDiagnostic[] * parseErrors:FSharpDiagnostic[] * @@ -371,7 +431,7 @@ module internal ParseAndCheckFile = type internal FsiInteractiveChecker = internal new: LegacyReferenceResolver * - ops: IReactorOperations * + reactorOps: IReactorOperations * tcConfig: TcConfig * tcGlobals: TcGlobals * tcImports: TcImports * diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index fb99c50efe6..f4c4f1dbb30 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -8,6 +8,7 @@ open System.IO open System.Runtime.InteropServices open System.Threading open Internal.Utilities.Library +open Internal.Utilities.Library.Extras open FSharp.Compiler open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.IL @@ -245,6 +246,8 @@ type BoundModel private (tcConfig: TcConfig, member _.TcImports = tcImports + member _.SyntaxTree = syntaxTreeOpt + member _.BackingSignature = match syntaxTreeOpt with | Some syntaxTree -> @@ -412,7 +415,7 @@ type BoundModel private (tcConfig: TcConfig, let input, moduleNamesDict = DeduplicateParsedInputModuleName prevModuleNamesDict input Logger.LogBlockMessageStart filename LogCompilerFunctionId.IncrementalBuild_TypeCheck - let! (tcEnvAtEndOfFile, topAttribs, implFile, ccuSigForFile), tcState = + let! (tcEnvAtEndOfFile, topAttribs, (_inp, implFile, ccuSigForFile)), tcState = TypeCheckOneInputEventually ((fun () -> hadParseErrors || errorLogger.ErrorCount > 0), tcConfig, tcImports, @@ -631,7 +634,7 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, tcState: let exportRemapping = MakeExportRemapping generatedCcu generatedCcu.Contents let sigData = - let _sigDataAttributes, sigDataResources = Driver.EncodeSignatureData(tcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, true) + let _sigDataAttributes, sigDataResources = EncodeSignatureData(tcConfig, tcGlobals, exportRemapping, generatedCcu, outfile, true) [ for r in sigDataResources do let ccuName = GetSignatureDataResourceName r yield (ccuName, (fun () -> r.GetBytes())) ] @@ -654,8 +657,15 @@ type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, tcState: member _.HasMatchingFSharpSignatureDataAttribute _ilg = true /// Manages an incremental build graph for the build of a single F# project -type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, nonFrameworkResolutions, unresolvedReferences, tcConfig: TcConfig, projectDirectory, outfile, - assemblyName, niceNameGen: NiceNameGenerator, lexResourceManager, +type IncrementalBuilder(tcGlobals, frameworkTcImports, + nonFrameworkAssemblyInputs, + nonFrameworkResolutions, + unresolvedReferences, + tcConfig: TcConfig, + projectDirectory, outfile, + assemblyName, niceNameGen: NiceNameGenerator, + analyzers: FSharpAnalyzer list, + lexResourceManager, sourceFiles, loadClosureOpt: LoadClosure option, keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, @@ -671,7 +681,6 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput #if !NO_EXTENSIONTYPING let importsInvalidatedByTypeProvider = new Event() #endif - let mutable currentTcImportsOpt = None let defaultPartialTypeChecking = enablePartialTypeChecking let mutable enablePartialTypeChecking = enablePartialTypeChecking @@ -756,7 +765,6 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput | true, tg -> tg.Trigger msg | _ -> ())) #endif - currentTcImportsOpt <- Some tcImports return tcImports with e -> System.Diagnostics.Debug.Assert(false, sprintf "Could not BuildAllReferencedDllTcImports %A" e) @@ -833,7 +841,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput let finalInfo = finalBoundModel.TcInfo |> Eventually.force ctok // Finish the checking - let (_tcEnvAtEndOfLastFile, topAttrs, mimpls, _), tcState = + let (_tcEnvAtEndOfLastFile, topAttrs, tcFileResults), tcState = let results = boundModels |> List.ofArray @@ -845,7 +853,12 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput else let tcInfo, tcInfoOptional = boundModel.TcInfoWithOptional |> Eventually.force ctok tcInfo, tcInfoOptional.latestImplFile - tcInfo.tcEnvAtEndOfFile, defaultArg tcInfo.topAttribs EmptyTopAttrs, latestImplFile, tcInfo.latestCcuSigForFile) + + assert tcInfo.latestCcuSigForFile.IsSome + assert boundModel.SyntaxTree.IsSome + let latestCcuSigForFile = tcInfo.latestCcuSigForFile.Value + let syntaxTree = boundModel.SyntaxTree.Value + tcInfo.tcEnvAtEndOfFile, defaultArg tcInfo.topAttribs EmptyTopAttrs, (syntaxTree, latestImplFile, latestCcuSigForFile)) TypeCheckMultipleInputsFinish (results, finalInfo.tcState) let ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt = @@ -854,7 +867,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput // so we make this temporary here let oldContents = tcState.Ccu.Deref.Contents try - let tcState, tcAssemblyExpr = TypeCheckClosedInputSetFinish (mimpls, tcState) + let tcState = TypeCheckClosedInputSetFinish (tcState) // Compute the identity of the generated assembly based on attributes, options etc. // Some of this is duplicated from fsc.fs @@ -896,7 +909,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput with e -> errorRecoveryNoRange e None - ilAssemRef, tcAssemblyDataOpt, Some tcAssemblyExpr + let mimpls = List.choose p23 tcFileResults + ilAssemRef, tcAssemblyDataOpt, Some mimpls finally tcState.Ccu.Deref.Contents <- oldContents with e -> @@ -1144,8 +1158,6 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput member _.ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider.Publish #endif - member _.TryGetCurrentTcImports () = currentTcImportsOpt - member _.AllDependenciesDeprecated = allDependencies member _.Step (ctok: CompilationThreadToken) = @@ -1253,6 +1265,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput member _.GetSlotsCount () = fileNames.Length + member _.Analyzers = analyzers + member this.ContainsFile(filename: string) = (this.TryGetSlotOfFileName filename).IsSome @@ -1410,10 +1424,20 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput for pr in projectReferences do yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + let builder = - new IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInputs, - nonFrameworkResolutions, unresolvedReferences, - tcConfig, projectDirectory, outfile, assemblyName, niceNameGen, + new IncrementalBuilder(tcGlobals, + frameworkTcImports, + nonFrameworkAssemblyInputs, + nonFrameworkResolutions, + unresolvedReferences, + tcConfig, + projectDirectory, + outfile, + assemblyName, + niceNameGen, + analyzers, resourceManager, sourceFilesNew, loadClosureOpt, keepAssemblyContents, keepAllBackgroundResolutions, diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 5ed26249366..2fbe4ed1ef4 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -150,9 +150,6 @@ type internal IncrementalBuilder = member ImportsInvalidatedByTypeProvider : IEvent #endif - /// Tries to get the current successful TcImports. This is only used in testing. Do not use it for other stuff. - member TryGetCurrentTcImports : unit -> TcImports option - /// The list of files the build depends on member AllDependenciesDeprecated : string[] @@ -222,6 +219,9 @@ type internal IncrementalBuilder = /// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed) member GetParseResultsForFile: CompilationThreadToken * filename:string -> Cancellable + /// Get the active analyzers for the project + member Analyzers: FSharpAnalyzer list + /// Create the incremental builder static member TryCreateIncrementalBuilderForProjectOptions: CompilationThreadToken * diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 994fb8a2ed0..2e7c441f974 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -21,6 +21,7 @@ open FSharp.Compiler.CompilerOptions open FSharp.Compiler.DependencyManager open FSharp.Compiler.Diagnostics open FSharp.Compiler.Driver +open FSharp.Compiler.EditorServices open FSharp.Compiler.ErrorLogger open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.ScriptClosure @@ -42,52 +43,6 @@ module EnvMisc = let maxMBDefault = GetEnvInteger "FCS_MaxMB" 1000000 // a million MB = 1TB = disabled //let maxMBDefault = GetEnvInteger "FCS_maxMB" (if sizeof = 4 then 1700 else 3400) -type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list - -// NOTE: may be better just to move to optional arguments here -type FSharpProjectOptions = - { - ProjectFileName: string - ProjectId: string option - SourceFiles: string[] - OtherOptions: string[] - ReferencedProjects: (string * FSharpProjectOptions)[] - IsIncompleteTypeCheckEnvironment : bool - UseScriptResolutionRules : bool - LoadTime : System.DateTime - UnresolvedReferences : FSharpUnresolvedReferencesSet option - OriginalLoadReferences: (range * string * string) list - Stamp : int64 option - } - member x.ProjectOptions = x.OtherOptions - /// Whether the two parse options refer to the same project. - static member UseSameProject(options1,options2) = - match options1.ProjectId, options2.ProjectId with - | Some(projectId1), Some(projectId2) when not (String.IsNullOrWhiteSpace(projectId1)) && not (String.IsNullOrWhiteSpace(projectId2)) -> - projectId1 = projectId2 - | Some(_), Some(_) - | None, None -> options1.ProjectFileName = options2.ProjectFileName - | _ -> false - - /// Compare two options sets with respect to the parts of the options that are important to building. - static member AreSameForChecking(options1,options2) = - match options1.Stamp, options2.Stamp with - | Some x, Some y -> (x = y) - | _ -> - FSharpProjectOptions.UseSameProject(options1, options2) && - options1.SourceFiles = options2.SourceFiles && - options1.OtherOptions = options2.OtherOptions && - options1.UnresolvedReferences = options2.UnresolvedReferences && - options1.OriginalLoadReferences = options2.OriginalLoadReferences && - options1.ReferencedProjects.Length = options2.ReferencedProjects.Length && - Array.forall2 (fun (n1,a) (n2,b) -> - n1 = n2 && - FSharpProjectOptions.AreSameForChecking(a,b)) options1.ReferencedProjects options2.ReferencedProjects && - options1.LoadTime = options2.LoadTime - - /// Compute the project directory. - member po.ProjectDirectory = System.IO.Path.GetDirectoryName(po.ProjectFileName) - override this.ToString() = "FSharpProjectOptions(" + this.ProjectFileName + ")" //---------------------------------------------------------------------------- // BackgroundCompiler @@ -426,7 +381,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC static let mutable foregroundTypeCheckCount = 0 - member _.RecordTypeCheckFileInProjectResults(filename,options,parsingOptions,parseResults,fileVersion,priorTimeStamp,checkAnswer,sourceText) = + member _.RecordCheckFileInProjectResults(filename,options,parsingOptions,parseResults,fileVersion,priorTimeStamp,checkAnswer,sourceText) = match checkAnswer with | None | Some FSharpCheckFileAnswer.Aborted -> () @@ -551,7 +506,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC reactorOps, userOpName, options.IsIncompleteTypeCheckEnvironment, - builder, + box builder, Array.ofList tcDependencyFiles, creationDiags, parseResults.Diagnostics, @@ -559,7 +514,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC suggestNamesForErrors) let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, Array.ofList builder.SourceFiles, options.UseScriptResolutionRules) reactor.SetPreferredUILang tcConfig.preferredUiLang - bc.RecordTypeCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, timeStamp, Some checkAnswer, sourceText.GetHashCode()) + bc.RecordCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, timeStamp, Some checkAnswer, sourceText.GetHashCode()) return checkAnswer finally let dummy = ref () @@ -703,6 +658,76 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC bc.ImplicitlyStartCheckProjectInBackground(options, userOpName) } + member bc.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, userOpName) = + let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "AnalyzeFileInProject", parseResults.FileName, action) + async { + let! analysisDiags = execWithReactorAsync (fun ctok -> + cancellable { + let! builderOpt, _creationDiags = getOrCreateBuilder (ctok, options, userOpName) + match builderOpt with + | None -> return [| |] + | Some builder -> + let fileName = parseResults.FileName + let ctxt = + FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], + fileName, + options, + parseResults, + checkResults) + + let! ct = Cancellable.token() + let diags = + let diagsCollector = ResizeArray() + for analyzer in builder.Analyzers do + let moreDiags = + try analyzer.OnCheckFile(ctxt, ct) + with exn -> + let m = Range.rangeN fileName 0 + let errExn = Error(FSComp.SR.etAnalyzerException(analyzer.GetType().FullName, fileName, exn.ToString()), m) + let diag = FSharpDiagnostic.CreateFromException(PhasedDiagnostic.Create(errExn, BuildPhase.TypeCheck), false, m, false) + [| diag |] + diagsCollector.AddRange(moreDiags) + diagsCollector.ToArray() + return diags + }) + return analysisDiags + } + + member bc.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, pos: Position, userOpName) = + let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "AnalyzeFileInProject", parseResults.FileName, action) + async { + let! analysisDiags = execWithReactorAsync (fun ctok -> + cancellable { + let! builderOpt, _creationDiags = getOrCreateBuilder (ctok, options, userOpName) + match builderOpt with + | None -> return [| |] + | Some builder -> + let fileName = parseResults.FileName + let ctxt = + FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], + fileName, + options, + parseResults, + checkResults) + + let! ct = Cancellable.token() + let tooltips = + let tooltipsCollector = ResizeArray() + for analyzer in builder.Analyzers do + try + match analyzer.TryAdditionalToolTip(ctxt, pos, ct) with + | Some t -> tooltipsCollector.Add(t) + | None -> () + with exn -> + let _, msg = FSComp.SR.etAnalyzerException(analyzer.GetType().FullName, fileName, exn.Message) + let diag = TaggedText.tagText msg + tooltipsCollector.Add([| diag |]) + + tooltipsCollector.ToArray() + return tooltips + }) + return analysisDiags + } /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) member _.GetBackgroundCheckResultsForFileInProject(filename, options, userOpName) = reactor.EnqueueAndAwaitOpAsync(userOpName, "GetBackgroundCheckResultsForFileInProject", filename, fun ctok -> @@ -740,7 +765,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC tcProj.TcConfig, tcProj.TcGlobals, options.IsIncompleteTypeCheckEnvironment, - builder, + Some (box builder), Array.ofList tcDependencyFiles, creationDiags, parseResults.Diagnostics, @@ -1259,6 +1284,14 @@ type FSharpChecker(legacyReferenceResolver, ic.CheckMaxMemoryReached() backgroundCompiler.CheckFileInProject(parseResults,filename,fileVersion,sourceText,options,userOpName) + member ic.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, userOpName) = + let userOpName = defaultArg userOpName "Unknown" + backgroundCompiler.AnalyzeFileInProject(parseResults,checkResults,sourceText,options,userOpName) + + member ic.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, pos: Position, userOpName) = + let userOpName = defaultArg userOpName "Unknown" + backgroundCompiler.GetAdditionalAnalyzerToolTips(parseResults,checkResults,sourceText,options,pos,userOpName) + /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. member ic.ParseAndCheckFileInProject(filename:string, fileVersion:int, sourceText:ISourceText, options:FSharpProjectOptions, ?userOpName: string) = diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index f646d0c1c1b..6d23856c9bb 100644 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -15,53 +15,6 @@ open FSharp.Compiler.Syntax open FSharp.Compiler.Text open FSharp.Compiler.Tokenization -/// Unused in this API -type public FSharpUnresolvedReferencesSet - -/// A set of information describing a project or script build configuration. -type public FSharpProjectOptions = - { - // Note that this may not reduce to just the project directory, because there may be two projects in the same directory. - ProjectFileName: string - - /// This is the unique identifier for the project, it is case sensitive. If it's None, will key off of ProjectFileName in our caching. - ProjectId: string option - - /// The files in the project - SourceFiles: string[] - - /// Additional command line argument options for the project. These can include additional files and references. - OtherOptions: string[] - - /// The command line arguments for the other projects referenced by this project, indexed by the - /// exact text used in the "-r:" reference in FSharpProjectOptions. - ReferencedProjects: (string * FSharpProjectOptions)[] - - /// When true, the typechecking environment is known a priori to be incomplete, for - /// example when a .fs file is opened outside of a project. In this case, the number of error - /// messages reported is reduced. - IsIncompleteTypeCheckEnvironment: bool - - /// When true, use the reference resolution rules for scripts rather than the rules for compiler. - UseScriptResolutionRules: bool - - /// Timestamp of project/script load, used to differentiate between different instances of a project load. - /// This ensures that a complete reload of the project or script type checking - /// context occurs on project or script unload/reload. - LoadTime: DateTime - - /// Unused in this API and should be 'None' when used as user-specified input - UnresolvedReferences: FSharpUnresolvedReferencesSet option - - /// Unused in this API and should be '[]' when used as user-specified input - OriginalLoadReferences: (range * string * string) list - - /// An optional stamp to uniquely identify this set of options - /// If two sets of options both have stamps, then they are considered equal - /// if and only if the stamps are equal - Stamp: int64 option - } - [] /// Used to parse and check F# source code. type public FSharpChecker = @@ -170,6 +123,29 @@ type public FSharpChecker = /// An optional string used for tracing compiler operations associated with this request. member CheckFileInProject: parseResults: FSharpParseFileResults * filename: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async + /// + /// Run analyzers on a source code file + /// + /// + /// The results of ParseFile for this file. + /// The results of CheckFileInProject for this file. + /// The full source for the file. + /// The options for the project or script. + /// An optional string used for tracing compiler operations associated with this request. + member AnalyzeFileInProject: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async + + /// + /// Get the additional tooltips provided by all analyzers at a specific location + /// + /// + /// The results of ParseFile for this file. + /// The results of CheckFileInProject for this file. + /// The full source for the file. + /// The options for the project or script. + /// The position where the tool tip is requested. + /// An optional string used for tracing compiler operations associated with this request. + member GetAdditionalAnalyzerToolTips: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * sourceText: ISourceText * options: FSharpProjectOptions * pos: Position * ?userOpName: string -> Async + /// /// /// Parse and check a source code file, returning a handle to the results diff --git a/src/fsharp/symbols/SymbolHelpers.fs b/src/fsharp/symbols/SymbolHelpers.fs index b9e1029c9f2..c671cedfc5f 100644 --- a/src/fsharp/symbols/SymbolHelpers.fs +++ b/src/fsharp/symbols/SymbolHelpers.fs @@ -29,7 +29,7 @@ type FSharpDiagnosticSeverity = | Warning | Error -type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: string, subcategory: string, errorNum: int) = +type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: string, subcategory: string, errorNum: int, numberPrefix: string) = member _.Range = m member _.Severity = severity @@ -40,6 +40,10 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str member _.ErrorNumber = errorNum + member _.ErrorNumberPrefix = numberPrefix + + member _.ErrorNumberText = numberPrefix + errorNum.ToString("0000") + member _.Start = m.Start member _.End = m.End @@ -56,11 +60,11 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str member _.WithStart newStart = let m = mkFileIndexRange m.FileIndex newStart m.End - FSharpDiagnostic(m, severity, message, subcategory, errorNum) + FSharpDiagnostic(m, severity, message, subcategory, errorNum, numberPrefix) member _.WithEnd newEnd = let m = mkFileIndexRange m.FileIndex m.Start newEnd - FSharpDiagnostic(m, severity, message, subcategory, errorNum) + FSharpDiagnostic(m, severity, message, subcategory, errorNum, numberPrefix) override _.ToString() = let fileName = m.FileName @@ -75,7 +79,7 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str let severity = if isError then FSharpDiagnosticSeverity.Error else FSharpDiagnosticSeverity.Warning let msg = bufs (fun buf -> OutputPhasedDiagnostic buf exn false suggestNames) let errorNum = GetDiagnosticNumber exn - FSharpDiagnostic(m, severity, msg, exn.Subcategory(), errorNum) + FSharpDiagnostic(m, severity, msg, exn.Subcategory(), errorNum, "FS") /// Decompose a warning or error into parts: position, severity, message, error number static member CreateFromExceptionAndAdjustEof(exn, isError, fallbackRange: range, (linesCount: int, lastLength: int), suggestNames: bool) = @@ -94,6 +98,11 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str static member NormalizeErrorString(text) = ErrorLogger.NormalizeErrorString(text) + static member Create(severity: FSharpDiagnosticSeverity, message: string, number: int, range: range, ?numberPrefix: string, ?subcategory: string) = + let subcategory = defaultArg subcategory BuildPhaseSubcategory.Analysis + let numberPrefix = defaultArg numberPrefix "FS" + FSharpDiagnostic(range, severity, message, subcategory, number, numberPrefix) + /// Use to reset error and warning handlers [] type ErrorScope() = diff --git a/src/fsharp/symbols/SymbolHelpers.fsi b/src/fsharp/symbols/SymbolHelpers.fsi index 798b072090c..a91739b61a8 100755 --- a/src/fsharp/symbols/SymbolHelpers.fsi +++ b/src/fsharp/symbols/SymbolHelpers.fsi @@ -57,7 +57,17 @@ namespace FSharp.Compiler.Diagnostics /// Gets the number for the diagnostic member ErrorNumber: int + /// Gets the number prefix for the diagnostic, usually "FS" but may differ for analyzers + member ErrorNumberPrefix: string + + /// Gets the full error number text e.g "FS0031" + member ErrorNumberText: string + + /// Creates a diagnostic, e.g. for reporting from an analyzer + static member Create: severity: FSharpDiagnosticSeverity * message: string * number: int * range: range * ?numberPrefix: string * ?subcategory: string -> FSharpDiagnostic + static member internal CreateFromExceptionAndAdjustEof: PhasedDiagnostic * isError: bool * range * lastPosInFile: (int*int) * suggestNames: bool -> FSharpDiagnostic + static member internal CreateFromException: PhasedDiagnostic * isError: bool * range * suggestNames: bool -> FSharpDiagnostic /// Newlines are recognized and replaced with (ASCII 29, the 'group separator'), diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 62de847f733..b1c198518b6 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -62,6 +62,31 @@ Argument {0} neodpovídá + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Navržené sestavení poskytovatele typu {0} nešlo načíst ze složky {1}, protože chyběla závislost nebo ji nešlo načíst. Všechny závislosti tohoto sestavení se musí nacházet ve stejné složce jako toto sestavení. Ohlášená výjimka: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 39ba79acced..f18ac1320a3 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -62,6 +62,31 @@ Das Argument "{0}" stimmt nicht überein. + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Die Typanbieter-Designerassembly "{0}" konnte aus dem Ordner "{1}" nicht geladen werden, weil eine Abhängigkeit fehlte oder nicht geladen werden konnte. Alle Abhängigkeiten der Typanbieter-Designerassembly müssen sich in demselben Ordner wie die Assembly befinden. Gemeldete Ausnahme: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 8e84e6f6a60..2f343ae6e5a 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -62,6 +62,31 @@ El argumento "{0}" no coincide. + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} No se pudo cargar el ensamblado del diseñador de proveedores de tipos "{0}" desde la carpeta "{1}" porque falta una dependencia o no se pudo cargar. Todas las dependencias del ensamblado del diseñador de proveedores de tipos deben encontrarse en la misma carpeta que el ensamblado. Se notificó la excepción: {2} - {3}. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 9b6afea1a50..828f1c03507 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -62,6 +62,31 @@ L'argument '{0}' ne correspond pas + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Impossible de charger l'assembly de concepteur de fournisseur de type '{0}' à partir du dossier '{1}', car une dépendance est manquante ou n'a pas pu être chargée. Toutes les dépendances de l'assembly de concepteur de fournisseur de type doivent se trouver dans le même dossier que cet assembly. Exception signalée : {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index ca0fecd3fb7..5c08a0c5189 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -62,6 +62,31 @@ L'argomento '{0}' non corrisponde + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Non è stato possibile caricare l'assembly '{0}' della finestra di progettazione del provider di tipi dalla cartella '{1}' perché una dipendenza non è presente o non è stato possibile caricarla. Tutte le dipendenze dell'assembly della finestra di progettazione del provider di tipi devono trovarsi nella stessa cartella dell'assembly. L'eccezione restituita è {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 922c0231ef1..9bc3ecd6385 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -62,6 +62,31 @@ 引数 '{0}' が一致しません + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 依存関係がないか、または読み込めなかったため、型プロバイダーのデザイナー アセンブリ '{0}' をフォルダー '{1}' から読み込めませんでした。型プロバイダーのデザイナー アセンブリのすべての依存関係は、そのアセンブリと同じフォルダーに配置されている必要があります。次の例外が報告されました: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 51449e93cf2..43e801facd6 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -62,6 +62,31 @@ '{0}' 인수가 일치하지 않습니다. + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 종속성이 없거나 로드되지 않았으므로 '{0}' 형식 공급자 디자이너 어셈블리를 '{1}' 폴더에서 로드할 수 없습니다. 형식 공급자 디자이너 어셈블리의 모든 종속성은 해당 어셈블리와 동일한 폴더에 있어야 합니다. 보고된 예외: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 600f79c6841..bf6d4eed3b7 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -62,6 +62,31 @@ Argument „{0}” nie jest zgodny + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Nie można załadować zestawu projektanta dostawców typów „{0}” z folderu „{1}”, ponieważ brakuje zależności lub nie można jej załadować. Wszystkie zależności zestawu projektanta dostawców typów muszą znajdować się w tym samym folderze co ten zestaw. Zgłoszony wyjątek: {2} — {3} diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index 34aaee4f99f..baa4c852add 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -62,6 +62,31 @@ O argumento '{0}' não corresponde + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Não foi possível carregar o assembly do designer do provedor de tipos '{0}' da pasta '{1}' porque uma dependência estava ausente ou não pôde ser carregada. Todas as dependências do assembly do designer do provedor de tipos precisam estar localizadas na mesma pasta que esse assembly. A exceção relatada foi: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index a114cb0e143..a99f66483f7 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -62,6 +62,31 @@ Аргумент "{0}" не соответствует + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Не удалось загрузить сборку конструктора поставщика типа "{0}" из папки "{1}", так как зависимость отсутствует или не может быть загружена. Все зависимости для сборки конструктора поставщика типа должны находиться в папке сборки. Получено исключение: {2} — {3} diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 35488763b0f..886f1e3a801 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -62,6 +62,31 @@ '{0}' bağımsız değişkeni eşleşmiyor + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} '{0}' tür sağlayıcısı tasarımcı bütünleştirilmiş kodu, bir bağımlılık eksik olduğundan veya yüklenemediğinden '{1}' klasöründen yüklenemedi. Tür sağlayıcısı tasarımcısı bütünleştirilmiş kodunun tüm bağımlılıkları, ilgili bütünleştirilmiş kodun bulunduğu klasörde bulunmalıdır. Bildirilen özel durum: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 7b96eaaf0a0..e54829a79f3 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -62,6 +62,31 @@ 参数 "{0}" 不匹配 + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 无法从文件夹“{1}”加载类型提供程序设计器程序集“{0}”,因为依赖项缺失或无法加载。类型提供程序设计器程序集的所有依赖项必须与该程序集位于同一文件夹中。报告的异常是: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 3c80e36fde1..d46c6c84b58 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -62,6 +62,31 @@ 引數 '{0}' 不相符 + + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + The analyzer '{0}' raised an exception during analyzer construction: '{1}'. + + + + The analyzer '{0}' doesn't have a valid constructor. + The analyzer '{0}' doesn't have a valid constructor. + + + + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + The analyzer '{0}' raised an exception during analysis of file '{1}': '{2}'. + + + + The analyzer '{0}' failed to load: '{1}' + The analyzer '{0}' failed to load: '{1}' + + + + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 因為缺少相依性或相依性無法載入,導致無法從資料夾 '{1}' 載入類型提供者設計工具組件 '{0}'。類型提供者設計工具組件的所有相依性都必須位於該組件所在的資料夾內。回報的例外狀況: {2} - {3} diff --git a/tests/FSharp.Compiler.UnitTests/CompilerTestHelpers.fs b/tests/FSharp.Compiler.UnitTests/CompilerTestHelpers.fs index 1ac573a84e2..f02688333b4 100644 --- a/tests/FSharp.Compiler.UnitTests/CompilerTestHelpers.fs +++ b/tests/FSharp.Compiler.UnitTests/CompilerTestHelpers.fs @@ -6,5 +6,5 @@ module CompilerTestHelpers = let (|Warning|_|) (exn: System.Exception) = match exn with | :? FSharp.Compiler.ErrorLogger.Error as e -> let n,d = e.Data0 in Some (n,d) - | :? FSharp.Compiler.ErrorLogger.NumberedError as e -> let n,d = e.Data0 in Some (n,d) + | :? FSharp.Compiler.ErrorLogger.CompilerToolDiagnostic as e -> let n,d = e.Data0 in Some (n,d) | _ -> None diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index efc4f2e5142..b5a8883ae46 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -120,6 +120,7 @@ let ``Test project1 and make sure TcImports gets cleaned up`` () = Assert.True weakTcImports.IsAlive weakTcImports + // Here we are only keeping a handle to weakTcImports and nothing else let weakTcImports = test () checker.InvalidateConfiguration (Project1.options) checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index 6e3cb4c34b4..f0b8f3d75e3 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -142,7 +142,7 @@ module internal RoslynHelpers = // (i.e the same error does not appear twice, where the only difference is the line endings.) let normalizedMessage = error.Message |> FSharpDiagnostic.NormalizeErrorString |> FSharpDiagnostic.NewlineifyErrorString - let id = "FS" + error.ErrorNumber.ToString("0000") + let id = error.ErrorNumberText let emptyString = LocalizableString.op_Implicit("") let description = LocalizableString.op_Implicit(normalizedMessage) let severity = if error.Severity = FSharpDiagnosticSeverity.Error then DiagnosticSeverity.Error else DiagnosticSeverity.Warning diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index 382c97db4f2..f9a320ff63e 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -249,7 +249,7 @@ type internal FSharpCompletionProvider let documentation = List() let collector = RoslynHelpers.CollectTaggedText documentation // mix main description and xmldoc by using one collector - XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description) + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description, [| |]) return CompletionDescription.Create(documentation.ToImmutableArray()) else return CompletionDescription.Empty diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index 7e1523ea0be..d5c7ca1a2ec 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -345,7 +345,8 @@ type internal FSharpSignatureHelpProvider typeParameterMap.Add, usage.Add, exceptions.Add, - tooltip) + tooltip, + [| |]) let fsharpDocs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 2ff45d77c38..3300b051d2b 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -71,7 +71,8 @@ type internal FSharpDocumentDiagnosticAnalyzer // In order to eleminate duplicates, we should not return parse errors here because they are returned by `AnalyzeSyntaxAsync` method. let allErrors = HashSet(results.Diagnostics, errorInfoEqualityComparer) allErrors.ExceptWith(parseResults.Diagnostics) - return Seq.toArray allErrors + let! analysisErrors = checker.AnalyzeFileInProject(parseResults, results, fsSourceText, options, userOpName=userOpName) + return Array.append (Seq.toArray allErrors) analysisErrors | DiagnosticsType.Syntax -> return parseResults.Diagnostics } @@ -132,3 +133,5 @@ type internal FSharpDocumentDiagnosticAnalyzer } |> Async.map (Option.defaultValue ImmutableArray.Empty) |> RoslynHelpers.StartAsyncAsTask cancellationToken + + diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 3eddf9a3ec8..2ef37669771 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -306,6 +306,7 @@ module internal XmlDocumentation = /// Build a data tip text string with xml comments injected. let BuildTipText(documentationProvider:IDocumentationBuilder, dataTipText: ToolTipElement list, + extras: FSharp.Compiler.Text.TaggedText[][], textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, showText, showExceptions, showParameters) = let textCollector: ITaggedTextCollector = TextSanitizingCollector(textCollector, lineLimit = 45) :> _ @@ -376,12 +377,15 @@ module internal XmlDocumentation = true List.fold Process false dataTipText |> ignore + for extra in extras do + AppendHardLine textCollector + extra |> Seq.iter textCollector.Add - let BuildDataTipText(documentationProvider, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, ToolTipText(dataTipText)) = - BuildTipText(documentationProvider, dataTipText, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, true, true, false) + let BuildDataTipText(documentationProvider, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, ToolTipText(dataTipText), extras: TaggedText[][]) = + BuildTipText(documentationProvider, dataTipText, extras, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, true, true, false) let BuildMethodOverloadTipText(documentationProvider, textCollector, xmlCollector, ToolTipText(dataTipText), showParams) = - BuildTipText(documentationProvider, dataTipText, textCollector, xmlCollector, xmlCollector, ignore, ignore, false, false, showParams) + BuildTipText(documentationProvider, dataTipText, [| |], textCollector, xmlCollector, xmlCollector, ignore, ignore, false, false, showParams) let BuildMethodParamText(documentationProvider, xmlCollector, xml, paramName) = AppendXmlComment(documentationProvider, TextSanitizingCollector(xmlCollector), TextSanitizingCollector(xmlCollector), xml, false, true, Some paramName) diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index ef29e2a7546..1101251fbe4 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -27,6 +27,7 @@ open FSharp.Compiler.Tokenization type internal QuickInfo = { StructuredText: ToolTipText + Extras: TaggedText[][] Span: TextSpan Symbol: FSharpSymbol option SymbolKind: LexerSymbolKind } @@ -61,21 +62,25 @@ module internal FSharpQuickInfo = let! extParsingOptions, extProjectOptions = projectInfoManager.TryGetOptionsByProject(document.Project, cancellationToken) let extDefines = CompilerEnvironment.GetCompilationDefinesForEditing extParsingOptions let! extLexerSymbol = Tokenizer.getSymbolAtPosition(extDocId, extSourceText, extSpan.Start, declRange.FileName, extDefines, SymbolLookupKind.Greedy, true, true) - let! _, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, sourceText=extSourceText, userOpName = userOpName) + let! extParseResults, _, extCheckFileResults = checker.ParseAndCheckDocument(extDocument, extProjectOptions, allowStaleResults=true, sourceText=extSourceText, userOpName = userOpName) let extQuickInfoText = extCheckFileResults.GetToolTip (declRange.StartLine, extLexerSymbol.Ident.idRange.EndColumn, extLineText, extLexerSymbol.FullIsland, FSharpTokenTag.IDENT) - match extQuickInfoText with - | ToolTipText [] - | ToolTipText [ToolTipElement.None] -> return! None - | extQuickInfoText -> + let fcsPos = Position.mkPos declRange.StartLine (extLexerSymbol.Ident.idRange.EndColumn-1) + let! extExtras = checker.GetAdditionalAnalyzerToolTips(extParseResults, extCheckFileResults, extSourceText.ToFSharpSourceText(), options=extProjectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync + let extExtras = extExtras |> Array.filter (fun arr -> arr.Length <> 0) + match extQuickInfoText, extExtras with + | ToolTipText [], [| |] + | ToolTipText [ToolTipElement.None], [| |] -> return! None + | _ -> let! extSymbolUse = extCheckFileResults.GetSymbolUseAtLocation(declRange.StartLine, extLexerSymbol.Ident.idRange.EndColumn, extLineText, extLexerSymbol.FullIsland) let! span = RoslynHelpers.TryFSharpRangeToTextSpan (extSourceText, extLexerSymbol.Range) return { StructuredText = extQuickInfoText + Extras = extExtras Span = span Symbol = Some extSymbolUse.Symbol SymbolKind = extLexerSymbol.Kind } @@ -98,7 +103,7 @@ module internal FSharpQuickInfo = let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! lexerSymbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, true, true) let idRange = lexerSymbol.Ident.idRange - let! _, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText=sourceText, userOpName = userOpName) + let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = true, sourceText=sourceText, userOpName = userOpName) let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line let lineText = (sourceText.Lines.GetLineFromPosition position).ToString() @@ -110,12 +115,16 @@ module internal FSharpQuickInfo = checkFileResults.GetToolTip (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland,tag) - match targetQuickInfo with - | ToolTipText [] - | ToolTipText [ToolTipElement.None] -> return! None + let fcsPos = Position.mkPos fcsTextLineNumber textLinePos.Character + let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, sourceText.ToFSharpSourceText(), options=projectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync + let extras = extras |> Array.filter (fun arr -> arr.Length <> 0) + match targetQuickInfo, extras with + | ToolTipText [], [| |] + | ToolTipText [ToolTipElement.None], [| |] -> return! None | _ -> let! targetTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, lexerSymbol.Range) return { StructuredText = targetQuickInfo + Extras = extras Span = targetTextSpan Symbol = symbol SymbolKind = lexerSymbol.Kind } @@ -180,20 +189,25 @@ type internal FSharpAsyncQuickInfoSource // test helper static member ProvideQuickInfo(checker:FSharpChecker, documentId:DocumentId, sourceText:SourceText, filePath:string, position:int, parsingOptions:FSharpParsingOptions, options:FSharpProjectOptions, textVersionHash:int, languageServicePerformanceOptions: LanguageServicePerformanceOptions) = asyncMaybe { - let! _, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName=FSharpQuickInfo.userOpName) + let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, options, languageServicePerformanceOptions, userOpName=FSharpQuickInfo.userOpName) let textLine = sourceText.Lines.GetLineFromPosition position + let textPos = sourceText.Lines.GetLinePosition position let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based let textLineString = textLine.ToString() let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true, true) let res = checkFileResults.GetToolTip (textLineNumber, symbol.Ident.idRange.EndColumn, textLineString, symbol.FullIsland, FSharpTokenTag.IDENT) - match res with - | ToolTipText [] - | ToolTipText [ToolTipElement.None] -> return! None + let fcsPos = Position.mkPos textLineNumber textPos.Character + let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, sourceText.ToFSharpSourceText(), options=options, pos=fcsPos, userOpName=FSharpQuickInfo.userOpName) |> liftAsync + let extras = extras |> Array.filter (fun arr -> arr.Length <> 0) + match res, extras with + | ToolTipText [], [| |] + | ToolTipText [ToolTipElement.None], [| |] -> return! None | _ -> let! symbolUse = checkFileResults.GetSymbolUseAtLocation (textLineNumber, symbol.Ident.idRange.EndColumn, textLineString, symbol.FullIsland) let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, symbol.Range) return { StructuredText = res + Extras = extras Span = symbolSpan Symbol = Some symbolUse.Symbol SymbolKind = symbol.Kind } @@ -201,7 +215,7 @@ type internal FSharpAsyncQuickInfoSource static member BuildSingleQuickInfoItem (documentationBuilder:IDocumentationBuilder) (quickInfo:QuickInfo) = let mainDescription, documentation, typeParameterMap, usage, exceptions = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, documentation.Add, typeParameterMap.Add, usage.Add, exceptions.Add, quickInfo.StructuredText) + XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, documentation.Add, typeParameterMap.Add, usage.Add, exceptions.Add, quickInfo.StructuredText, quickInfo.Extras) let docs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] (mainDescription, docs) @@ -236,8 +250,8 @@ type internal FSharpAsyncQuickInfoSource | Some sigQuickInfo, Some targetQuickInfo -> let mainDescription, targetDocumentation, sigDocumentation, typeParameterMap, exceptions, usage = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText) - XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, targetQuickInfo.StructuredText) + XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText, sigQuickInfo.Extras) + XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, targetQuickInfo.StructuredText, targetQuickInfo.Extras) // get whitespace nomalized documentation text let getText (tts: seq) = let text = From 03d01a6727fcc02f10285c48fc7da30980f9079e Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 8 Feb 2021 18:46:57 +0000 Subject: [PATCH 02/31] analyzers draft --- src/fsharp/fsc.fs | 7 +++++- src/fsharp/service/FSharpAnalyzer.fs | 6 ++---- src/fsharp/service/FSharpAnalyzer.fsi | 3 +++ src/fsharp/service/FSharpCheckerResults.fs | 24 ++++++++++++--------- src/fsharp/service/FSharpCheckerResults.fsi | 7 +++++- src/fsharp/service/IncrementalBuild.fs | 22 ++++++++++--------- src/fsharp/service/IncrementalBuild.fsi | 4 ++-- src/fsharp/service/service.fs | 4 ++-- 8 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 36aa3c2b21b..6d014d4605f 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -612,6 +612,11 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, Stamp = None } + let tcFileResults, implFilesRev = + ([], tcFileResults) ||> List.mapFold (fun implFilesRev (a,b,c) -> + let implFilesRev2 = Option.toList b @ implFilesRev + (a, List.rev implFilesRev2, c), implFilesRev2) + for (inp, implFileOpt, ccuSig) in tcFileResults do let parseResults = @@ -670,7 +675,7 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // checkResults) if tcConfig.typeCheckOnly then exiter.Exit 0 - let typedImplFiles = List.choose p23 tcFileResults + let typedImplFiles = List.rev implFilesRev Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedImplFiles, topAttrs, tcConfig, outfile, pdbfile, assemblyName, errorLogger, exiter) diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index 203ca4eca47..f3fc991064b 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -50,21 +50,19 @@ type public FSharpAnalyzer(context:FSharpAnalysisContext) = abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFileContext * position: Position * cancellationToken: CancellationToken -> TaggedText[] option abstract TryCodeFix: context: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option abstract FixableDiagnosticIds: string[] + abstract RequiresAssemblyContents: bool default _.OnCheckFile(_, _) = [| |] default _.OnCheckProject(_, _) = [| |] default _.TryAdditionalToolTip(_, _, _) = None default _.TryCodeFix(_, _, _) = None default _.FixableDiagnosticIds = [| |] + default _.RequiresAssemblyContents = false module FSharpAnalyzers = - open FSharp.Compiler open FSharp.Compiler.IO.FileSystemAutoOpens - open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.ErrorLogger - open FSharp.Compiler.TcGlobals open FSharp.Core.CompilerServices - open System.IO #if !NO_EXTENSIONTYPING let CreateAnalyzer (analyzerType: System.Type, m) = diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index d8ff8b4bdd2..807789671f1 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -51,6 +51,8 @@ type public FSharpAnalyzer = member Context: FSharpAnalysisContext + abstract RequiresAssemblyContents: bool + abstract OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] abstract OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] @@ -61,6 +63,7 @@ type public FSharpAnalyzer = abstract FixableDiagnosticIds: string[] + default RequiresAssemblyContents: bool default OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] default OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] default TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * Position * cancellationToken: CancellationToken -> TaggedText[] option diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index fc6d10b5159..bc61dd0ec3a 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -220,7 +220,7 @@ type internal TypeCheckInfo // This is a name resolution environment to use if no better match can be found. sFallback: NameResolutionEnv, loadClosure : LoadClosure option, - implFileOpt: TypedImplFile option, + implFiles: TypedImplFile list, openDeclarations: OpenDeclaration[]) = // These strings are potentially large and the editor may choose to hold them for a while. @@ -1420,7 +1420,7 @@ type internal TypeCheckInfo /// The assembly being analyzed member _.ThisCcu = thisCcu - member _.ImplementationFile = implFileOpt + member _.ImplementationFiles = implFiles /// All open declarations in the file, including auto open modules member _.OpenDeclarations = openDeclarations @@ -1824,7 +1824,7 @@ module internal ParseAndCheckFile = sink.GetSymbolUses(), tcEnvAtEnd.NameEnv, loadClosure, - (List.tryHead implFiles |> Option.bind p23), + (implFiles |> List.choose p23), sink.GetOpenDeclarations()) |> Result.Ok | None -> @@ -1935,28 +1935,32 @@ type FSharpCheckFileResults threadSafeOp (fun () -> [| |]) (fun scope -> - // This operation is not asynchronous - GetFormatSpecifierLocationsAndArity can be run on the calling thread scope.GetFormatSpecifierLocationsAndArity()) member _.GetSemanticClassification(range: range option) = threadSafeOp (fun () -> [| |]) (fun scope -> - // This operation is not asynchronous - GetSemanticClassification can be run on the calling thread scope.GetSemanticClassification(range)) member _.PartialAssemblySignature = threadSafeOp (fun () -> failwith "not available") (fun scope -> - // This operation is not asynchronous - PartialAssemblySignature can be run on the calling thread scope.PartialAssemblySignatureForFile) + member _.PartialAssemblyContents = + if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access PartialAssemblyContents, or an analyzer must request RequiresAssemblyContents" + threadSafeOp + (fun () -> failwith "not available") + (fun scope -> + let mimpls = scope.ImplementationFiles + FSharpAssemblyContents(scope.TcGlobals, scope.ThisCcu, Some scope.CcuSigForFile, scope.TcImports, mimpls)) + member _.ProjectContext = threadSafeOp (fun () -> failwith "not available") (fun scope -> - // This operation is not asynchronous - GetReferencedAssemblies can be run on the calling thread FSharpProjectContext(scope.ThisCcu, scope.GetReferencedAssemblies(), scope.AccessRights)) member _.DependencyFiles = dependencyFiles @@ -2007,7 +2011,7 @@ type FSharpCheckFileResults scopeOptX |> Option.map (fun scope -> let cenv = SymbolEnv(scope.TcGlobals, scope.ThisCcu, Some scope.CcuSigForFile, scope.TcImports) - scope.ImplementationFile |> Option.map (fun implFile -> FSharpImplementationFileContents(cenv, implFile))) + scope.ImplementationFiles |> List.tryLast |> Option.map (fun implFile -> FSharpImplementationFileContents(cenv, implFile))) |> Option.defaultValue None member _.OpenDeclarations = @@ -2051,14 +2055,14 @@ type FSharpCheckFileResults thisCcu, tcImports, tcAccessRights, sResolutions, sSymbolUses, sFallback, loadClosure, - implFileOpt, + implFiles, openDeclarations) = let tcFileInfo = TypeCheckInfo(tcConfig, tcGlobals, ccuSigForFile, thisCcu, tcImports, tcAccessRights, projectFileName, mainInputFileName, sResolutions, sSymbolUses, sFallback, loadClosure, - implFileOpt, openDeclarations) + implFiles, openDeclarations) let errors = FSharpCheckFileResults.JoinErrors(isIncompleteTypeCheckEnvironment, creationErrors, parseErrors, tcErrors) FSharpCheckFileResults (mainInputFileName, errors, Some tcFileInfo, dependencyFiles, builder, keepAssemblyContents) diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index d8bc7848231..6085588a933 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -160,6 +160,11 @@ type public FSharpCheckFileResults = /// The errors returned by parsing a source file. member Diagnostics: FSharpDiagnostic[] + /// Get a view of the overall contents of the assembly up to and including the file just checked. + /// Only available if keepAssemblyContents is true or an analyzer has requested assembly contents + /// be kept + member PartialAssemblyContents: FSharpAssemblyContents + /// Get a view of the contents of the assembly up to and including the file just checked member PartialAssemblySignature : FSharpAssemblySignature @@ -328,7 +333,7 @@ type public FSharpCheckFileResults = sSymbolUses: TcSymbolUses * sFallback: NameResolutionEnv * loadClosure : LoadClosure option * - implFileOpt: TypedImplFile option * + implFiles: TypedImplFile list * openDeclarations: OpenDeclaration[] -> FSharpCheckFileResults diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index f4c4f1dbb30..45f9089b8e1 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -191,8 +191,8 @@ type TcInfoOptional = /// Accumulated 'open' declarations, last file first tcOpenDeclarationsRev: OpenDeclaration[] list - /// Result of checking most recent file, if any - latestImplFile: TypedImplFile option + /// Contents of checking files, if any, last file first + tcImplFilesRev: TypedImplFile list /// If enabled, stores a linear list of ranges and strings that identify an Item(symbol) in a file. Used for background find all references. itemKeyStore: ItemKeyStore option @@ -374,7 +374,7 @@ type BoundModel private (tcConfig: TcConfig, tcResolutionsRev = [] tcSymbolUsesRev = [] tcOpenDeclarationsRev = [] - latestImplFile = None + tcImplFilesRev = [] itemKeyStore = None semanticClassificationKeyStore = None } @@ -483,7 +483,7 @@ type BoundModel private (tcConfig: TcConfig, let tcInfoOptional = { /// Only keep the typed interface files when doing a "full" build for fsc.exe, otherwise just throw them away - latestImplFile = if keepAssemblyContents then implFile else None + tcImplFilesRev = match implFile with Some f when keepAssemblyContents -> f :: prevTcInfoOptional.tcImplFilesRev | _ -> prevTcInfoOptional.tcImplFilesRev tcResolutionsRev = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty) :: prevTcInfoOptional.tcResolutionsRev tcSymbolUsesRev = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty) :: prevTcInfoOptional.tcSymbolUsesRev tcOpenDeclarationsRev = sink.GetOpenDeclarations() :: prevTcInfoOptional.tcOpenDeclarationsRev @@ -799,7 +799,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, tcResolutionsRev=[] tcSymbolUsesRev=[] tcOpenDeclarationsRev=[] - latestImplFile=None + tcImplFilesRev=[] itemKeyStore = None semanticClassificationKeyStore = None } @@ -846,19 +846,19 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, boundModels |> List.ofArray |> List.map (fun boundModel -> - let tcInfo, latestImplFile = + let tcInfo, tcImplFilesRev = if enablePartialTypeChecking then let tcInfo = boundModel.TcInfo |> Eventually.force ctok - tcInfo, None + tcInfo, [] else let tcInfo, tcInfoOptional = boundModel.TcInfoWithOptional |> Eventually.force ctok - tcInfo, tcInfoOptional.latestImplFile + tcInfo, tcInfoOptional.tcImplFilesRev assert tcInfo.latestCcuSigForFile.IsSome assert boundModel.SyntaxTree.IsSome let latestCcuSigForFile = tcInfo.latestCcuSigForFile.Value let syntaxTree = boundModel.SyntaxTree.Value - tcInfo.tcEnvAtEndOfFile, defaultArg tcInfo.topAttribs EmptyTopAttrs, (syntaxTree, latestImplFile, latestCcuSigForFile)) + tcInfo.tcEnvAtEndOfFile, defaultArg tcInfo.topAttribs EmptyTopAttrs, (syntaxTree, List.tryHead tcImplFilesRev, latestCcuSigForFile)) TypeCheckMultipleInputsFinish (results, finalInfo.tcState) let ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt = @@ -1425,6 +1425,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + let analyzersRequireAssemblyContents = + analyzers |> List.exists (fun analyzer -> analyzer.RequiresAssemblyContents) let builder = new IncrementalBuilder(tcGlobals, @@ -1439,7 +1441,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, niceNameGen, analyzers, resourceManager, sourceFilesNew, loadClosureOpt, - keepAssemblyContents, + (keepAssemblyContents || analyzersRequireAssemblyContents), keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 2fbe4ed1ef4..7b4aec85923 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -80,8 +80,8 @@ type internal TcInfoOptional = /// Accumulated 'open' declarations, last file first tcOpenDeclarationsRev: OpenDeclaration[] list - /// Result of checking most recent file, if any - latestImplFile: TypedImplFile option + /// Result of checking most recent file, if any, last file first + tcImplFilesRev: TypedImplFile list /// If enabled, stores a linear list of ranges and strings that identify an Item(symbol) in a file. Used for background find all references. itemKeyStore: ItemKeyStore option diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 2e7c441f974..e2469cfa5ce 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -750,7 +750,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let latestCcuSigForFile = tcInfo.latestCcuSigForFile let tcState = tcInfo.tcState let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile - let latestImplementationFile = tcInfoOptional.latestImplFile + let tcImplFiles = tcInfoOptional.tcImplFilesRev |> List.rev let tcDependencyFiles = tcInfo.tcDependencyFiles let tcErrors = tcInfo.TcErrors let errorOptions = builder.TcConfig.errorSeverityOptions @@ -779,7 +779,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC List.head tcSymbolUsesRev, tcEnvAtEnd.NameEnv, loadClosure, - latestImplementationFile, + tcImplFiles, List.head tcOpenDeclarationsRev) return (parseResults, typedResults) } From 0f2d7365b3689e0865da189d1f40e1beee72356a Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 8 Feb 2021 19:14:20 +0000 Subject: [PATCH 03/31] analyzers draft --- VisualFSharp.sln | 15 ++++++++++++ tests/service/data/TestAnalyzer/Analyzer.fs | 23 +++++++++++++++++++ .../data/TestAnalyzer/TestAnalyzer.fsproj | 20 ++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/service/data/TestAnalyzer/Analyzer.fs create mode 100644 tests/service/data/TestAnalyzer/TestAnalyzer.fsproj diff --git a/VisualFSharp.sln b/VisualFSharp.sln index 55dc1c07fed..614c6d91b3f 100644 --- a/VisualFSharp.sln +++ b/VisualFSharp.sln @@ -158,6 +158,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service", " EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}" EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestAnalyzer", "tests\service\data\TestAnalyzer\TestAnalyzer.fsproj", "{A341304E-7223-4931-88B5-690EE88C2241}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -924,6 +926,18 @@ Global {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|Any CPU.Build.0 = Release|Any CPU {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|x86.ActiveCfg = Release|Any CPU {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|x86.Build.0 = Release|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Debug|x86.ActiveCfg = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Debug|x86.Build.0 = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Proto|Any CPU.ActiveCfg = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Proto|Any CPU.Build.0 = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Proto|x86.ActiveCfg = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Proto|x86.Build.0 = Debug|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Release|Any CPU.Build.0 = Release|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Release|x86.ActiveCfg = Release|Any CPU + {A341304E-7223-4931-88B5-690EE88C2241}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -998,6 +1012,7 @@ Global {0610FB97-7C15-422A-86FD-32335C6DF14D} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449} {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77} {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449} + {A341304E-7223-4931-88B5-690EE88C2241} = {35636A82-401A-4C3A-B2AB-EB7DC5E9C268} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {48EDBBBE-C8EE-4E3C-8B19-97184A487B37} diff --git a/tests/service/data/TestAnalyzer/Analyzer.fs b/tests/service/data/TestAnalyzer/Analyzer.fs new file mode 100644 index 00000000000..36d3b7793f0 --- /dev/null +++ b/tests/service/data/TestAnalyzer/Analyzer.fs @@ -0,0 +1,23 @@ +namespace TestAnalyzer + +open FSharp.Core.CompilerServices +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Diagnostics +open FSharp.Compiler.Text + +[] +do() + +[] +type MyAnalyzer(ctxt) = + inherit FSharpAnalyzer(ctxt) + + override _.OnCheckFile(fileCtxt, ct) = + + let m = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 3 0) (Position.mkPos 3 80) + let m2 = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 6 0) (Position.mkPos 6 80) + let source = fileCtxt.TryGetFileSource(fileCtxt.ParseFileResults.FileName).Value + [| if source.ToString().Contains("WIBBLE") |> not then + FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 6 until the magic word WIBBLE appears", 45, m2, "FA") + if source.ToString().Contains("WAZZAM") |> not then + FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 3 until the magic word WAZZAM appears", 45, m, "FA") |] diff --git a/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj b/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj new file mode 100644 index 00000000000..1b00b0bd4e0 --- /dev/null +++ b/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj @@ -0,0 +1,20 @@ + + + + + net472 + true + nunit + $(OtherFlags) --nowarn:3390 --nowarn:3218 + + + + + + + + + + + + From 3b1c7f4b7e3cdee55e876207e25b75bc9ed02336 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 9 Feb 2021 01:24:07 +0000 Subject: [PATCH 04/31] fix some basics --- src/fsharp/fsc.fs | 14 +++----------- src/fsharp/service/FSharpAnalyzer.fs | 11 +++++++---- src/fsharp/service/FSharpAnalyzer.fsi | 10 ++++++---- src/fsharp/service/service.fs | 11 +++++++---- src/fsharp/utils/FileSystem.fs | 12 ++++++++++++ src/fsharp/utils/FileSystem.fsi | 3 +++ src/fsharp/utils/prim-lexing.fs | 1 + tests/service/data/TestAnalyzer/Analyzer.fs | 13 +++++++++---- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 4 ++-- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 6d014d4605f..9a16a277f70 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -586,16 +586,7 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) - let sourceTexts = - [| for sourceFile in sourceFiles -> - let sourceFile = FileSystem.GetFullPathShim sourceFile - use stream = FileSystem.FileStreamReadShim sourceFile - use reader = - match tcConfig.inputCodePage with - | None -> new StreamReader(stream, true) - | Some (n: int) -> new StreamReader(stream, Encoding.GetEncoding n) - let source = reader.ReadToEnd() - sourceFile, SourceText.ofString source |] + let sourceTexts = [| for sourceFile in sourceFiles -> sourceFile, SourceText.readFile sourceFile tcConfig.inputCodePage |] let projectOptions = { @@ -654,7 +645,8 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, inp.FileName, projectOptions, parseResults, - checkResults) + checkResults, + tcConfig) for analyzer in analyzers do let diagnostics = analyzer.OnCheckFile(ctxt, CancellationToken.None) diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index f3fc991064b..294029ad7d9 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -11,6 +11,7 @@ open System.Threading open Internal.Utilities.Library open FSharp.Compiler.CompilerConfig open FSharp.Compiler.Diagnostics +open FSharp.Compiler.IO open FSharp.Compiler.Text type FSharpAnalyzerTextChange = Range * string @@ -20,9 +21,10 @@ type public FSharpAnalyzerCheckFileContext(sourceTexts: (string * ISourceText)[] fileName: string, projectOptions: FSharpProjectOptions, parseResults: FSharpParseFileResults, - checkResults: FSharpCheckFileResults) = + checkResults: FSharpCheckFileResults, + tcConfig: TcConfig) = let sourceTextMap = Map.ofArray sourceTexts - member _.TryGetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then Some sourceTextMap.[fileName] else None + member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage member _.FileName = fileName member _.ProjectOptions = projectOptions member _.ParseFileResults = parseResults @@ -31,9 +33,10 @@ type public FSharpAnalyzerCheckFileContext(sourceTexts: (string * ISourceText)[] [] type public FSharpAnalyzerCheckProjectContext(sourceTexts: (string * ISourceText)[], projectOptions: FSharpProjectOptions, - checkResults: FSharpCheckProjectResults) = + checkResults: FSharpCheckProjectResults, + tcConfig: TcConfig) = let sourceTextMap = Map.ofArray sourceTexts - member _.TryGetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then Some sourceTextMap.[fileName] else None + member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage member _.ProjectOptions = projectOptions member _.CheckProjectResults = checkResults diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index 807789671f1..cce9f31a17a 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -16,9 +16,11 @@ type FSharpAnalyzerTextChange = Range * string [] type public FSharpAnalyzerCheckFileContext = - internal new: sourceTexts: (string * ISourceText)[] * fileName: string * projectOptions: FSharpProjectOptions * parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults -> FSharpAnalyzerCheckFileContext + internal new: sourceTexts: (string * ISourceText)[] * fileName: string * projectOptions: FSharpProjectOptions * parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * tcConfig: TcConfig -> FSharpAnalyzerCheckFileContext - member TryGetFileSource: fileName: string -> ISourceText option + member FileName: string + + member GetFileSource: fileName: string -> ISourceText member ProjectOptions: FSharpProjectOptions @@ -30,9 +32,9 @@ type public FSharpAnalyzerCheckFileContext = [] type public FSharpAnalyzerCheckProjectContext = - internal new: sourceTexts: (string * ISourceText)[] * projectOptions: FSharpProjectOptions * checkResults: FSharpCheckProjectResults -> FSharpAnalyzerCheckProjectContext + internal new: sourceTexts: (string * ISourceText)[] * projectOptions: FSharpProjectOptions * checkResults: FSharpCheckProjectResults * tcConfig: TcConfig -> FSharpAnalyzerCheckProjectContext - member TryGetFileSource: fileName: string -> ISourceText option + member GetFileSource: fileName: string -> ISourceText member ProjectOptions: FSharpProjectOptions diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index e2469cfa5ce..8f2ab24e09f 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -24,6 +24,7 @@ open FSharp.Compiler.Driver open FSharp.Compiler.EditorServices open FSharp.Compiler.ErrorLogger open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.IO open FSharp.Compiler.ScriptClosure open FSharp.Compiler.Symbols open FSharp.Compiler.Syntax @@ -667,13 +668,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match builderOpt with | None -> return [| |] | Some builder -> - let fileName = parseResults.FileName + let fileName = Path.GetFullPath parseResults.FileName let ctxt = FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], fileName, options, parseResults, - checkResults) + checkResults, + builder.TcConfig) let! ct = Cancellable.token() let diags = @@ -702,13 +704,14 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match builderOpt with | None -> return [| |] | Some builder -> - let fileName = parseResults.FileName + let fileName = Path.GetFullPath parseResults.FileName let ctxt = FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], fileName, options, parseResults, - checkResults) + checkResults, + builder.TcConfig) let! ct = Cancellable.token() let tooltips = diff --git a/src/fsharp/utils/FileSystem.fs b/src/fsharp/utils/FileSystem.fs index 570e3bffe23..5217964546c 100644 --- a/src/fsharp/utils/FileSystem.fs +++ b/src/fsharp/utils/FileSystem.fs @@ -5,6 +5,8 @@ namespace FSharp.Compiler.IO open System open System.IO open System.Reflection +open System.Text +open FSharp.Compiler.Text type IFileSystem = @@ -162,3 +164,13 @@ module FileSystemAutoOpens = static member OpenReaderAndRetry (filename, codepage, retryLocked) = getReader (filename, codepage, retryLocked) +module SourceText = + let readFile fileName inputCodePage = + let fileName = FileSystem.GetFullPathShim fileName + use stream = FileSystem.FileStreamReadShim fileName + use reader = + match inputCodePage with + | None -> new StreamReader(stream, true) + | Some (n: int) -> new StreamReader(stream, Encoding.GetEncoding n) + let source = reader.ReadToEnd() + SourceText.ofString source diff --git a/src/fsharp/utils/FileSystem.fsi b/src/fsharp/utils/FileSystem.fsi index 515d25c5918..d963f02ac2a 100644 --- a/src/fsharp/utils/FileSystem.fsi +++ b/src/fsharp/utils/FileSystem.fsi @@ -5,6 +5,7 @@ namespace FSharp.Compiler.IO open System open System.IO +open FSharp.Compiler.Text /// Represents a shim for the file system type public IFileSystem = @@ -68,3 +69,5 @@ module public FileSystemAutoOpens = static member internal OpenReaderAndRetry: filename:string * codepage:int option * retryLocked:bool -> System.IO.StreamReader +module internal SourceText = + val readFile: fileName: string -> inputCodePage: int option -> ISourceText \ No newline at end of file diff --git a/src/fsharp/utils/prim-lexing.fs b/src/fsharp/utils/prim-lexing.fs index 6a691af3cba..ed6c2ec34b0 100644 --- a/src/fsharp/utils/prim-lexing.fs +++ b/src/fsharp/utils/prim-lexing.fs @@ -104,6 +104,7 @@ type StringText(str: string) = module SourceText = let ofString str = StringText(str) :> ISourceText + // NOTE: the code in this file is a drop-in replacement runtime for Lexing.fs from the FsLexYacc repository namespace Internal.Utilities.Text.Lexing diff --git a/tests/service/data/TestAnalyzer/Analyzer.fs b/tests/service/data/TestAnalyzer/Analyzer.fs index 36d3b7793f0..5d99168a083 100644 --- a/tests/service/data/TestAnalyzer/Analyzer.fs +++ b/tests/service/data/TestAnalyzer/Analyzer.fs @@ -12,12 +12,17 @@ do() type MyAnalyzer(ctxt) = inherit FSharpAnalyzer(ctxt) - override _.OnCheckFile(fileCtxt, ct) = + override this.OnCheckFile(fileCtxt, ct) = let m = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 3 0) (Position.mkPos 3 80) let m2 = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 6 0) (Position.mkPos 6 80) - let source = fileCtxt.TryGetFileSource(fileCtxt.ParseFileResults.FileName).Value - [| if source.ToString().Contains("WIBBLE") |> not then + let source = fileCtxt.GetFileSource(fileCtxt.ParseFileResults.FileName) + let text = source.GetSubTextString(0,source.Length) + [| if text.Contains("WIBBLE") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 6 until the magic word WIBBLE appears", 45, m2, "FA") - if source.ToString().Contains("WAZZAM") |> not then + if text.Contains("WAZZAM") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 3 until the magic word WAZZAM appears", 45, m, "FA") |] + + override _.TryAdditionalToolTip(fileCtxt, pos, ct) = + Some [| TaggedText.tagText $"This thing is on line {pos.Line} in file {fileCtxt.ParseFileResults.FileName}" |] + diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 3300b051d2b..75d5517d4da 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -107,7 +107,7 @@ type internal FSharpDocumentDiagnosticAnalyzer interface IFSharpDocumentDiagnosticAnalyzer with - member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = + member _.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task> = asyncMaybe { let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) @@ -119,7 +119,7 @@ type internal FSharpDocumentDiagnosticAnalyzer |> Async.map (Option.defaultValue ImmutableArray.Empty) |> RoslynHelpers.StartAsyncAsTask cancellationToken - member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = + member _.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task> = asyncMaybe { let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) From e025cd762eb30233a39cfdb83c20f0d40d8fba40 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 9 Feb 2021 10:46:13 +0000 Subject: [PATCH 05/31] update surface area --- .../SurfaceArea.netstandard.fs | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index d129bade980..7612ee2d41c 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1349,6 +1349,35 @@ FSharp.Compiler.AbstractIL.ILBinaryReader+Shim: IAssemblyReader get_AssemblyRead FSharp.Compiler.AbstractIL.ILBinaryReader+Shim: Void set_AssemblyReader(IAssemblyReader) FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+Shim +FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean RequiresAssemblyContents +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean get_RequiresAssemblyContents() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext Context +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext get_Context() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckFile(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, System.Threading.CancellationToken) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckProject(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext, System.Threading.CancellationToken) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]] TryAdditionalToolTip(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Text.Position, System.Threading.CancellationToken) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Text.Range,System.String][]] TryCodeFix(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Diagnostics.FSharpDiagnostic[], System.Threading.CancellationToken) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] FixableDiagnosticIds +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] get_FixableDiagnosticIds() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Void .ctor(FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckFileResults +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckFileResults() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpParseFileResults ParseFileResults +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpParseFileResults get_ParseFileResults() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions get_ProjectOptions() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.String FileName +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.String get_FileName() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults CheckProjectResults +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults get_CheckProjectResults() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions get_ProjectOptions() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults Item FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_Item() @@ -1385,6 +1414,8 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.EditorServi FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.EditorServices.MethodGroup GetMethods(Int32, Int32, System.String, Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[System.String]]) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.EditorServices.SemanticClassificationItem[] GetSemanticClassification(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.EditorServices.ToolTipText GetToolTip(Int32, Int32, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], Int32) +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Symbols.FSharpAssemblyContents PartialAssemblyContents +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Symbols.FSharpAssemblyContents get_PartialAssemblyContents() FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Symbols.FSharpAssemblySignature PartialAssemblySignature FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Symbols.FSharpAssemblySignature get_PartialAssemblySignature() FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Symbols.FSharpOpenDeclaration[] OpenDeclarations @@ -1442,6 +1473,8 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] GetBackgroundParseResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] AnalyzeFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Text.TaggedText[][]] GetAdditionalAnalyzerToolTips(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Text.Position, Microsoft.FSharp.Core.FSharpOption`1[System.String]) 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]) @@ -1683,9 +1716,10 @@ FSharp.Compiler.DependencyManager.ResolvingErrorReport: Void .ctor(System.Object FSharp.Compiler.DependencyManager.ResolvingErrorReport: Void EndInvoke(System.IAsyncResult) FSharp.Compiler.DependencyManager.ResolvingErrorReport: Void Invoke(FSharp.Compiler.DependencyManager.ErrorReportType, Int32, System.String) FSharp.Compiler.Diagnostics.CompilerDiagnostics -FSharp.Compiler.Diagnostics.CompilerDiagnostics: System.String GetErrorMessage(FSharp.Compiler.Diagnostics.FSharpDiagnosticKind) FSharp.Compiler.Diagnostics.CompilerDiagnostics: System.Collections.Generic.IEnumerable`1[System.String] GetSuggestedNames(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit],Microsoft.FSharp.Core.Unit], System.String) +FSharp.Compiler.Diagnostics.CompilerDiagnostics: System.String GetErrorMessage(FSharp.Compiler.Diagnostics.FSharpDiagnosticKind) FSharp.Compiler.Diagnostics.FSharpDiagnostic +FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnostic Create(FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity, System.String, Int32, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity Severity FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Diagnostics.FSharpDiagnosticSeverity get_Severity() FSharp.Compiler.Diagnostics.FSharpDiagnostic: FSharp.Compiler.Text.Position End @@ -1704,12 +1738,16 @@ FSharp.Compiler.Diagnostics.FSharpDiagnostic: Int32 get_EndLine() FSharp.Compiler.Diagnostics.FSharpDiagnostic: Int32 get_ErrorNumber() FSharp.Compiler.Diagnostics.FSharpDiagnostic: Int32 get_StartColumn() FSharp.Compiler.Diagnostics.FSharpDiagnostic: Int32 get_StartLine() +FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String ErrorNumberPrefix +FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String ErrorNumberText FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String FileName FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String Message FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String NewlineifyErrorString(System.String) FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String NormalizeErrorString(System.String) FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String Subcategory FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String ToString() +FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String get_ErrorNumberPrefix() +FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String get_ErrorNumberText() FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String get_FileName() FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String get_Message() FSharp.Compiler.Diagnostics.FSharpDiagnostic: System.String get_Subcategory() @@ -2161,7 +2199,6 @@ FSharp.Compiler.EditorServices.FindDeclExternalParam: Int32 CompareTo(System.Obj FSharp.Compiler.EditorServices.FindDeclExternalParam: Int32 GetHashCode() FSharp.Compiler.EditorServices.FindDeclExternalParam: Int32 GetHashCode(System.Collections.IEqualityComparer) FSharp.Compiler.EditorServices.FindDeclExternalParam: System.String ToString() -FSharp.Compiler.EditorServices.FindDeclExternalParamModule FSharp.Compiler.EditorServices.FindDeclExternalSymbol FSharp.Compiler.EditorServices.FindDeclExternalSymbol+Constructor: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.EditorServices.FindDeclExternalParam] args FSharp.Compiler.EditorServices.FindDeclExternalSymbol+Constructor: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.EditorServices.FindDeclExternalParam] get_args() @@ -2274,7 +2311,6 @@ FSharp.Compiler.EditorServices.FindDeclExternalType: Int32 GetHashCode(System.Co FSharp.Compiler.EditorServices.FindDeclExternalType: Int32 Tag FSharp.Compiler.EditorServices.FindDeclExternalType: Int32 get_Tag() FSharp.Compiler.EditorServices.FindDeclExternalType: System.String ToString() -FSharp.Compiler.EditorServices.FindDeclExternalTypeModule FSharp.Compiler.EditorServices.FindDeclFailureReason FSharp.Compiler.EditorServices.FindDeclFailureReason+ProvidedMember: System.String get_memberName() FSharp.Compiler.EditorServices.FindDeclFailureReason+ProvidedMember: System.String memberName @@ -4801,7 +4837,9 @@ FSharp.Compiler.Syntax.ParsedInput: FSharp.Compiler.Text.Range Range FSharp.Compiler.Syntax.ParsedInput: FSharp.Compiler.Text.Range get_Range() FSharp.Compiler.Syntax.ParsedInput: Int32 Tag FSharp.Compiler.Syntax.ParsedInput: Int32 get_Tag() +FSharp.Compiler.Syntax.ParsedInput: System.String FileName FSharp.Compiler.Syntax.ParsedInput: System.String ToString() +FSharp.Compiler.Syntax.ParsedInput: System.String get_FileName() FSharp.Compiler.Syntax.ParsedScriptInteraction FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.ParsedScriptInteraction+Definitions: FSharp.Compiler.Text.Range range From 92ca5045cbf56493db844dcfacc6c2e03dbb4c22 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 9 Feb 2021 13:06:04 +0000 Subject: [PATCH 06/31] update surface area --- tests/FSharp.Core.UnitTests/SurfaceArea.fs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/FSharp.Core.UnitTests/SurfaceArea.fs b/tests/FSharp.Core.UnitTests/SurfaceArea.fs index 11fb8cec14e..4674c9bce83 100644 --- a/tests/FSharp.Core.UnitTests/SurfaceArea.fs +++ b/tests/FSharp.Core.UnitTests/SurfaceArea.fs @@ -774,6 +774,8 @@ Microsoft.FSharp.Core.CompilerServices.TypeProviderTypeAttributes: Microsoft.FSh Microsoft.FSharp.Core.CompilerServices.TypeProviderXmlDocAttribute: System.String CommentText Microsoft.FSharp.Core.CompilerServices.TypeProviderXmlDocAttribute: System.String get_CommentText() Microsoft.FSharp.Core.CompilerServices.TypeProviderXmlDocAttribute: Void .ctor(System.String) +Microsoft.FSharp.Core.CompilerServices.AnalyzerAssemblyAttribute: Void .ctor() +Microsoft.FSharp.Core.CompilerServices.AnalyzerAttribute: Void .ctor() Microsoft.FSharp.Core.CustomComparisonAttribute: Void .ctor() Microsoft.FSharp.Core.CustomEqualityAttribute: Void .ctor() Microsoft.FSharp.Core.CustomOperationAttribute: Boolean AllowIntoPattern From 89675e74694396816dc40d53038e32a826868d70 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 13 Feb 2021 00:07:02 +0000 Subject: [PATCH 07/31] updates to contain more in result types --- src/fsharp/fsc.fs | 14 ++-- src/fsharp/service/FSharpAnalyzer.fs | 32 ++++----- src/fsharp/service/FSharpAnalyzer.fsi | 35 +++++----- src/fsharp/service/FSharpCheckerResults.fs | 74 +++++++++++++++------ src/fsharp/service/FSharpCheckerResults.fsi | 14 +++- src/fsharp/service/IncrementalBuild.fs | 69 ++++++++++--------- src/fsharp/service/service.fs | 24 +++---- 7 files changed, 151 insertions(+), 111 deletions(-) diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 9a16a277f70..0a228423c20 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -593,7 +593,7 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, ProjectFileName = "compile.fsproj" ProjectId = None SourceFiles = Array.ofList sourceFiles - ReferencedProjects = [| |] //for a in tcImports.GetImportedAssemblies() -> a.FSharpViewOfMetadata.FileName |] + ReferencedProjects = [| |] OtherOptions = argv IsIncompleteTypeCheckEnvironment = true UseScriptResolutionRules = false @@ -624,6 +624,8 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, tcGlobals, false, None, + parseResults.ParseTree, + projectOptions, [| |], [| |], [| |], @@ -640,16 +642,10 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, implFileOpt, [| |]) - let ctxt = - FSharpAnalyzerCheckFileContext(sourceTexts, - inp.FileName, - projectOptions, - parseResults, - checkResults, - tcConfig) + let ctxt = FSharpAnalyzerCheckFileContext(sourceTexts, checkResults, CancellationToken.None, tcConfig) for analyzer in analyzers do - let diagnostics = analyzer.OnCheckFile(ctxt, CancellationToken.None) + let diagnostics = analyzer.OnCheckFile(ctxt) for diag in diagnostics do let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) match diag.Severity with diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index 294029ad7d9..55479a3fff6 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -18,27 +18,23 @@ type FSharpAnalyzerTextChange = Range * string [] type public FSharpAnalyzerCheckFileContext(sourceTexts: (string * ISourceText)[], - fileName: string, - projectOptions: FSharpProjectOptions, - parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, + cancellationToken: CancellationToken, tcConfig: TcConfig) = let sourceTextMap = Map.ofArray sourceTexts + member _.CancellationToken = cancellationToken member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage - member _.FileName = fileName - member _.ProjectOptions = projectOptions - member _.ParseFileResults = parseResults - member _.CheckFileResults = checkResults + member _.CheckerModel = checkResults [] type public FSharpAnalyzerCheckProjectContext(sourceTexts: (string * ISourceText)[], - projectOptions: FSharpProjectOptions, checkResults: FSharpCheckProjectResults, + cancellationToken: CancellationToken, tcConfig: TcConfig) = let sourceTextMap = Map.ofArray sourceTexts + member _.CancellationToken = cancellationToken member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage - member _.ProjectOptions = projectOptions - member _.CheckProjectResults = checkResults + member _.CheckerModel = checkResults [] type public FSharpAnalysisContext() = @@ -48,17 +44,17 @@ type public FSharpAnalysisContext() = [] type public FSharpAnalyzer(context:FSharpAnalysisContext) = member _.Context = context - abstract OnCheckFile: context: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] - abstract OnCheckProject: context: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] - abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFileContext * position: Position * cancellationToken: CancellationToken -> TaggedText[] option - abstract TryCodeFix: context: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + abstract OnCheckFile: context: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] + abstract OnCheckProject: context: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] + abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option + abstract TryCodeFix: context: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option abstract FixableDiagnosticIds: string[] abstract RequiresAssemblyContents: bool - default _.OnCheckFile(_, _) = [| |] - default _.OnCheckProject(_, _) = [| |] - default _.TryAdditionalToolTip(_, _, _) = None - default _.TryCodeFix(_, _, _) = None + default _.OnCheckFile(_) = [| |] + default _.OnCheckProject(_) = [| |] + default _.TryAdditionalToolTip(_, _) = None + default _.TryCodeFix(_, _) = None default _.FixableDiagnosticIds = [| |] default _.RequiresAssemblyContents = false diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index cce9f31a17a..2bb99624d8e 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -7,6 +7,7 @@ open System.Threading open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CompilerConfig open FSharp.Compiler.Diagnostics +open FSharp.Compiler.Syntax open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text @@ -16,29 +17,25 @@ type FSharpAnalyzerTextChange = Range * string [] type public FSharpAnalyzerCheckFileContext = - internal new: sourceTexts: (string * ISourceText)[] * fileName: string * projectOptions: FSharpProjectOptions * parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * tcConfig: TcConfig -> FSharpAnalyzerCheckFileContext + internal new: sourceTexts: (string * ISourceText)[] * checkResults: FSharpCheckFileResults * cancellationToken: CancellationToken * tcConfig: TcConfig -> FSharpAnalyzerCheckFileContext - member FileName: string + member CancellationToken: CancellationToken member GetFileSource: fileName: string -> ISourceText - member ProjectOptions: FSharpProjectOptions - - member ParseFileResults: FSharpParseFileResults - - member CheckFileResults: FSharpCheckFileResults + member CheckerModel: FSharpCheckFileResults /// The context for an analyzer when a project is checked [] type public FSharpAnalyzerCheckProjectContext = - internal new: sourceTexts: (string * ISourceText)[] * projectOptions: FSharpProjectOptions * checkResults: FSharpCheckProjectResults * tcConfig: TcConfig -> FSharpAnalyzerCheckProjectContext + internal new: sourceTexts: (string * ISourceText)[] * checkResults: FSharpCheckProjectResults * cancellationToken: CancellationToken * tcConfig: TcConfig -> FSharpAnalyzerCheckProjectContext - member GetFileSource: fileName: string -> ISourceText + member CancellationToken: CancellationToken - member ProjectOptions: FSharpProjectOptions + member GetFileSource: fileName: string -> ISourceText - member CheckProjectResults: FSharpCheckProjectResults + member CheckerModel: FSharpCheckProjectResults /// The context for an analyzer. Currently empty. [] @@ -55,21 +52,21 @@ type public FSharpAnalyzer = abstract RequiresAssemblyContents: bool - abstract OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + abstract OnCheckFile: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] - abstract OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] + abstract OnCheckProject: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] - abstract TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * Position * cancellationToken: CancellationToken -> TaggedText[] option + abstract TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option - abstract TryCodeFix: FSharpAnalyzerCheckFileContext * FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + abstract TryCodeFix: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option abstract FixableDiagnosticIds: string[] default RequiresAssemblyContents: bool - default OnCheckFile: FSharpAnalyzerCheckFileContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] - default OnCheckProject: FSharpAnalyzerCheckProjectContext * cancellationToken: CancellationToken -> FSharpDiagnostic[] - default TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * Position * cancellationToken: CancellationToken -> TaggedText[] option - default TryCodeFix: FSharpAnalyzerCheckFileContext * FSharpDiagnostic[] * cancellationToken: CancellationToken -> FSharpAnalyzerTextChange[] option + default OnCheckFile: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] + default OnCheckProject: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] + default TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option + default TryCodeFix: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option default FixableDiagnosticIds: string[] module internal FSharpAnalyzers = diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index bc61dd0ec3a..7450f475d58 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -215,6 +215,8 @@ type internal TypeCheckInfo tcAccessRights: AccessorDomain, projectFileName: string, mainInputFileName: string, + parseTree: ParsedInput option, + projectOptions: FSharpProjectOptions, sResolutions: TcResolutions, sSymbolUses: TcSymbolUses, // This is a name resolution environment to use if no better match can be found. @@ -498,7 +500,7 @@ type internal TypeCheckInfo | _ -> let bestQual, textChanged = match parseResults.ParseTree with - | Some(input) -> + | Some input -> match ParsedInput.GetRangeOfExprLeftOfDot(endOfExprPos,Some(input)) with // TODO we say "colAtEndOfNames" everywhere, but that's not really a good name ("foo . $" hit Ctrl-Space at $) | Some( exprRange) -> // We have an up-to-date sync parse, and know the exact range of the prior expression. @@ -993,6 +995,8 @@ type internal TypeCheckInfo member scope.IsRelativeNameResolvableFromSymbol(cursorPos: pos, plid: string list, symbol: FSharpSymbol) : bool = scope.IsRelativeNameResolvable(cursorPos, plid, symbol.Item) + member _.ParseTree = parseTree + /// Get the auto-complete items at a location member _.GetDeclarations (parseResultsOpt, line, lineStr, partialName, getAllEntities) = let isInterfaceFile = SourceFileImpl.IsInterfaceFile mainInputFileName @@ -1394,6 +1398,8 @@ type internal TypeCheckInfo member _.AccessRights = tcAccessRights + member _.ProjectOptions = projectOptions + member _.GetReferencedAssemblies() = [ for x in tcImports.GetImportedAssemblies() do yield FSharpAssembly(g, tcImports, x.FSharpViewOfMetadata) ] @@ -1725,6 +1731,7 @@ module internal ParseAndCheckFile = (parseResults: FSharpParseFileResults, sourceText: ISourceText, mainInputFileName: string, + projectOptions: FSharpProjectOptions, projectFileName: string, tcConfig: TcConfig, tcGlobals: TcGlobals, @@ -1819,7 +1826,9 @@ module internal ParseAndCheckFile = tcImports, tcEnvAtEnd.AccessRights, projectFileName, - mainInputFileName, + mainInputFileName, + parseResults.ParseTree, + projectOptions, sink.GetResolutions(), sink.GetSymbolUses(), tcEnvAtEnd.NameEnv, @@ -1834,7 +1843,9 @@ module internal ParseAndCheckFile = [] -type FSharpProjectContext(thisCcu: CcuThunk, assemblies: FSharpAssembly list, ad: AccessorDomain) = +type FSharpProjectContext(thisCcu: CcuThunk, assemblies: FSharpAssembly list, ad: AccessorDomain, projectOptions: FSharpProjectOptions) = + + member _.ProjectOptions = projectOptions /// Get the assemblies referenced member _.GetReferencedAssemblies() = assemblies @@ -1873,6 +1884,10 @@ type FSharpCheckFileResults | None -> None | Some (scope, _builderOpt) -> Some scope.TcImports + /// Intellisense autocompletions + member _.ParseTree = + threadSafeOp (fun () -> None) (fun scope -> scope.ParseTree) + /// Intellisense autocompletions member _.GetDeclarationListInfo(parsedFileResults, line, lineText, partialName, ?getAllEntities) = let getAllEntities = defaultArg getAllEntities (fun() -> []) @@ -1961,7 +1976,7 @@ type FSharpCheckFileResults threadSafeOp (fun () -> failwith "not available") (fun scope -> - FSharpProjectContext(scope.ThisCcu, scope.GetReferencedAssemblies(), scope.AccessRights)) + FSharpProjectContext(scope.ThisCcu, scope.GetReferencedAssemblies(), scope.AccessRights, scope.ProjectOptions)) member _.DependencyFiles = dependencyFiles @@ -2046,6 +2061,8 @@ type FSharpCheckFileResults tcConfig, tcGlobals, isIncompleteTypeCheckEnvironment: bool, builder: obj option, + parseTree, + projectOptions, dependencyFiles, creationErrors: FSharpDiagnostic[], parseErrors: FSharpDiagnostic[], @@ -2060,7 +2077,9 @@ type FSharpCheckFileResults let tcFileInfo = TypeCheckInfo(tcConfig, tcGlobals, ccuSigForFile, thisCcu, tcImports, tcAccessRights, - projectFileName, mainInputFileName, sResolutions, sSymbolUses, + projectFileName, mainInputFileName, + parseTree, projectOptions, + sResolutions, sSymbolUses, sFallback, loadClosure, implFiles, openDeclarations) @@ -2083,6 +2102,7 @@ type FSharpCheckFileResults userOpName: string, isIncompleteTypeCheckEnvironment: bool, builder: obj, + projectOptions: FSharpProjectOptions, dependencyFiles: string[], creationErrors: FSharpDiagnostic[], parseErrors: FSharpDiagnostic[], @@ -2091,7 +2111,7 @@ type FSharpCheckFileResults async { let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile - (parseResults, sourceText, mainInputFileName, projectFileName, tcConfig, tcGlobals, tcImports, + (parseResults, sourceText, mainInputFileName, projectOptions, projectFileName, tcConfig, tcGlobals, tcImports, tcState, moduleNamesDict, loadClosure, backgroundDiagnostics, reactorOps, userOpName, suggestNamesForErrors) match tcFileInfo with @@ -2117,7 +2137,7 @@ type FSharpCheckProjectResults diagnostics: FSharpDiagnostic[], details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * TcSymbolUses list * TopAttribs option * IRawFSharpAssemblyData option * ILAssemblyRef * - AccessorDomain * TypedImplFile list option * string[]) option) = + AccessorDomain * TypedImplFile list option * string[] * FSharpProjectOptions) option) = let getDetails() = match details with @@ -2134,12 +2154,12 @@ type FSharpCheckProjectResults member _.HasCriticalErrors = details.IsNone member _.AssemblySignature = - let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() FSharpAssemblySignature(tcGlobals, thisCcu, ccuSig, tcImports, topAttribs, ccuSig) member _.TypedImplementationFiles = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2148,7 +2168,7 @@ type FSharpCheckProjectResults member info.AssemblyContents = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2157,7 +2177,7 @@ type FSharpCheckProjectResults member _.GetOptimizedAssemblyContents() = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2176,7 +2196,7 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetUsesOfSymbol(symbol:FSharpSymbol, ?cancellationToken: CancellationToken) = - let (tcGlobals, _tcImports, _thisCcu, _ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, _tcImports, _thisCcu, _ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() tcSymbolUses |> Seq.collect (fun r -> r.GetUsesOfSymbol symbol.Item) @@ -2189,7 +2209,7 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetAllUsesOfAllSymbols(?cancellationToken: CancellationToken) = - let (tcGlobals, tcImports, thisCcu, ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let cenv = SymbolEnv(tcGlobals, thisCcu, Some ccuSig, tcImports) [| for r in tcSymbolUses do @@ -2201,22 +2221,22 @@ type FSharpCheckProjectResults yield FSharpSymbolUse(tcGlobals, symbolUse.DisplayEnv, symbol, symbolUse.ItemOccurence, symbolUse.Range) |] member _.ProjectContext = - let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, ad, _tcAssemblyExpr, _dependencyFiles, projectOptions) = getDetails() let assemblies = tcImports.GetImportedAssemblies() |> List.map (fun x -> FSharpAssembly(tcGlobals, tcImports, x.FSharpViewOfMetadata)) - FSharpProjectContext(thisCcu, assemblies, ad) + FSharpProjectContext(thisCcu, assemblies, ad, projectOptions) member _.RawFSharpAssemblyData = - let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() tcAssemblyData member _.DependencyFiles = - let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, dependencyFiles) = getDetails() + let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, dependencyFiles, _projectOptions) = getDetails() dependencyFiles member _.AssemblyFullName = - let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles) = getDetails() + let (_tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() ilAssemRef.QualifiedName override _.ToString() = "FSharpCheckProjectResults(" + projectFileName + ")" @@ -2259,9 +2279,23 @@ type FsiInteractiveChecker(legacyReferenceResolver, reduceMemoryUsage=reduceMemoryUsage, dependencyProvider=tcImports.DependencyProvider) + let projectOptions = + { + ProjectFileName="project" + ProjectId=None + SourceFiles=[||] + OtherOptions=[||] + ReferencedProjects=[||] + IsIncompleteTypeCheckEnvironment=false + UseScriptResolutionRules =false + LoadTime=System.DateTime.Now + UnresolvedReferences =None + OriginalLoadReferences = [] + Stamp = None + } let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile - (parseResults, sourceText, filename, "project", + (parseResults, sourceText, filename, projectOptions, "project", tcConfig, tcGlobals, tcImports, tcState, Map.empty, Some loadClosure, backgroundDiagnostics, reactorOps, userOpName, suggestNamesForErrors) @@ -2276,7 +2310,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, keepAssemblyContents, errors, Some(tcGlobals, tcImports, tcFileInfo.ThisCcu, tcFileInfo.CcuSigForFile, [tcFileInfo.ScopeSymbolUses], None, None, mkSimpleAssemblyRef "stdin", - tcState.TcEnvFromImpls.AccessRights, None, dependencyFiles)) + tcState.TcEnvFromImpls.AccessRights, None, dependencyFiles, projectOptions)) parseResults, typeCheckResults, projectResults diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index 6085588a933..975f0f49027 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -137,6 +137,9 @@ type public FSharpProjectContext = /// Get the accessibility rights for this project context w.r.t. InternalsVisibleTo attributes granting access to other assemblies member AccessibilityRights : FSharpAccessibilityRights + /// Get the project options + member ProjectOptions: FSharpProjectOptions + /// Options used to determine active --define conditionals and other options relevant to parsing files in a project type public FSharpParsingOptions = { @@ -157,6 +160,10 @@ type public FSharpParsingOptions = /// A handle to the results of CheckFileInProject. [] type public FSharpCheckFileResults = + + /// The syntax tree for the source file, if available + member ParseTree: ParsedInput option + /// The errors returned by parsing a source file. member Diagnostics: FSharpDiagnostic[] @@ -320,6 +327,8 @@ type public FSharpCheckFileResults = tcGlobals: TcGlobals * isIncompleteTypeCheckEnvironment: bool * builder: obj option * + parseTree: ParsedInput option * + projectOptions: FSharpProjectOptions * dependencyFiles: string[] * creationErrors: FSharpDiagnostic[] * parseErrors: FSharpDiagnostic[] * @@ -354,6 +363,7 @@ type public FSharpCheckFileResults = userOpName: string * isIncompleteTypeCheckEnvironment: bool * builder: obj * + projectOptions: FSharpProjectOptions * dependencyFiles: string[] * creationErrors:FSharpDiagnostic[] * parseErrors:FSharpDiagnostic[] * @@ -410,7 +420,9 @@ type public FSharpCheckProjectResults = tcConfigOption: TcConfig option * keepAssemblyContents: bool * diagnostics: FSharpDiagnostic[] * - details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * TcSymbolUses list * TopAttribs option * IRawFSharpAssemblyData option * ILAssemblyRef * AccessorDomain * TypedImplFile list option * string[]) option + details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * TcSymbolUses list * + TopAttribs option * IRawFSharpAssemblyData option * + ILAssemblyRef * AccessorDomain * TypedImplFile list option * string[] * FSharpProjectOptions) option -> FSharpCheckProjectResults module internal ParseAndCheckFile = diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 45f9089b8e1..726561fc36e 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -227,13 +227,14 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked: Event, fileChecked: Event, prevTcInfo: TcInfo, - prevTcInfoOptional: Eventually, + prevTcInfoOptional: (unit -> Eventually), syntaxTreeOpt: SyntaxTree option, - lazyTcInfoState: TcInfoState option ref) = + tcInfoStateOpt: TcInfoState option) = + let mutable lazyTcInfoState = tcInfoStateOpt let defaultTypeCheck () = eventually { - match prevTcInfoOptional with + match prevTcInfoOptional() with | Eventually.Done(Some prevTcInfoOptional) -> return FullState(prevTcInfo, prevTcInfoOptional) | _ -> @@ -262,13 +263,13 @@ type BoundModel private (tcConfig: TcConfig, member this.Invalidate() = let hasSig = this.BackingSignature.IsSome - match !lazyTcInfoState with + match lazyTcInfoState with // If partial checking is enabled and we have a backing sig file, then do nothing. The partial state contains the sig state. | Some(PartialState _) when enablePartialTypeChecking && hasSig -> () // If partial checking is enabled and we have a backing sig file, then use the partial state. The partial state contains the sig state. - | Some(FullState(tcInfo, _)) when enablePartialTypeChecking && hasSig -> lazyTcInfoState := Some(PartialState tcInfo) + | Some(FullState(tcInfo, _)) when enablePartialTypeChecking && hasSig -> lazyTcInfoState <- Some(PartialState tcInfo) | _ -> - lazyTcInfoState := None + lazyTcInfoState <- None // Always invalidate the syntax tree cache. syntaxTreeOpt @@ -281,33 +282,34 @@ type BoundModel private (tcConfig: TcConfig, else false let mustCheck = - match !lazyTcInfoState, partialCheck with + match lazyTcInfoState, partialCheck with | None, _ -> true | Some(PartialState _), false -> true | _ -> false if mustCheck then - lazyTcInfoState := None + lazyTcInfoState <- None - match !lazyTcInfoState with + match lazyTcInfoState with | Some tcInfoState -> tcInfoState |> Eventually.Done | _ -> eventually { let! tcInfoState = this.TypeCheck(partialCheck) - lazyTcInfoState := Some tcInfoState + lazyTcInfoState <- Some tcInfoState return tcInfoState } + member this.TryOptional() = + eventually { + let! prevState = this.GetState(false) + match prevState with + | FullState(_, prevTcInfoOptional) -> return Some prevTcInfoOptional + | _ -> return None + } + member this.Next(syntaxTree) = eventually { let! prevState = this.GetState(true) - let lazyPrevTcInfoOptional = - eventually { - let! prevState = this.GetState(false) - match prevState with - | FullState(_, prevTcInfoOptional) -> return Some prevTcInfoOptional - | _ -> return None - } return BoundModel( tcConfig, @@ -322,9 +324,9 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked, fileChecked, prevState.Partial, - lazyPrevTcInfoOptional, + (fun () -> this.TryOptional()), Some syntaxTree, - ref None) + None) } member this.Finish(finalTcErrorsRev, finalTopAttribs) = @@ -353,7 +355,7 @@ type BoundModel private (tcConfig: TcConfig, prevTcInfo, prevTcInfoOptional, syntaxTreeOpt, - ref (Some finishState)) + Some finishState) } member this.TcInfo = @@ -381,7 +383,7 @@ type BoundModel private (tcConfig: TcConfig, } member private this.TypeCheck (partialCheck: bool) = - match partialCheck, !lazyTcInfoState with + match partialCheck, lazyTcInfoState with | true, Some (PartialState _ as state) | true, Some (FullState _ as state) -> state |> Eventually.Done | false, Some (FullState _ as state) -> state |> Eventually.Done @@ -451,7 +453,7 @@ type BoundModel private (tcConfig: TcConfig, if partialCheck then return PartialState tcInfo else - match! prevTcInfoOptional with + match! prevTcInfoOptional() with | None -> return PartialState tcInfo | Some prevTcInfoOptional -> // Build symbol keys @@ -523,7 +525,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked: Event, fileChecked: Event, prevTcInfo: TcInfo, - prevTcInfoOptional: Eventually, + prevTcInfoOptional: (unit -> Eventually), syntaxTreeOpt: SyntaxTree option) = BoundModel(tcConfig, tcGlobals, tcImports, keepAssemblyContents, keepAllBackgroundResolutions, @@ -535,7 +537,7 @@ type BoundModel private (tcConfig: TcConfig, prevTcInfo, prevTcInfoOptional, syntaxTreeOpt, - ref None) + None) /// Global service state type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list * (*fsharpBinaries*)string * (*langVersion*)decimal @@ -588,7 +590,7 @@ type FrameworkImportsCache(size) = /// Represents the interim state of checking an assembly [] -type PartialCheckResults private (boundModel: BoundModel, timeStamp: DateTime) = +type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime) = let eval ctok (work: Eventually<'T>) = match work with @@ -596,7 +598,9 @@ type PartialCheckResults private (boundModel: BoundModel, timeStamp: DateTime) = | _ -> Eventually.force ctok work member _.TcImports = boundModel.TcImports + member _.TcGlobals = boundModel.TcGlobals + member _.TcConfig = boundModel.TcConfig member _.TimeStamp = timeStamp @@ -613,9 +617,6 @@ type PartialCheckResults private (boundModel: BoundModel, timeStamp: DateTime) = let _, info = boundModel.TcInfoWithOptional |> eval ctok info.semanticClassificationKeyStore - static member Create (boundModel: BoundModel, timestamp) = - PartialCheckResults(boundModel, timestamp) - [] module Utilities = let TryFindFSharpStringAttribute tcGlobals attribSpec attribs = @@ -814,7 +815,11 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, defaultPartialTypeChecking, - beforeFileChecked, fileChecked, tcInfo, Eventually.Done (Some tcInfoOptional), None) } + beforeFileChecked, + fileChecked, + tcInfo, + (fun () -> Eventually.Done (Some tcInfoOptional)), + None) } /// Type check all files. let TypeCheckTask ctok (prevBoundModel: BoundModel) syntaxTree: Eventually = @@ -1176,7 +1181,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, let result = tryGetBeforeSlot slotOfFile match result with - | Some (boundModel, timestamp) -> Some (PartialCheckResults.Create (boundModel, timestamp)) + | Some (boundModel, timestamp) -> Some (PartialCheckResults (boundModel, timestamp)) | _ -> None @@ -1192,7 +1197,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, let! result = eval cache ctok (slotOfFile - 1) match result with - | Some (boundModel, timestamp) -> return PartialCheckResults.Create (boundModel, timestamp) + | Some (boundModel, timestamp) -> return PartialCheckResults (boundModel, timestamp) | None -> return! failwith "Build was not evaluated, expected the results to be ready after 'Eval' (GetCheckResultsBeforeSlotInProject)." } @@ -1224,7 +1229,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, match! tryGetFinalized cache ctok with | Some ((ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, boundModel), timestamp) -> - return PartialCheckResults.Create (boundModel, timestamp), ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt + return PartialCheckResults (boundModel, timestamp), ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt | None -> let msg = "Build was not evaluated, expected the results to be ready after 'tryGetFinalized')." return! failwith msg diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 8f2ab24e09f..731fa80cabd 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -508,6 +508,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC userOpName, options.IsIncompleteTypeCheckEnvironment, box builder, + options, Array.ofList tcDependencyFiles, creationDiags, parseResults.Diagnostics, @@ -669,20 +670,18 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | None -> return [| |] | Some builder -> let fileName = Path.GetFullPath parseResults.FileName + let! ct = Cancellable.token() let ctxt = FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], - fileName, - options, - parseResults, checkResults, + ct, builder.TcConfig) - let! ct = Cancellable.token() let diags = let diagsCollector = ResizeArray() for analyzer in builder.Analyzers do let moreDiags = - try analyzer.OnCheckFile(ctxt, ct) + try analyzer.OnCheckFile(ctxt) with exn -> let m = Range.rangeN fileName 0 let errExn = Error(FSComp.SR.etAnalyzerException(analyzer.GetType().FullName, fileName, exn.ToString()), m) @@ -705,20 +704,18 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | None -> return [| |] | Some builder -> let fileName = Path.GetFullPath parseResults.FileName + let! ct = Cancellable.token() let ctxt = FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], - fileName, - options, - parseResults, checkResults, + ct, builder.TcConfig) - let! ct = Cancellable.token() let tooltips = let tooltipsCollector = ResizeArray() for analyzer in builder.Analyzers do try - match analyzer.TryAdditionalToolTip(ctxt, pos, ct) with + match analyzer.TryAdditionalToolTip(ctxt, pos) with | Some t -> tooltipsCollector.Add(t) | None -> () with exn -> @@ -769,6 +766,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC tcProj.TcGlobals, options.IsIncompleteTypeCheckEnvironment, Some (box builder), + parseTreeOpt, + options, Array.ofList tcDependencyFiles, creationDiags, parseResults.Diagnostics, @@ -850,8 +849,9 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let errors = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (errorOptions, true, fileName, tcErrors, suggestNamesForErrors) |] return FSharpCheckProjectResults (options.ProjectFileName, Some tcProj.TcConfig, keepAssemblyContents, errors, Some(tcProj.TcGlobals, tcProj.TcImports, tcState.Ccu, tcState.CcuSig, - tcSymbolUses, topAttribs, tcAssemblyDataOpt, ilAssemRef, - tcEnvAtEnd.AccessRights, tcAssemblyExprOpt, Array.ofList tcDependencyFiles)) + tcSymbolUses, topAttribs, tcAssemblyDataOpt, ilAssemRef, + tcEnvAtEnd.AccessRights, tcAssemblyExprOpt, Array.ofList tcDependencyFiles, + options)) } member _.GetAssemblyData(options, ctok, userOpName) = From 4ddc61e6c52312211c9b929c8ab1699709f50c28 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 16 Feb 2021 18:29:38 +0000 Subject: [PATCH 08/31] allow analyzers to run in fsi.exe with --runanalyzers, also respect --typecheckonly, also format analyzer extra tooltips at end --- src/fsharp/ParseAndCheckInputs.fs | 12 ++- src/fsharp/ParseAndCheckInputs.fsi | 1 + src/fsharp/ScriptClosure.fs | 7 +- src/fsharp/ScriptClosure.fsi | 3 + src/fsharp/TextLayoutRender.fs | 4 + src/fsharp/TextLayoutRender.fsi | 8 +- src/fsharp/fsc.fs | 72 +---------------- src/fsharp/fsi/FSIstrings.txt | 1 + src/fsharp/fsi/fsi.fs | 25 +++++- src/fsharp/fsi/xlf/FSIstrings.txt.cs.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.de.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.es.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.fr.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.it.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.ja.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.ko.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.pl.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.pt-BR.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.ru.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.tr.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hans.xlf | 5 ++ src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hant.xlf | 5 ++ src/fsharp/service/FSharpAnalyzer.fs | 80 ++++++++++++++++++- src/fsharp/service/FSharpAnalyzer.fsi | 5 ++ src/fsharp/service/IncrementalBuild.fs | 15 +++- src/fsharp/service/IncrementalBuild.fsi | 8 +- src/fsharp/service/ServiceLexing.fs | 1 + src/fsharp/service/service.fs | 28 ++++--- tests/service/data/TestAnalyzer/Analyzer.fs | 14 ++-- .../Completion/CompletionProvider.fs | 2 +- .../FSharp.Editor/Completion/SignatureHelp.fs | 7 +- .../DocComments/XMLDocumentation.fs | 31 ++++--- .../src/FSharp.Editor/QuickInfo/Navigation.fs | 14 ++++ .../QuickInfo/QuickInfoProvider.fs | 30 +++---- .../src/FSharp.Editor/QuickInfo/Views.fs | 4 + 35 files changed, 308 insertions(+), 129 deletions(-) diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index c1f340ac7d6..b07972ae03a 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -396,6 +396,7 @@ let ParseOneInputFile (tcConfig: TcConfig, lexResourceManager, conditionalCompil let ProcessMetaCommandsFromInput (nowarnF: 'state -> range * string -> 'state, hashReferenceF: 'state -> range * string * Directive -> 'state, + compilerToolF: 'state -> range * string -> 'state, loadSourceF: 'state -> range * string -> unit) (tcConfig:TcConfigBuilder, inp: ParsedInput, @@ -441,12 +442,15 @@ let ProcessMetaCommandsFromInput errorR(Error(FSComp.SR.buildInvalidHashIDirective(), m)) state | ParsedHashDirective("nowarn",numbers,m) -> - List.fold (fun state d -> nowarnF state (m,d)) state numbers + List.fold (fun state d -> nowarnF state (m,d)) state numbers | ParsedHashDirective(("reference" | "r"), args, m) -> matchedm<-m ProcessDependencyManagerDirective Directive.Resolution args m state + | ParsedHashDirective("compilertool", args, m) -> + List.fold (fun state d -> compilerToolF state (m,d)) state args + | ParsedHashDirective(("i"), args, m) -> matchedm<-m ProcessDependencyManagerDirective Directive.Include args m state @@ -526,9 +530,10 @@ let ApplyNoWarnsToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaComm let tcConfigB = tcConfig.CloneToBuilder() let addNoWarn = fun () (m,s) -> tcConfigB.TurnWarningOff(m, s) let addReference = fun () (_m, _s, _) -> () + let addCompilerTool = fun () (_m, _s) -> () let addLoadedSource = fun () (_m, _s) -> () ProcessMetaCommandsFromInput - (addNoWarn, addReference, addLoadedSource) + (addNoWarn, addReference, addCompilerTool, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) @@ -537,9 +542,10 @@ let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, let tcConfigB = tcConfig.CloneToBuilder() let getWarningNumber = fun () _ -> () let addReferenceDirective = fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive) + let addCompilerTool = fun () (_m, s) -> tcConfigB.AddCompilerToolsByPath(s) let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s,pathOfMetaCommandSource) ProcessMetaCommandsFromInput - (getWarningNumber, addReferenceDirective, addLoadedSource) + (getWarningNumber, addReferenceDirective, addCompilerTool, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) TcConfig.Create(tcConfigB, validate=false) diff --git a/src/fsharp/ParseAndCheckInputs.fsi b/src/fsharp/ParseAndCheckInputs.fsi index 101dcd31db9..ca218331564 100644 --- a/src/fsharp/ParseAndCheckInputs.fsi +++ b/src/fsharp/ParseAndCheckInputs.fsi @@ -36,6 +36,7 @@ val ParseInput: (Lexbuf -> Parser.token) * ErrorLogger * Lexbuf * string option val ProcessMetaCommandsFromInput : (('T -> range * string -> 'T) * ('T -> range * string * Directive -> 'T) * + ('T -> range * string -> 'T) * ('T -> range * string -> unit)) -> TcConfigBuilder * ParsedInput * string * 'T -> 'T diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index 494c47906a0..4cd386ef57b 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -38,6 +38,9 @@ type LoadClosure = /// The resolved references along with the ranges of the #r positions in each file. References: (string * AssemblyResolution list) list + /// The referenced compiler tools. + CompilerTools: string list + /// The resolved pacakge references along with the ranges of the #r positions in each file. PackageReferences: (range * string list)[] @@ -200,9 +203,10 @@ module ScriptPreprocessClosure = let mutable nowarns = [] let getWarningNumber = fun () (m, s) -> nowarns <- (s, m) :: nowarns let addReferenceDirective = fun () (m, s, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive) + let addCompilerTool = fun () (_m, s) -> tcConfigB.AddCompilerToolsByPath(s) let addLoadedSource = fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource) try - ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) + ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addCompilerTool, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) with ReportedError _ -> // Recover by using whatever did end up in the tcConfig () @@ -408,6 +412,7 @@ module ScriptPreprocessClosure = let result: LoadClosure = { SourceFiles = List.groupBy fst sourceFiles |> List.map (map2Of2 (List.map snd)) References = List.groupBy fst references |> List.map (map2Of2 (List.map snd)) + CompilerTools = tcConfig.compilerToolPaths PackageReferences = packageReferences UseDesktopFramework = (tcConfig.primaryAssembly = PrimaryAssembly.Mscorlib) SdkDirOverride = tcConfig.sdkDirOverride diff --git a/src/fsharp/ScriptClosure.fsi b/src/fsharp/ScriptClosure.fsi index 67d90654a27..84059c564df 100644 --- a/src/fsharp/ScriptClosure.fsi +++ b/src/fsharp/ScriptClosure.fsi @@ -40,6 +40,9 @@ type LoadClosure = /// The resolved references along with the ranges of the #r positions in each file. References: (string * AssemblyResolution list) list + /// The referenced compiler tools. + CompilerTools: string list + /// The resolved pacakge references along with the ranges of the #r positions in each file. PackageReferences: (range * string list)[] diff --git a/src/fsharp/TextLayoutRender.fs b/src/fsharp/TextLayoutRender.fs index 83a8e1d0590..fe67864d583 100644 --- a/src/fsharp/TextLayoutRender.fs +++ b/src/fsharp/TextLayoutRender.fs @@ -16,6 +16,10 @@ type NavigableTaggedText(taggedText: TaggedText, range: range) = inherit TaggedText(taggedText.Tag, taggedText.Text) member val Range = range +type WebLinkTaggedText(taggedText: TaggedText, uri: System.Uri) = + inherit TaggedText(taggedText.Tag, taggedText.Text) + member val Uri = uri + module SepL = let dot = sepL TaggedText.dot let star = sepL TaggedText.star diff --git a/src/fsharp/TextLayoutRender.fsi b/src/fsharp/TextLayoutRender.fsi index 25f67418c02..c9237fd4cef 100644 --- a/src/fsharp/TextLayoutRender.fsi +++ b/src/fsharp/TextLayoutRender.fsi @@ -10,10 +10,16 @@ open FSharp.Compiler.Text /// An enhancement to TaggedText in the TaggedText layouts generated by FSharp.Compiler.Service type public NavigableTaggedText = - internal new: TaggedText * range -> NavigableTaggedText + new: taggedText: TaggedText * range: range -> NavigableTaggedText member Range: range inherit TaggedText +/// An enhancement to TaggedText in the TaggedText layouts generated by FSharp.Compiler.Service +type public WebLinkTaggedText = + new: taggedText: TaggedText * uri: System.Uri -> WebLinkTaggedText + member Uri: System.Uri + inherit TaggedText + /// Render a Layout yielding an 'a using a 'b (hidden state) type type internal LayoutRenderer<'a,'b> = abstract Start: unit -> 'b diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 0a228423c20..30813f884fa 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -586,73 +586,9 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) - let sourceTexts = [| for sourceFile in sourceFiles -> sourceFile, SourceText.readFile sourceFile tcConfig.inputCodePage |] - - let projectOptions = - { - ProjectFileName = "compile.fsproj" - ProjectId = None - SourceFiles = Array.ofList sourceFiles - ReferencedProjects = [| |] - OtherOptions = argv - IsIncompleteTypeCheckEnvironment = true - UseScriptResolutionRules = false - LoadTime = DateTime.MaxValue - OriginalLoadReferences = [] - UnresolvedReferences = None - Stamp = None - } - - let tcFileResults, implFilesRev = - ([], tcFileResults) ||> List.mapFold (fun implFilesRev (a,b,c) -> - let implFilesRev2 = Option.toList b @ implFilesRev - (a, List.rev implFilesRev2, c), implFilesRev2) - - for (inp, implFileOpt, ccuSig) in tcFileResults do - - let parseResults = - FSharpParseFileResults(diagnostics = [||], - input = Some inp, - parseHadErrors = false, - dependencyFiles = [| |]) - - let checkResults = - FSharpCheckFileResults.Make - (inp.FileName, - "compile.fsproj", - tcConfig, - tcGlobals, - false, - None, - parseResults.ParseTree, - projectOptions, - [| |], - [| |], - [| |], - [| |], - true, - ccuSig, - tcState.Ccu, - tcImports, - tcEnvAtEnd.AccessRights, - TcResolutions.Empty, - TcSymbolUses.Empty, - tcEnvAtEnd.NameEnv, - None, - implFileOpt, - [| |]) - - let ctxt = FSharpAnalyzerCheckFileContext(sourceTexts, checkResults, CancellationToken.None, tcConfig) - - for analyzer in analyzers do - let diagnostics = analyzer.OnCheckFile(ctxt) - for diag in diagnostics do - let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) - match diag.Severity with - | FSharpDiagnosticSeverity.Error -> errorR(exn) - | FSharpDiagnosticSeverity.Warning -> warning(exn) - | FSharpDiagnosticSeverity.Info -> warning(exn) - | FSharpDiagnosticSeverity.Hidden -> () + FSharpAnalyzers.RunAnalyzers(analyzers, tcConfig, tcImports, tcGlobals, tcState.Ccu, sourceFiles, tcFileResults, tcEnvAtEnd) + + let typedImplFiles = tcFileResults |> List.collect (fun (_a,b,_c) -> Option.toList b) // TODO: run project analysis //let ctxt = @@ -662,8 +598,6 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, // parseResults, // checkResults) if tcConfig.typeCheckOnly then exiter.Exit 0 - - let typedImplFiles = List.rev implFilesRev Args (ctok, tcGlobals, tcImports, frameworkTcImports, tcState.Ccu, typedImplFiles, topAttrs, tcConfig, outfile, pdbfile, assemblyName, errorLogger, exiter) diff --git a/src/fsharp/fsi/FSIstrings.txt b/src/fsharp/fsi/FSIstrings.txt index dbd7642476b..86d02c5fcf0 100644 --- a/src/fsharp/fsi/FSIstrings.txt +++ b/src/fsharp/fsi/FSIstrings.txt @@ -14,6 +14,7 @@ fsiRemaining,"Treat remaining arguments as command line arguments, accessed usin fsiHelp,"Display this usage message (Short form: -?)" fsiExec,"Exit fsi after loading the files or running the .fsx script given on the command line" fsiGui,"Execute interactions on a Windows Forms event loop (on by default)" +fsiRunAnalyzers,"Execute analyzers (off by default)" fsiQuiet,"Suppress fsi writing to stdout" fsiReadline,"Support TAB completion in console (on by default)" fsiEmitDebugInfoInQuotations,"Emit debug information in quotations" diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 705b4ebf86f..e0914231c58 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -616,6 +616,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, not (runningOnMono && System.Environment.OSVersion.Platform = System.PlatformID.Win32NT) let mutable gui = not runningOnMono // override via "--gui", on by default except when on Mono + let mutable runAnalyzers = false #if DEBUG let mutable showILCode = false // show modul il code #endif @@ -744,6 +745,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, PublicOptions(FSComp.SR.optsHelpBannerAdvanced(), [CompilerOption("exec", "", OptionUnit (fun () -> interact <- false), None, Some (FSIstrings.SR.fsiExec())); CompilerOption("gui", tagNone, OptionSwitch(fun flag -> gui <- (flag = OptionSwitch.On)),None,Some (FSIstrings.SR.fsiGui())); + CompilerOption("runanalyzers", tagNone, OptionSwitch(fun flag -> runAnalyzers <- (flag = OptionSwitch.On)),None,Some (FSIstrings.SR.fsiRunAnalyzers())); CompilerOption("quiet", "", OptionUnit (fun () -> tcConfigB.noFeedback <- true), None,Some (FSIstrings.SR.fsiQuiet())); (* Renamed --readline and --no-readline to --tabcompletion:+|- *) CompilerOption("readline", tagNone, OptionSwitch(fun flag -> enableConsoleKeyProcessing <- (flag = OptionSwitch.On)), None, Some(FSIstrings.SR.fsiReadline())); @@ -838,6 +840,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, member _.PeekAheadOnConsoleToPermitTyping = peekAheadOnConsoleToPermitTyping member _.SourceFiles = sourceFiles member _.Gui = gui + member _.RunAnalyzers = runAnalyzers member _.WriteReferencesAndExit = writeReferencesAndExit @@ -983,6 +986,7 @@ type internal FsiDynamicCompilerState = tcGlobals : TcGlobals tcState : TcState tcImports : TcImports + tcAnalyzers: FSharpAnalyzer list ilxGenerator : IlxGen.IlxAssemblyGenerator boundValues : NameMap // Why is this not in FsiOptions? @@ -1171,8 +1175,9 @@ type internal FsiDynamicCompiler Microsoft.FSharp.Quotations.Expr.RegisterReflectedDefinitions (assemblyBuilder, fragName, bytes, referencedTypes); - ReportTime tcConfig "Run Bindings"; - timeReporter.TimeOpIf istate.timing (fun () -> + if not tcConfig.typeCheckOnly then + ReportTime tcConfig "Run Bindings"; + timeReporter.TimeOpIf istate.timing (fun () -> execs |> List.iter (fun exec -> match exec() with | Some err -> @@ -1191,7 +1196,7 @@ type internal FsiDynamicCompiler // Echo the decls (reach inside wrapping) // This code occurs AFTER the execution of the declarations. // So stored values will have been initialised, modified etc. - if showTypes && not tcConfig.noFeedback then + if showTypes && not tcConfig.noFeedback && not tcConfig.typeCheckOnly then let denv = tcState.TcEnvFromImpls.DisplayEnv let denv = if isIncrementalFragment then @@ -1252,6 +1257,9 @@ type internal FsiDynamicCompiler let (tcState:TcState), topCustomAttrs, declaredImpls, tcEnvAtEndOfLastInput = lock tcLockObject (fun _ -> TypeCheckClosedInputSet(ctok, errorLogger.CheckForErrors, tcConfig, tcImports, tcGlobals, Some prefixPath, tcState, inputs)) + if fsiOptions.RunAnalyzers then + FSharpAnalyzers.RunAnalyzers(istate.tcAnalyzers, tcConfig, tcImports, tcGlobals, tcState.Ccu, [], declaredImpls, tcEnvAtEndOfLastInput) + // TODO: run analyzers here let declaredImpls = List.map p23 declaredImpls |> List.choose id let codegenResults, optEnv, fragName = ProcessTypedImpl(errorLogger, optEnv, tcState, tcConfig, isInteractiveItExpr, topCustomAttrs, prefixPath, isIncrementalFragment, declaredImpls, ilxGenerator) @@ -1554,6 +1562,7 @@ type internal FsiDynamicCompiler | path, _ -> snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) ), + (fun st (_m,nm) -> tcConfigB.AddCompilerToolsByPath(nm); st), (fun _ _ -> ())) (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) @@ -1696,6 +1705,7 @@ type internal FsiDynamicCompiler tcGlobals = tcGlobals tcState = tcState tcImports = tcImports + tcAnalyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) ilxGenerator = ilxGenerator boundValues = NameMap.empty timing = false @@ -2229,6 +2239,15 @@ type internal FsiInteractionProcessor | ParsedScriptInteraction.HashDirective (ParsedHashDirective(("reference" | "r"), [path], m), _) -> packageManagerDirective Directive.Resolution path m + | ParsedScriptInteraction.HashDirective (ParsedHashDirective("compilertool", [path], m), _) -> + let istate = + if FileSystem.SafeExists(path) then + { istate with tcAnalyzers = istate.tcAnalyzers @ FSharpAnalyzers.CreateAnalyzers (path, m) } + else + // TODO: give a warning here (or in CreateAnalyzers) + istate + istate, Completed None + | ParsedScriptInteraction.HashDirective (ParsedHashDirective("i", [path], m), _) -> packageManagerDirective Directive.Include path m diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.cs.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.cs.xlf index e7c41ab141d..a29ae632651 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.cs.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.cs.xlf @@ -17,6 +17,11 @@ Operace nebyla úspěšná. Text chyby se vytiskl do streamu chyb. Pokud chcete vrátit odpovídající FSharpDiagnostic, použijte EvalInteractionNonThrowing, EvalScriptNonThrowing nebo EvalExpressionNonThrowing. + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Zastavilo se kvůli chybě.\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.de.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.de.xlf index e75d448790d..917da0c6661 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.de.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.de.xlf @@ -17,6 +17,11 @@ Fehler beim Vorgang. Der Fehlertext wurde im Fehlerstream ausgegeben. Verwenden Sie "EvalInteractionNonThrowing", "EvalScriptNonThrowing" oder "EvalExpressionNonThrowing", um die entsprechende FSharpDiagnostic zurückzugeben. + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Aufgrund eines Fehlers beendet\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.es.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.es.xlf index 21655a4e010..7b3e5bf09fc 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.es.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.es.xlf @@ -17,6 +17,11 @@ Error en la operación. El texto del error se ha impreso en la secuencia de errores. Para devolver el valor FSharpDiagnostic correspondiente, use EvalInteractionNonThrowing, EvalScriptNonThrowing o EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Detenido debido a un error.\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.fr.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.fr.xlf index fc42cf0b812..0bc06bd4192 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.fr.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.fr.xlf @@ -17,6 +17,11 @@ Échec de l'opération. Le texte d'erreur est affiché dans le flux d'erreur. Pour retourner le FSharpDiagnostic correspondant, utilisez EvalInteractionNonThrowing, EvalScriptNonThrowing ou EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Arrêt en raison d'une erreur\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.it.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.it.xlf index de4f016ad9a..0d15711bcf7 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.it.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.it.xlf @@ -17,6 +17,11 @@ L'operazione non è riuscita. Il testo dell'errore è stato stampato nel flusso degli errori. Per restituire l'elemento FSharpDiagnostic corrispondente, usare EvalInteractionNonThrowing, EvalScriptNonThrowing o EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Interruzione a causa di un errore\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.ja.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.ja.xlf index 614ddf284ac..a4273abeb4d 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.ja.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.ja.xlf @@ -17,6 +17,11 @@ 操作に失敗しました。エラー テキストがエラー ストリームに出力されました。対応する FSharpDiagnostic を戻すには、EvalInteractionNonThrowing、EvalScriptNonThrowing、または EvalExpressionNonThrowing を使用します + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n エラーのため停止しました\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.ko.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.ko.xlf index 4f132496c00..1f6c29e1d95 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.ko.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.ko.xlf @@ -17,6 +17,11 @@ 작업이 실패했습니다. 오류 텍스트가 오류 스트림에 출력되었습니다. 해당 FSharpDiagnostic을 반환하려면 EvalInteractionNonThrowing, EvalScriptNonThrowing 또는 EvalExpressionNonThrowing을 사용하세요. + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n 오류 때문에 중지되었습니다.\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.pl.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.pl.xlf index 8806c4ace6e..2f9cd49331a 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.pl.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.pl.xlf @@ -17,6 +17,11 @@ Operacja nie powiodła się. Tekst błędu został umieszczony w strumieniu błędów. Aby zwrócić odpowiedni element FSharpDiagnostic, użyj elementu EvalInteractionNonThrowing, eEvalScriptNonThrowing lub EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Zatrzymano ze względu na błąd\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.pt-BR.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.pt-BR.xlf index c67ed4a0e70..15b0a2eb5e3 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.pt-BR.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.pt-BR.xlf @@ -17,6 +17,11 @@ Falha na operação. O texto do erro foi impresso no fluxo de erros. Para retornar o FSharpDiagnostic correspondente, use EvalInteractionNonThrowing, EvalScriptNonThrowing ou EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Interrompido devido a erro\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.ru.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.ru.xlf index efd1f831714..c3692fe864c 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.ru.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.ru.xlf @@ -17,6 +17,11 @@ Не удалось выполнить операцию. Текст ошибки был выведен в потоке ошибок. Чтобы вернуть соответствующие сведения FSharpDiagnostic, используйте EvalInteractionNonThrowing, EvalScriptNonThrowing или EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Остановлено из-за ошибки\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.tr.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.tr.xlf index 0aa1916e2de..07becdf7bfd 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.tr.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.tr.xlf @@ -17,6 +17,11 @@ İşlem başarısız oldu. Hata metni hata akışında yazdırıldı. İlgili FSharpDiagnostic'i döndürmek için EvalInteractionNonThrowing, EvalScriptNonThrowing veya EvalExpressionNonThrowing kullanın + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n Hata nedeniyle durduruldu\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hans.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hans.xlf index d183e5f2349..e3738fa7d23 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hans.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hans.xlf @@ -17,6 +17,11 @@ 操作失败。错误文本已在错误流中打印。若要返回相应的 FSharpDiagnostic,请使用 EvalInteractionNonThrowing、EvalScriptNonThrowing 或 EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n 已因出错而停止\n diff --git a/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hant.xlf b/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hant.xlf index ccb733230cb..47b8905757c 100644 --- a/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hant.xlf +++ b/src/fsharp/fsi/xlf/FSIstrings.txt.zh-Hant.xlf @@ -17,6 +17,11 @@ 作業失敗。錯誤文字已列印在錯誤串流中。若要傳回相對應的 FSharpDiagnostic,請使用 EvalInteractionNonThrowing、EvalScriptNonThrowing 或 EvalExpressionNonThrowing + + Execute analyzers (off by default) + Execute analyzers (off by default) + + Stopped due to error\n 已因錯誤而停止\n diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index 55479a3fff6..03246aca703 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -13,6 +13,11 @@ open FSharp.Compiler.CompilerConfig open FSharp.Compiler.Diagnostics open FSharp.Compiler.IO open FSharp.Compiler.Text +open FSharp.Compiler.NameResolution +open FSharp.Compiler.CheckExpressions +open FSharp.Compiler.CompilerImports +open FSharp.Compiler.TcGlobals +open FSharp.Compiler.TypedTree type FSharpAnalyzerTextChange = Range * string @@ -108,8 +113,79 @@ module FSharpAnalyzers = [ for analyzerPath in tcConfig.compilerToolPaths do if FileSystem.SafeExists(analyzerPath) then - yield! CreateAnalyzers (analyzerPath, m) ] - + yield! CreateAnalyzers (analyzerPath, m) + // TODO: give a warning here (or in CreateAnalyzers) + ] + + let RunAnalyzers(analyzers: FSharpAnalyzer list, tcConfig: TcConfig, tcImports: TcImports, tcGlobals: TcGlobals, tcCcu: CcuThunk, sourceFiles: string list, tcFileResults, tcEnvAtEnd: TcEnv) = + + let sourceTexts = [| for sourceFile in sourceFiles -> sourceFile, SourceText.readFile sourceFile tcConfig.inputCodePage |] + + let projectOptions = + { + ProjectFileName = "compile.fsproj" + ProjectId = None + SourceFiles = Array.ofList sourceFiles + ReferencedProjects = [| |] + OtherOptions = [| |] + IsIncompleteTypeCheckEnvironment = true + UseScriptResolutionRules = false + LoadTime = DateTime.MaxValue + OriginalLoadReferences = [] + UnresolvedReferences = None + Stamp = None + } + + let tcFileResults, _implFilesRev = + ([], tcFileResults) ||> List.mapFold (fun implFilesRev (a,b,c) -> + let implFilesRev2 = Option.toList b @ implFilesRev + (a, List.rev implFilesRev2, c), implFilesRev2) + + for (inp, implFileOpt, ccuSig) in tcFileResults do + + let parseResults = + FSharpParseFileResults(diagnostics = [||], + input = Some inp, + parseHadErrors = false, + dependencyFiles = [| |]) + + let checkResults = + FSharpCheckFileResults.Make + (inp.FileName, + "compile.fsproj", + tcConfig, + tcGlobals, + false, + None, + parseResults.ParseTree, + projectOptions, + [| |], + [| |], + [| |], + [| |], + true, + ccuSig, + tcCcu, + tcImports, + tcEnvAtEnd.AccessRights, + TcResolutions.Empty, + TcSymbolUses.Empty, + tcEnvAtEnd.NameEnv, + None, + implFileOpt, + [| |]) + + let ctxt = FSharpAnalyzerCheckFileContext(sourceTexts, checkResults, CancellationToken.None, tcConfig) + + for analyzer in analyzers do + let diagnostics = analyzer.OnCheckFile(ctxt) + for diag in diagnostics do + let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) + match diag.Severity with + | FSharpDiagnosticSeverity.Error -> errorR(exn) + | FSharpDiagnosticSeverity.Warning -> warning(exn) + | FSharpDiagnosticSeverity.Info -> warning(exn) + | FSharpDiagnosticSeverity.Hidden -> () #else diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index 2bb99624d8e..42ba700aecb 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -4,11 +4,14 @@ namespace FSharp.Compiler.CodeAnalysis open System open System.Threading +open FSharp.Compiler.CheckExpressions open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CompilerConfig +open FSharp.Compiler.CompilerImports open FSharp.Compiler.Diagnostics open FSharp.Compiler.Syntax open FSharp.Compiler.TcGlobals +open FSharp.Compiler.TypedTree open FSharp.Compiler.Text type FSharpAnalyzerTextChange = Range * string @@ -70,4 +73,6 @@ type public FSharpAnalyzer = default FixableDiagnosticIds: string[] module internal FSharpAnalyzers = + val CreateAnalyzers: analyzerPath: string * m: range -> FSharpAnalyzer list val ImportAnalyzers: tcConfig: TcConfig * m: range -> FSharpAnalyzer list + val RunAnalyzers: analyzers: FSharpAnalyzer list * tcConfig: TcConfig * tcImports: TcImports * tcGlobals: TcGlobals * tcCcu: CcuThunk * sourceFiles: string list * tcFileResults: (ParsedInput * TypedImplFile option * ModuleOrNamespaceType) list * tcEnvAtEnd: TcEnv -> unit diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 726561fc36e..549fbc731b4 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1272,6 +1272,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, member _.Analyzers = analyzers + member _.KeepAssemblyContents = keepAssemblyContents + member this.ContainsFile(filename: string) = (this.TryGetSlotOfFileName filename).IsSome @@ -1295,12 +1297,12 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, sourceFiles: string list, commandLineArgs: string list, projectReferences, projectDirectory, - useScriptResolutionRules, keepAssemblyContents, + useScriptResolutionRules, keepAssemblyContentsRequestForChecker, keepAllBackgroundResolutions, maxTimeShareMilliseconds, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, - enablePartialTypeChecking: bool, + enablePartialTypeCheckingRequestForChecker: bool, dependencyProvider) = let useSimpleResolutionSwitch = "--simpleresolution" @@ -1393,6 +1395,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, dllReferences |> List.iter (fun dllReference -> tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text)) tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences + loadClosure.CompilerTools |> List.iter (fun compilerTool -> + tcConfigB.AddCompilerToolsByPath(compilerTool)) | None -> () let tcConfig = TcConfig.Create(tcConfigB, validate=true) @@ -1432,6 +1436,11 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) let analyzersRequireAssemblyContents = analyzers |> List.exists (fun analyzer -> analyzer.RequiresAssemblyContents) + + // partial type checking based on signatures alone gets disabled if any + // analyzer requires assembly contents + let enablePartialTypeChecking = enablePartialTypeCheckingRequestForChecker && not analyzersRequireAssemblyContents + let keepAssemblyContents = keepAssemblyContentsRequestForChecker || analyzersRequireAssemblyContents let builder = new IncrementalBuilder(tcGlobals, @@ -1446,7 +1455,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, niceNameGen, analyzers, resourceManager, sourceFilesNew, loadClosureOpt, - (keepAssemblyContents || analyzersRequireAssemblyContents), + keepAssemblyContents, keepAllBackgroundResolutions, maxTimeShareMilliseconds, keepAllBackgroundSymbolUses, diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 7b4aec85923..fe8cf257774 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -221,6 +221,10 @@ type internal IncrementalBuilder = /// Get the active analyzers for the project member Analyzers: FSharpAnalyzer list + + /// True if keeping assembly contents, either for entire checker of because an analyzer in this builder + /// requires it. + member KeepAssemblyContents: bool /// Create the incremental builder static member TryCreateIncrementalBuilderForProjectOptions: @@ -234,14 +238,14 @@ type internal IncrementalBuilder = projectReferences: IProjectReference list * projectDirectory:string * useScriptResolutionRules:bool * - keepAssemblyContents: bool * + keepAssemblyContentsRequestForChecker: bool * keepAllBackgroundResolutions: bool * maxTimeShareMilliseconds: int64 * tryGetMetadataSnapshot: ILBinaryReader.ILReaderTryGetMetadataSnapshot * suggestNamesForErrors: bool * keepAllBackgroundSymbolUses: bool * enableBackgroundItemKeyStoreAndSemanticClassification: bool * - enablePartialTypeChecking: bool * + enablePartialTypeCheckingRequestForChecker: bool * dependencyProvider: DependencyProvider option -> Cancellable diff --git a/src/fsharp/service/ServiceLexing.fs b/src/fsharp/service/ServiceLexing.fs index 22bb70e492c..8d47dca6fff 100755 --- a/src/fsharp/service/ServiceLexing.fs +++ b/src/fsharp/service/ServiceLexing.fs @@ -873,6 +873,7 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, // These are for script (.fsx and .fsscript) files. | true, "r" | true, "reference" + | true, "compilertool" | true, "I" | true, "load" | true, "time" diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 731fa80cabd..286376328d7 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -206,7 +206,7 @@ type ScriptClosureCacheToken() = interface LockToken // There is only one instance of this type, held in FSharpChecker -type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyContents, keepAllBackgroundResolutions, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking) as self = +type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyContentsRequestForChecker, keepAllBackgroundResolutions, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking) as self = // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.reactor: The one and only Reactor let reactor = Reactor.Singleton let beforeFileChecked = Event() @@ -269,7 +269,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions (ctok, legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, Array.toList options.SourceFiles, Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory, - options.UseScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions, FSharpCheckerResultsSettings.maxTimeShareMilliseconds, + options.UseScriptResolutionRules, keepAssemblyContentsRequestForChecker, keepAllBackgroundResolutions, FSharpCheckerResultsSettings.maxTimeShareMilliseconds, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking, @@ -512,7 +512,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC Array.ofList tcDependencyFiles, creationDiags, parseResults.Diagnostics, - keepAssemblyContents, + builder.KeepAssemblyContents, suggestNamesForErrors) let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, Array.ofList builder.SourceFiles, options.UseScriptResolutionRules) reactor.SetPreferredUILang tcConfig.preferredUiLang @@ -587,7 +587,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC reactor.CancelBackgroundOp() // cancel the background work, since we will start new work after we're done let! builderOpt,creationDiags = execWithReactorAsync (fun ctok -> getOrCreateBuilder (ctok, options, userOpName)) match builderOpt with - | None -> return FSharpCheckFileAnswer.Succeeded (FSharpCheckFileResults.MakeEmpty(filename, creationDiags, keepAssemblyContents)) + | None -> return FSharpCheckFileAnswer.Succeeded (FSharpCheckFileResults.MakeEmpty(filename, creationDiags, true)) | Some builder -> // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date let cachedResults = bc.GetCachedCheckFileResult(builder, filename, sourceText, options) @@ -736,7 +736,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match builderOpt with | None -> let parseResults = FSharpParseFileResults(creationDiags, None, true, [| |]) - let typedResults = FSharpCheckFileResults.MakeEmpty(filename, creationDiags, keepAssemblyContents) + let typedResults = FSharpCheckFileResults.MakeEmpty(filename, creationDiags, true) return (parseResults, typedResults) | Some builder -> let! (parseTreeOpt, _, _, parseDiags) = builder.GetParseResultsForFile (ctok, filename) @@ -772,7 +772,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC creationDiags, parseResults.Diagnostics, tcErrors, - keepAssemblyContents, + builder.KeepAssemblyContents, Option.get latestCcuSigForFile, tcState.Ccu, tcProj.TcImports, @@ -832,7 +832,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let! builderOpt,creationDiags = getOrCreateBuilder (ctok, options, userOpName) match builderOpt with | None -> - return FSharpCheckProjectResults (options.ProjectFileName, None, keepAssemblyContents, creationDiags, None) + return FSharpCheckProjectResults (options.ProjectFileName, None, true, creationDiags, None) | Some builder -> let! (tcProj, ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt) = builder.GetFullCheckResultsAndImplementationsForProject(ctok) let errorOptions = tcProj.TcConfig.errorSeverityOptions @@ -847,7 +847,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let tcErrors = tcInfo.TcErrors let tcDependencyFiles = tcInfo.tcDependencyFiles let errors = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (errorOptions, true, fileName, tcErrors, suggestNamesForErrors) |] - return FSharpCheckProjectResults (options.ProjectFileName, Some tcProj.TcConfig, keepAssemblyContents, errors, + return FSharpCheckProjectResults (options.ProjectFileName, Some tcProj.TcConfig, builder.KeepAssemblyContents, errors, Some(tcProj.TcGlobals, tcProj.TcImports, tcState.Ccu, tcState.CcuSig, tcSymbolUses, topAttribs, tcAssemblyDataOpt, ilAssemRef, tcEnvAtEnd.AccessRights, tcAssemblyExprOpt, Array.ofList tcDependencyFiles, @@ -1059,7 +1059,12 @@ type FSharpChecker(legacyReferenceResolver, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking) = - let backgroundCompiler = BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyContents, keepAllBackgroundResolutions, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking) + let backgroundCompiler = + BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyContents, + keepAllBackgroundResolutions, tryGetMetadataSnapshot, + suggestNamesForErrors, keepAllBackgroundSymbolUses, + enableBackgroundItemKeyStoreAndSemanticClassification, + enablePartialTypeChecking) static let globalInstance = lazy FSharpChecker.Create() @@ -1095,7 +1100,10 @@ type FSharpChecker(legacyReferenceResolver, if keepAssemblyContents && enablePartialTypeChecking then invalidArg "enablePartialTypeChecking" "'keepAssemblyContents' and 'enablePartialTypeChecking' cannot be both enabled." - new FSharpChecker(legacyReferenceResolver, projectCacheSizeReal,keepAssemblyContents, keepAllBackgroundResolutions, tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, enablePartialTypeChecking) + FSharpChecker(legacyReferenceResolver, projectCacheSizeReal, keepAssemblyContents, + keepAllBackgroundResolutions, tryGetMetadataSnapshot, suggestNamesForErrors, + keepAllBackgroundSymbolUses, enableBackgroundItemKeyStoreAndSemanticClassification, + enablePartialTypeChecking) member _.ReferenceResolver = legacyReferenceResolver diff --git a/tests/service/data/TestAnalyzer/Analyzer.fs b/tests/service/data/TestAnalyzer/Analyzer.fs index 5d99168a083..a73ed4a12a0 100644 --- a/tests/service/data/TestAnalyzer/Analyzer.fs +++ b/tests/service/data/TestAnalyzer/Analyzer.fs @@ -12,17 +12,19 @@ do() type MyAnalyzer(ctxt) = inherit FSharpAnalyzer(ctxt) - override this.OnCheckFile(fileCtxt, ct) = + override this.OnCheckFile(fileCtxt) = - let m = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 3 0) (Position.mkPos 3 80) - let m2 = Range.mkRange fileCtxt.ParseFileResults.FileName (Position.mkPos 6 0) (Position.mkPos 6 80) - let source = fileCtxt.GetFileSource(fileCtxt.ParseFileResults.FileName) + let fileName = fileCtxt.CheckerModel.ParseTree.Value.FileName + let m = Range.mkRange fileName (Position.mkPos 3 0) (Position.mkPos 3 80) + let m2 = Range.mkRange fileName (Position.mkPos 6 0) (Position.mkPos 6 80) + let source = fileCtxt.GetFileSource(fileName) let text = source.GetSubTextString(0,source.Length) [| if text.Contains("WIBBLE") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 6 until the magic word WIBBLE appears", 45, m2, "FA") if text.Contains("WAZZAM") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 3 until the magic word WAZZAM appears", 45, m, "FA") |] - override _.TryAdditionalToolTip(fileCtxt, pos, ct) = - Some [| TaggedText.tagText $"This thing is on line {pos.Line} in file {fileCtxt.ParseFileResults.FileName}" |] + override _.TryAdditionalToolTip(fileCtxt, pos) = + let fileName = fileCtxt.CheckerModel.ParseTree.Value.FileName + Some [| TaggedText.tagText $"This thing is on line {pos.Line} in file {fileName}" |] diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index f9a320ff63e..b1f9dc735f5 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -249,7 +249,7 @@ type internal FSharpCompletionProvider let documentation = List() let collector = RoslynHelpers.CollectTaggedText documentation // mix main description and xmldoc by using one collector - XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, description, [| |]) + XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, collector, collector, collector, collector, description, [| |]) return CompletionDescription.Create(documentation.ToImmutableArray()) else return CompletionDescription.Empty diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs index d5c7ca1a2ec..863a7ab96a2 100644 --- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs +++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs @@ -335,8 +335,8 @@ type internal FSharpSignatureHelpProvider else None - let mainDescription, documentation, typeParameterMap, usage, exceptions = - ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() + let mainDescription, documentation, typeParameterMap, usage, exceptions, analyzerExtras = + ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() XmlDocumentation.BuildDataTipText( documentationBuilder, @@ -345,10 +345,11 @@ type internal FSharpSignatureHelpProvider typeParameterMap.Add, usage.Add, exceptions.Add, + analyzerExtras.Add, tooltip, [| |]) - let fsharpDocs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] + let fsharpDocs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions; analyzerExtras] let docs = ResizeArray() fsharpDocs |> Seq.iter (RoslynHelpers.CollectTaggedText docs) diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index 2ef37669771..e1f54c0d7fd 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -300,20 +300,29 @@ module internal XmlDocumentation = let private AddSeparator (collector: ITaggedTextCollector) = if not collector.IsEmpty then EnsureHardLine collector - collector.Add (tagText "-------------") + collector.Add (tagText "—————————————————") AppendHardLine collector /// Build a data tip text string with xml comments injected. let BuildTipText(documentationProvider:IDocumentationBuilder, dataTipText: ToolTipElement list, - extras: FSharp.Compiler.Text.TaggedText[][], - textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, - showText, showExceptions, showParameters) = + analyzerExtras: FSharp.Compiler.Text.TaggedText[][], + textCollector, + xmlCollector, + typeParameterMapCollector, + usageCollector, + exnCollector, + analyzerExtrasCollector, + showText, + showExceptions, + showParameters, + showAnalyzerExtras) = let textCollector: ITaggedTextCollector = TextSanitizingCollector(textCollector, lineLimit = 45) :> _ let xmlCollector: ITaggedTextCollector = TextSanitizingCollector(xmlCollector, lineLimit = 45) :> _ let typeParameterMapCollector: ITaggedTextCollector = TextSanitizingCollector(typeParameterMapCollector, lineLimit = 6) :> _ let exnCollector: ITaggedTextCollector = TextSanitizingCollector(exnCollector, lineLimit = 45) :> _ let usageCollector: ITaggedTextCollector = TextSanitizingCollector(usageCollector, lineLimit = 45) :> _ + let analyzerExtrasCollector: ITaggedTextCollector = TextSanitizingCollector(analyzerExtrasCollector, lineLimit = 45) :> _ let addSeparatorIfNecessary add = if add then @@ -377,19 +386,21 @@ module internal XmlDocumentation = true List.fold Process false dataTipText |> ignore - for extra in extras do - AppendHardLine textCollector - extra |> Seq.iter textCollector.Add + if showAnalyzerExtras then + for extra in analyzerExtras do + AppendHardLine analyzerExtrasCollector + extra |> Seq.iter analyzerExtrasCollector.Add - let BuildDataTipText(documentationProvider, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, ToolTipText(dataTipText), extras: TaggedText[][]) = - BuildTipText(documentationProvider, dataTipText, extras, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, true, true, false) + let BuildDataTipText(documentationProvider, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, analyzerExtrasCollector, ToolTipText(dataTipText), analyzerExtras: TaggedText[][]) = + BuildTipText(documentationProvider, dataTipText, analyzerExtras, textCollector, xmlCollector, typeParameterMapCollector, usageCollector, exnCollector, analyzerExtrasCollector, true, true, false, true) let BuildMethodOverloadTipText(documentationProvider, textCollector, xmlCollector, ToolTipText(dataTipText), showParams) = - BuildTipText(documentationProvider, dataTipText, [| |], textCollector, xmlCollector, xmlCollector, ignore, ignore, false, false, showParams) + BuildTipText(documentationProvider, dataTipText, [| |], textCollector, xmlCollector, xmlCollector, ignore, ignore, ignore, false, false, false, showParams) let BuildMethodParamText(documentationProvider, xmlCollector, xml, paramName) = AppendXmlComment(documentationProvider, TextSanitizingCollector(xmlCollector), TextSanitizingCollector(xmlCollector), xml, false, true, Some paramName) let documentationBuilderCache = ConditionalWeakTable() + let CreateDocumentationBuilder(xmlIndexService: IVsXMLMemberIndexService) = documentationBuilderCache.GetValue(xmlIndexService,(fun _ -> Provider(xmlIndexService) :> IDocumentationBuilder)) \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs index eb3426f6734..a1455cb922a 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs @@ -9,7 +9,9 @@ open Microsoft.CodeAnalysis open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Text.Range open FSharp.Compiler.Text +open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop +open Microsoft.VisualStudio.ComponentModelHost type internal QuickInfoNavigation ( @@ -65,3 +67,15 @@ type internal QuickInfoNavigation | Signature, Implementation -> return! gtd.NavigateToSymbolDeclarationAsync(targetDoc, targetSource, range, statusBar) } |> Async.Ignore |> Async.StartImmediate + + member _.NavigateToUri (uri: System.Uri) = + asyncMaybe { + let componentModel = ServiceProvider.GlobalProvider.GetService() + let navigationService = componentModel.GetService() + if navigationService <> null then + let _hr, _ppFrame = navigationService.Navigate(uri.ToString(), 0u) + + //if not navigationSucceeded then + // statusBar.TempMessage (SR.CannotNavigateUnknown()) + () + } |> Async.Ignore |> Async.StartImmediate diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 1101251fbe4..60c989907aa 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -27,7 +27,7 @@ open FSharp.Compiler.Tokenization type internal QuickInfo = { StructuredText: ToolTipText - Extras: TaggedText[][] + AnalyzerExtras: TaggedText[][] Span: TextSpan Symbol: FSharpSymbol option SymbolKind: LexerSymbolKind } @@ -69,9 +69,9 @@ module internal FSharpQuickInfo = (declRange.StartLine, extLexerSymbol.Ident.idRange.EndColumn, extLineText, extLexerSymbol.FullIsland, FSharpTokenTag.IDENT) let fcsPos = Position.mkPos declRange.StartLine (extLexerSymbol.Ident.idRange.EndColumn-1) - let! extExtras = checker.GetAdditionalAnalyzerToolTips(extParseResults, extCheckFileResults, extSourceText.ToFSharpSourceText(), options=extProjectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync - let extExtras = extExtras |> Array.filter (fun arr -> arr.Length <> 0) - match extQuickInfoText, extExtras with + let! extAnalyzerExtras = checker.GetAdditionalAnalyzerToolTips(extParseResults, extCheckFileResults, extSourceText.ToFSharpSourceText(), options=extProjectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync + let extAnalyzerExtras = extAnalyzerExtras |> Array.filter (fun arr -> arr.Length <> 0) + match extQuickInfoText, extAnalyzerExtras with | ToolTipText [], [| |] | ToolTipText [ToolTipElement.None], [| |] -> return! None | _ -> @@ -80,7 +80,7 @@ module internal FSharpQuickInfo = let! span = RoslynHelpers.TryFSharpRangeToTextSpan (extSourceText, extLexerSymbol.Range) return { StructuredText = extQuickInfoText - Extras = extExtras + AnalyzerExtras = extAnalyzerExtras Span = span Symbol = Some extSymbolUse.Symbol SymbolKind = extLexerSymbol.Kind } @@ -124,7 +124,7 @@ module internal FSharpQuickInfo = | _ -> let! targetTextSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, lexerSymbol.Range) return { StructuredText = targetQuickInfo - Extras = extras + AnalyzerExtras = extras Span = targetTextSpan Symbol = symbol SymbolKind = lexerSymbol.Kind } @@ -207,16 +207,16 @@ type internal FSharpAsyncQuickInfoSource let! symbolUse = checkFileResults.GetSymbolUseAtLocation (textLineNumber, symbol.Ident.idRange.EndColumn, textLineString, symbol.FullIsland) let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan (sourceText, symbol.Range) return { StructuredText = res - Extras = extras + AnalyzerExtras = extras Span = symbolSpan Symbol = Some symbolUse.Symbol SymbolKind = symbol.Kind } } static member BuildSingleQuickInfoItem (documentationBuilder:IDocumentationBuilder) (quickInfo:QuickInfo) = - let mainDescription, documentation, typeParameterMap, usage, exceptions = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, documentation.Add, typeParameterMap.Add, usage.Add, exceptions.Add, quickInfo.StructuredText, quickInfo.Extras) - let docs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] + let mainDescription, documentation, typeParameterMap, usage, exceptions, analyzerExtras = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() + XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, documentation.Add, typeParameterMap.Add, usage.Add, exceptions.Add, analyzerExtras.Add, quickInfo.StructuredText, quickInfo.AnalyzerExtras) + let docs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions; analyzerExtras] (mainDescription, docs) interface IAsyncQuickInfoSource with @@ -249,9 +249,9 @@ type internal FSharpAsyncQuickInfoSource return QuickInfoItem(span, content) | Some sigQuickInfo, Some targetQuickInfo -> - let mainDescription, targetDocumentation, sigDocumentation, typeParameterMap, exceptions, usage = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() - XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, sigQuickInfo.StructuredText, sigQuickInfo.Extras) - XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, targetQuickInfo.StructuredText, targetQuickInfo.Extras) + let mainDescription, targetDocumentation, sigDocumentation, typeParameterMap, exceptions, usage, analyzerExtras = ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray(), ResizeArray() + XmlDocumentation.BuildDataTipText(documentationBuilder, ignore, sigDocumentation.Add, ignore, ignore, ignore, ignore, sigQuickInfo.StructuredText, sigQuickInfo.AnalyzerExtras) + XmlDocumentation.BuildDataTipText(documentationBuilder, mainDescription.Add, targetDocumentation.Add, typeParameterMap.Add, exceptions.Add, usage.Add, analyzerExtras.Add, targetQuickInfo.StructuredText, targetQuickInfo.AnalyzerExtras) // get whitespace nomalized documentation text let getText (tts: seq) = let text = @@ -269,9 +269,9 @@ type internal FSharpAsyncQuickInfoSource | Some implText, Some sigText when implText.Equals (sigText, StringComparison.OrdinalIgnoreCase) -> yield! sigDocumentation | Some _ , Some _ -> - yield! RoslynHelpers.joinWithLineBreaks [ sigDocumentation; [ TaggedText.tagText "-------------" ]; targetDocumentation ] + yield! RoslynHelpers.joinWithLineBreaks [ sigDocumentation; [ TaggedText.tagText "—————————————————"]; targetDocumentation ] ] |> ResizeArray - let docs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions] + let docs = RoslynHelpers.joinWithLineBreaks [documentation; typeParameterMap; usage; exceptions; analyzerExtras] let imageId = Tokenizer.GetImageIdForSymbol(targetQuickInfo.Symbol, targetQuickInfo.SymbolKind) let navigation = QuickInfoNavigation(statusBar, checkerProvider.Checker, projectInfoManager, document, symbolUseRange) let content = QuickInfoViewProvider.provideContent(imageId, mainDescription, docs, navigation) diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs index abcc6bde066..475de402d61 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Views.fs @@ -77,6 +77,10 @@ module internal QuickInfoViewProvider = flushRuns() let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateTo nav.Range) currentContainerItems.Add(navigableTextRun :> obj) + | :? WebLinkTaggedText as nav -> + flushRuns() + let navigableTextRun = NavigableTextRun(classificationTag, item.Text, fun () -> navigation.NavigateToUri nav.Uri) + currentContainerItems.Add(navigableTextRun :> obj) | _ when item.Tag = TextTag.LineBreak -> flushRuns() // preserve succesive linebreaks From c4b50ccd604d65926b8d828786291335d9727f97 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 16 Feb 2021 21:38:18 +0000 Subject: [PATCH 09/31] update baseline --- .../SurfaceArea.netstandard.fs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 7612ee2d41c..5ede8ba2604 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1355,29 +1355,25 @@ FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean RequiresAssemblyContents FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean get_RequiresAssemblyContents() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext Context FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext get_Context() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckFile(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, System.Threading.CancellationToken) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckProject(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext, System.Threading.CancellationToken) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]] TryAdditionalToolTip(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Text.Position, System.Threading.CancellationToken) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Text.Range,System.String][]] TryCodeFix(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Diagnostics.FSharpDiagnostic[], System.Threading.CancellationToken) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckFile(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckProject(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]] TryAdditionalToolTip(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Text.Position) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Text.Range,System.String][]] TryCodeFix(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Diagnostics.FSharpDiagnostic[]) FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] FixableDiagnosticIds FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] get_FixableDiagnosticIds() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Void .ctor(FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext) FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckFileResults -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckFileResults() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpParseFileResults ParseFileResults -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpParseFileResults get_ParseFileResults() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions get_ProjectOptions() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckerModel +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckerModel() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.String FileName -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.String get_FileName() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.Threading.CancellationToken CancellationToken +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults CheckProjectResults -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults get_CheckProjectResults() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions get_ProjectOptions() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults CheckerModel +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults get_CheckerModel() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: System.Threading.CancellationToken CancellationToken +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults Item FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_Item() @@ -1426,6 +1422,8 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FShar FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpDisplayContext] GetDisplayContextForPos(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpImplementationFileContents] ImplementationFile FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpImplementationFileContents] get_ImplementationFile() +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.ParsedInput] ParseTree +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.ParsedInput] get_ParseTree() FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpSymbolUse]] GetMethodsAsSymbols(Int32, Int32, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.String] GetF1Keyword(Int32, Int32, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: System.Collections.Generic.IEnumerable`1[FSharp.Compiler.CodeAnalysis.FSharpSymbolUse] GetAllUsesOfAllSymbolsInFile(Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken]) @@ -1565,6 +1563,8 @@ FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String[] SourceFiles FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String[] get_SourceFiles() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Void .ctor(System.String[], Microsoft.FSharp.Collections.FSharpList`1[System.String], FSharp.Compiler.Diagnostics.FSharpDiagnosticOptions, Boolean, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Boolean, Boolean) FSharp.Compiler.CodeAnalysis.FSharpProjectContext +FSharp.Compiler.CodeAnalysis.FSharpProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions +FSharp.Compiler.CodeAnalysis.FSharpProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions get_ProjectOptions() FSharp.Compiler.CodeAnalysis.FSharpProjectContext: FSharp.Compiler.Symbols.FSharpAccessibilityRights AccessibilityRights FSharp.Compiler.CodeAnalysis.FSharpProjectContext: FSharp.Compiler.Symbols.FSharpAccessibilityRights get_AccessibilityRights() FSharp.Compiler.CodeAnalysis.FSharpProjectContext: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Symbols.FSharpAssembly] GetReferencedAssemblies() @@ -8231,6 +8231,7 @@ FSharp.Compiler.Text.Line: Int32 toZ(Int32) FSharp.Compiler.Text.NavigableTaggedText FSharp.Compiler.Text.NavigableTaggedText: FSharp.Compiler.Text.Range Range FSharp.Compiler.Text.NavigableTaggedText: FSharp.Compiler.Text.Range get_Range() +FSharp.Compiler.Text.NavigableTaggedText: Void .ctor(FSharp.Compiler.Text.TaggedText, FSharp.Compiler.Text.Range) FSharp.Compiler.Text.Position FSharp.Compiler.Text.Position: Boolean Equals(System.Object) FSharp.Compiler.Text.Position: Int32 Column @@ -8511,6 +8512,10 @@ FSharp.Compiler.Text.TextTag: Int32 GetHashCode(System.Collections.IEqualityComp FSharp.Compiler.Text.TextTag: Int32 Tag FSharp.Compiler.Text.TextTag: Int32 get_Tag() FSharp.Compiler.Text.TextTag: System.String ToString() +FSharp.Compiler.Text.WebLinkTaggedText +FSharp.Compiler.Text.WebLinkTaggedText: System.Uri Uri +FSharp.Compiler.Text.WebLinkTaggedText: System.Uri get_Uri() +FSharp.Compiler.Text.WebLinkTaggedText: Void .ctor(FSharp.Compiler.Text.TaggedText, System.Uri) FSharp.Compiler.Tokenization.FSharpKeywords FSharp.Compiler.Tokenization.FSharpKeywords: Boolean DoesIdentifierNeedQuotation(System.String) FSharp.Compiler.Tokenization.FSharpKeywords: Microsoft.FSharp.Collections.FSharpList`1[System.String] KeywordNames From d134f4c3ff3123378f74b1930e971c0570ba78cc Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 01:10:23 +0000 Subject: [PATCH 10/31] fix issues with .NET core scripting references in editing --- src/fsharp/CompilerConfig.fs | 149 ++++++++++++++++------------------ src/fsharp/CompilerConfig.fsi | 11 +-- src/fsharp/CompilerImports.fs | 2 +- src/fsharp/CompilerOptions.fs | 8 +- src/fsharp/FxResolver.fs | 149 ++++++++++++++++++++++------------ src/fsharp/ScriptClosure.fs | 44 +++++----- src/fsharp/fsc.fs | 23 +++--- src/fsharp/fsi/fsi.fs | 2 +- src/fsharp/service/service.fs | 16 +++- 9 files changed, 230 insertions(+), 174 deletions(-) diff --git a/src/fsharp/CompilerConfig.fs b/src/fsharp/CompilerConfig.fs index 05eb55d2df2..955b4ce3ed2 100644 --- a/src/fsharp/CompilerConfig.fs +++ b/src/fsharp/CompilerConfig.fs @@ -466,13 +466,13 @@ type TcConfigBuilder = /// When false FSI will lock referenced assemblies requiring process restart, false = disable Shadow Copy false (*default*) mutable shadowCopyReferences: bool mutable useSdkRefs: bool - mutable fxResolver: FxResolver + mutable fxResolver: FxResolver option /// specify the error range for FxResolver - mutable rangeForErrors: range + rangeForErrors: range /// Override the SDK directory used by FxResolver, used for FCS only - mutable sdkDirOverride: string option + sdkDirOverride: string option /// A function to call to try to get an object that acts as a snapshot of the metadata section of a .NET binary, /// and from which we can read the metadata. Only used when metadataOnly=true. @@ -487,19 +487,50 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion } - static member Initial = + + // Directories to start probing in + // Algorithm: + // Search for native libraries using: + // 1. Include directories + // 2. compilerToolPath directories + // 3. reference dll's + // 4. The implicit include directory + // + // NOTE: it is important this is a delayed IEnumerable sequence. It is recomputed + // each time a resolution happens and additional paths may be added as a result. + member tcConfigB.GetNativeProbingRoots () = + seq { + yield! tcConfigB.includes + yield! tcConfigB.compilerToolPaths + yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) + yield tcConfigB.implicitIncludeDir + } + |> Seq.distinct + + static member CreateNew(legacyReferenceResolver, + defaultFSharpBinariesDir, + reduceMemoryUsage, + implicitIncludeDir, + isInteractive, + isInvalidationSupported, + defaultCopyFSharpCore, + tryGetMetadataSnapshot, + sdkDirOverride, + rangeForErrors) = + + if (String.IsNullOrEmpty defaultFSharpBinariesDir) then + failwith "Expected a valid defaultFSharpBinariesDir" + + // These are all default values, many can be overridden using the command line switch { - primaryAssembly = PrimaryAssembly.Mscorlib // default value, can be overridden using the command line switch + primaryAssembly = PrimaryAssembly.Mscorlib light = None noFeedback = false stackReserveSize = None conditionalCompilationDefines = [] - implicitIncludeDir = String.Empty openDebugInformationForLaterStaticLinking = false - defaultFSharpBinariesDir = String.Empty compilingFslib = false useIncrementalBuilder = false - useFsiAuxLib = false implicitOpens = [] includes = [] resolutionEnvironment = LegacyResolutionEnvironment.EditingOrCompilation false @@ -514,7 +545,6 @@ type TcConfigBuilder = errorSeverityOptions = FSharpDiagnosticOptions.Default embedResources = [] inputCodePage = None - reduceMemoryUsage = ReduceMemoryFlag.Yes // always gets set explicitly subsystemVersion = 4, 0 // per spec for 357994 useHighEntropyVA = false mlCompatibility = false @@ -576,7 +606,6 @@ type TcConfigBuilder = win32manifest = "" includewin32manifest = true linkResources = [] - legacyReferenceResolver = null showFullPaths = false errorStyle = ErrorStyle.DefaultErrors @@ -609,86 +638,46 @@ type TcConfigBuilder = pause = false alwaysCallVirt = true noDebugData = false - isInteractive = false - isInvalidationSupported = false emitDebugInfoInQuotations = false exename = None - copyFSharpCore = CopyFSharpCoreFlag.No shadowCopyReferences = false useSdkRefs = true - fxResolver = Unchecked.defaultof - rangeForErrors = range0 - sdkDirOverride = None - tryGetMetadataSnapshot = (fun _ -> None) + fxResolver = None internalTestSpanStackReferring = false noConditionalErasure = false pathMap = PathMap.empty langVersion = LanguageVersion("default") + implicitIncludeDir = implicitIncludeDir + defaultFSharpBinariesDir = defaultFSharpBinariesDir + reduceMemoryUsage = reduceMemoryUsage + legacyReferenceResolver = legacyReferenceResolver + isInteractive = isInteractive + isInvalidationSupported = isInvalidationSupported + copyFSharpCore = defaultCopyFSharpCore + tryGetMetadataSnapshot = tryGetMetadataSnapshot + useFsiAuxLib = isInteractive + rangeForErrors = rangeForErrors + sdkDirOverride = sdkDirOverride } - - // Directories to start probing in - // Algorithm: - // Search for native libraries using: - // 1. Include directories - // 2. compilerToolPath directories - // 3. reference dll's - // 4. The implicit include directory - // - // NOTE: it is important this is a delayed IEnumerable sequence. It is recomputed - // each time a resolution happens and additional paths may be added as a result. - member tcConfigB.GetNativeProbingRoots () = - seq { - yield! tcConfigB.includes - yield! tcConfigB.compilerToolPaths - yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) - yield tcConfigB.implicitIncludeDir - } - |> Seq.distinct - - static member CreateNew(legacyReferenceResolver, - defaultFSharpBinariesDir, - reduceMemoryUsage, - implicitIncludeDir, - isInteractive, - isInvalidationSupported, - defaultCopyFSharpCore, - tryGetMetadataSnapshot, - sdkDirOverride, - rangeForErrors) = - - Debug.Assert(FileSystem.IsPathRootedShim implicitIncludeDir, sprintf "implicitIncludeDir should be absolute: '%s'" implicitIncludeDir) - - if (String.IsNullOrEmpty defaultFSharpBinariesDir) then - failwith "Expected a valid defaultFSharpBinariesDir" - - let tcConfigBuilder = - { TcConfigBuilder.Initial with - implicitIncludeDir = implicitIncludeDir - defaultFSharpBinariesDir = defaultFSharpBinariesDir - reduceMemoryUsage = reduceMemoryUsage - legacyReferenceResolver = legacyReferenceResolver - isInteractive = isInteractive - isInvalidationSupported = isInvalidationSupported - copyFSharpCore = defaultCopyFSharpCore - tryGetMetadataSnapshot = tryGetMetadataSnapshot - useFsiAuxLib = isInteractive - rangeForErrors = rangeForErrors - sdkDirOverride = sdkDirOverride - } - tcConfigBuilder - + member tcConfigB.FxResolver = - let resolver = - lazy (let assumeDotNetFramework = Some (tcConfigB.primaryAssembly = PrimaryAssembly.Mscorlib) - FxResolver(assumeDotNetFramework, tcConfigB.implicitIncludeDir, rangeForErrors=tcConfigB.rangeForErrors, useSdkRefs=tcConfigB.useSdkRefs, isInteractive=tcConfigB.isInteractive, sdkDirOverride=tcConfigB.sdkDirOverride)) - - if tcConfigB.fxResolver = Unchecked.defaultof then - lock tcConfigB (fun () -> - if tcConfigB.fxResolver = Unchecked.defaultof then - tcConfigB.fxResolver <- resolver.Force() - ) - - tcConfigB.fxResolver + // We compute the FxResolver on-demand. It depends on some configuration parameters + // which may be later adjusted. + match tcConfigB.fxResolver with + | None -> + let useDotNetFramework = (tcConfigB.primaryAssembly = PrimaryAssembly.Mscorlib) + let fxResolver = FxResolver(useDotNetFramework, tcConfigB.implicitIncludeDir, rangeForErrors=tcConfigB.rangeForErrors, useSdkRefs=tcConfigB.useSdkRefs, isInteractive=tcConfigB.isInteractive, sdkDirOverride=tcConfigB.sdkDirOverride) + tcConfigB.fxResolver <- Some fxResolver + fxResolver + | Some fxResolver -> fxResolver + + member tcConfigB.SetPrimaryAssembly primaryAssembly = + tcConfigB.primaryAssembly <- primaryAssembly + tcConfigB.fxResolver <- None // this needs to be recreated when the primary assembly changes + + member tcConfigB.SetUseSdkRefs useSdkRefs = + tcConfigB.useSdkRefs <- useSdkRefs + tcConfigB.fxResolver <- None // this needs to be recreated when the primary assembly changes member tcConfigB.ResolveSourceFile(m, nm, pathLoadedFrom) = use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parameter diff --git a/src/fsharp/CompilerConfig.fsi b/src/fsharp/CompilerConfig.fsi index a14d8f398da..58ce21a082b 100644 --- a/src/fsharp/CompilerConfig.fsi +++ b/src/fsharp/CompilerConfig.fsi @@ -254,9 +254,9 @@ type TcConfigBuilder = mutable copyFSharpCore: CopyFSharpCoreFlag mutable shadowCopyReferences: bool mutable useSdkRefs: bool - mutable fxResolver: FxResolver - mutable rangeForErrors: range - mutable sdkDirOverride: string option + mutable fxResolver: FxResolver option + rangeForErrors: range + sdkDirOverride: string option /// A function to call to try to get an object that acts as a snapshot of the metadata section of a .NET binary, /// and from which we can read the metadata. Only used when metadataOnly=true. @@ -273,8 +273,6 @@ type TcConfigBuilder = mutable langVersion : LanguageVersion } - static member Initial: TcConfigBuilder - static member CreateNew: legacyReferenceResolver: LegacyReferenceResolver * defaultFSharpBinariesDir: string * @@ -319,6 +317,9 @@ type TcConfigBuilder = member FxResolver: FxResolver + member SetUseSdkRefs: useSdkRefs: bool -> unit + + member SetPrimaryAssembly: primaryAssembly: PrimaryAssembly -> unit /// Immutable TcConfig, modifications are made via a TcConfigBuilder [] diff --git a/src/fsharp/CompilerImports.fs b/src/fsharp/CompilerImports.fs index a397e7fdae5..70fca6f6f6d 100644 --- a/src/fsharp/CompilerImports.fs +++ b/src/fsharp/CompilerImports.fs @@ -553,7 +553,7 @@ type TcAssemblyResolutions(tcConfig: TcConfig, results: AssemblyResolution list, if found then yield asm if tcConfig.framework then - let references, _useDotNetFramework = tcConfig.FxResolver.GetDefaultReferences(tcConfig.useFsiAuxLib, assumeDotNetFramework) + let references, _useDotNetFramework = tcConfig.FxResolver.GetDefaultReferences(tcConfig.useFsiAuxLib) for s in references do yield AssemblyReference(rangeStartup, (if s.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) then s else s+".dll"), None) diff --git a/src/fsharp/CompilerOptions.fs b/src/fsharp/CompilerOptions.fs index 56652d33e4f..41fb657d69b 100644 --- a/src/fsharp/CompilerOptions.fs +++ b/src/fsharp/CompilerOptions.fs @@ -455,7 +455,8 @@ let subSystemVersionSwitch (tcConfigB: TcConfigBuilder) (text: string) = | _ -> fail() let SetUseSdkSwitch (tcConfigB: TcConfigBuilder) switch = - tcConfigB.useSdkRefs <- (switch = OptionSwitch.On) + let useSdkRefs = (switch = OptionSwitch.On) + tcConfigB.SetUseSdkRefs useSdkRefs let (++) x s = x @ [s] @@ -904,8 +905,8 @@ let cliRootFlag (_tcConfigB: TcConfigBuilder) = OptionString (fun _ -> ()), Some(DeprecatedCommandLineOptionFull(FSComp.SR.optsClirootDeprecatedMsg(), rangeCmdArgs)), Some(FSComp.SR.optsClirootDescription())) -let SetTargetProfile tcConfigB v = - tcConfigB.primaryAssembly <- +let SetTargetProfile (tcConfigB: TcConfigBuilder) v = + let primaryAssembly = match v with // Indicates we assume "mscorlib.dll", i.e .NET Framework, Mono and Profile 47 | "mscorlib" -> PrimaryAssembly.Mscorlib @@ -914,6 +915,7 @@ let SetTargetProfile tcConfigB v = // Indicates we assume "netstandard.dll", i.e .NET Standard 2.0 and above | "netstandard" -> PrimaryAssembly.NetStandard | _ -> error(Error(FSComp.SR.optsInvalidTargetProfile v, rangeCmdArgs)) + tcConfigB.SetPrimaryAssembly primaryAssembly let advancedFlagsBoth tcConfigB = [ diff --git a/src/fsharp/FxResolver.fs b/src/fsharp/FxResolver.fs index 31e8307c2fb..d12505e8bb9 100644 --- a/src/fsharp/FxResolver.fs +++ b/src/fsharp/FxResolver.fs @@ -25,7 +25,7 @@ open FSharp.Compiler.Text.Range /// - out-of-project sources editing /// - default references for fsc.exe /// - default references for fsi.exe -type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, useSdkRefs: bool, isInteractive: bool, rangeForErrors: range, sdkDirOverride: string option) = +type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdkRefs: bool, isInteractive: bool, rangeForErrors: range, sdkDirOverride: string option) = static let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) @@ -138,22 +138,32 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, with err -> Result.Error (Error(FSComp.SR.scriptSdkNotDetermined(dotnetHostPath, projectDir, err.Message, 1), rangeForErrors)))) + // We need to make sure the warning gets replayed each time, despite the lazy computations + // To do this we pass it back as data and eventually replay it at the entry points to FxResolver. let tryGetDesiredDotNetSdkVersionForDirectory() = - // Make sure the warning gets replayed each time we call this match tryGetDesiredDotNetSdkVersionForDirectoryInfo() with - | Result.Ok res -> Some res - | Result.Error exn -> warning(exn); None - - /// Get the .NET Core SDK directory relevant to projectDir, used to infer the default target framework assemblies. - let tryGetSdkDir() = + | Result.Ok res -> Some res, [] + | Result.Error exn -> None, [exn] + + // This is used to replay the warnings generated in the function above. + // It should not be used under the lazy on-demand computations in this type, nor should the warnings be explicitly ignored + let replayWarnings (res, warnings: exn list) = + for exn in warnings do warning exn + res + + /// Compute the .NET Core SDK directory relevant to projectDir, used to infer the default target framework assemblies. + /// + /// On-demand because (a) some FxResolver are ephemeral (b) we want to avoid recomputation + let trySdkDir = + lazy // This path shouldn't be used with reflective processes assert not isInteractive match assumeDotNetFramework with - | Some true -> None - | _ when not useSdkRefs -> None + | true -> None, [] + | _ when not useSdkRefs -> None, [] | _ -> match sdkDirOverride with - | Some sdkDir -> Some sdkDir + | Some sdkDir -> Some sdkDir, [] | None -> let sdksDir = match getDotnetDirectory() with @@ -165,32 +175,36 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, match sdksDir with | Some sdksDir -> // Find the sdk version by running `dotnet --version` in the script/project location - let desiredSdkVer = tryGetDesiredDotNetSdkVersionForDirectory() + let desiredSdkVer, warnings = tryGetDesiredDotNetSdkVersionForDirectory() let sdkDir = DirectoryInfo(sdksDir).GetDirectories() - |> Array.filter (fun di -> di.Name |> Seq.forall (fun c -> Char.IsDigit(c) || c = '.')) // Filter to the version reported by `dotnet --version` in the location, if that succeeded - |> Array.filter (fun di -> match desiredSdkVer with None -> true | Some v -> di.Name.Contains(v)) + |> Array.filter (fun di -> match desiredSdkVer with None -> true | Some v -> di.Name = v) |> Array.sortBy (fun di -> di.FullName) |> Array.tryLast |> Option.map (fun di -> di.FullName) - sdkDir + sdkDir, warnings | _ -> - None + None, [] + + let tryGetSdkDir() = trySdkDir.Force() /// Get the framework implementation directory of the currently running process let getRunningImplementationAssemblyDir() = let filename = Path.GetDirectoryName(typeof.Assembly.Location) if String.IsNullOrWhiteSpace filename then getFSharpCompilerLocation() else filename - /// Get the framework implementation directory, either of the selected SDK or the currently running process as a backup - /// F# interactive/reflective scenarios use the implementation directory of the currently running process - let getImplementationAssemblyDir() = + // Compute the framework implementation directory, either of the selected SDK or the currently running process as a backup + // F# interactive/reflective scenarios use the implementation directory of the currently running process + // + // On-demand because (a) some FxResolver are ephemeral (b) we want to avoid recomputation + let implementationAssemblyDir = + lazy if isInteractive then - getRunningImplementationAssemblyDir() + getRunningImplementationAssemblyDir(), [] else - let sdkDir = tryGetSdkDir() + let sdkDir, warnings = tryGetSdkDir() match sdkDir with | Some dir -> let dotnetConfigFile = Path.Combine(dir, "dotnet.runtimeconfig.json") @@ -201,12 +215,14 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, let ver = dotnetConfig.[startPos..endPos-1] let path = Path.GetFullPath(Path.Combine(dir, "..", "..", "shared", "Microsoft.NETCore.App", ver)) if Directory.Exists(path) then - path + path, warnings else - getRunningImplementationAssemblyDir() + getRunningImplementationAssemblyDir(), warnings | None -> let path = getRunningImplementationAssemblyDir() - path + path, [] + + let getImplementationAssemblyDir() = implementationAssemblyDir.Force() let getFSharpCoreLibraryName = "FSharp.Core" @@ -220,10 +236,11 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, // Use the ValueTuple that is executing with the compiler if it is from System.ValueTuple // or the System.ValueTuple.dll that sits alongside the compiler. (Note we always ship one with the compiler) - let getSystemValueTupleImplementationReference () = - let probeFile = Path.Combine(getImplementationAssemblyDir(), "System.ValueTuple.dll") + let getSystemValueTupleImplementationReference() = + let implDir = getImplementationAssemblyDir() |> replayWarnings + let probeFile = Path.Combine(implDir, "System.ValueTuple.dll") if File.Exists(probeFile) then - Some probeFile + Some probeFile else try let asm = typeof>.Assembly @@ -235,7 +252,9 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, Some valueTuplePath else None - with _ -> None + with _ -> + // This is defensive coding, we don't expect this exception to happen + None // Algorithm: // use implementation location of obj type, on shared frameworks it will always be in: @@ -249,7 +268,10 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, // we will rely on the sdk-version match on the two paths to ensure that we get the product that ships with the // version of the runtime we are executing on // Use the reference assemblies for the highest netcoreapp tfm that we find in that location. - let tryGetNetCoreRefsPackDirectoryRoot() = + // + // On-demand because (a) some FxResolver are ephemeral (b) we want to avoid recomputation + let tryNetCoreRefsPackDirectoryRoot = + lazy try // Use the reference assemblies for the highest netcoreapp tfm that we find in that location that is // lower than or equal to the implementation version. @@ -259,7 +281,7 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, | true, v -> v | false, _ -> zeroVersion - let implDir = getImplementationAssemblyDir() + let implDir, warnings = getImplementationAssemblyDir() let version = computeVersion (DirectoryInfo(implDir).Name) let microsoftNETCoreAppRef = Path.Combine(implDir, "../../../packs/Microsoft.NETCore.App.Ref") if Directory.Exists(microsoftNETCoreAppRef) then @@ -269,14 +291,22 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, |> Array.sort |> Array.filter(fun v -> v <= version) |> Array.last - Some (directory.ToString()), Some microsoftNETCoreAppRef + (Some (directory.ToString()), Some microsoftNETCoreAppRef), warnings else - None, None - with | _ -> None, None + (None, None), warnings + with _ -> + // This is defensive coding, we don't expect this exception to happen + // NOTE: consider reporting this exception as a warning + (None, None), [] + + let tryGetNetCoreRefsPackDirectoryRoot() = tryNetCoreRefsPackDirectoryRoot.Force() // Tries to figure out the tfm for the compiler instance. // On coreclr it uses the deps.json file - let tryGetRunningDotNetCoreTfm() = + // + // On-demand because (a) some FxResolver are ephemeral (b) we want to avoid recomputation + let tryRunningDotNetCoreTfm = + lazy let file = try let asm = Assembly.GetEntryAssembly() @@ -288,7 +318,10 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, File.ReadAllText(depsJsonPath) else "" - with _ -> "" + with _ -> + // This is defensive coding, we don't expect this exception to happen + // NOTE: consider reporting this exception as a warning + "" let tfmPrefix=".NETCoreApp,Version=v" let pattern = "\"name\": \"" + tfmPrefix @@ -318,6 +351,8 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, | _ -> "net" Some (prefix + suffix) + let tryGetRunningDotNetCoreTfm() = tryRunningDotNetCoreTfm.Force() + // Tries to figure out the tfm for the compiler instance on the Windows desktop // On full clr it uses the mscorlib version number let getRunningDotNetFrameworkTfm () = @@ -366,7 +401,8 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, // no TFM could be found, assume latest stable? "net48" - let tryGetSdkRefsPackDirectory() = + let trySdkRefsPackDirectory = + lazy let tfmPrefix = "netcoreapp" let tfmCompare c1 c2 = let deconstructTfmApp (netcoreApp: DirectoryInfo) = @@ -376,7 +412,10 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, Some (Double.Parse(name.Substring(tfmPrefix.Length), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture)) else None - with _ -> None + with _ -> + // This is defensive coding, we don't expect this exception to happen + // NOTE: consider reporting this exception as a warning + None if c1 = c2 then 0 else @@ -387,7 +426,7 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, | _ -> 0 match tryGetNetCoreRefsPackDirectoryRoot() with - | Some version, Some root -> + | (Some version, Some root), warnings -> try let ref = Path.Combine(root, version, "ref") let highestTfm = @@ -396,17 +435,23 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, |> Array.tryLast match highestTfm with - | Some tfm -> Some (Path.Combine(ref, tfm.Name)) - | None -> None - with _ -> None - | _ -> None + | Some tfm -> Some (Path.Combine(ref, tfm.Name)), warnings + | None -> None, warnings + with _ -> + // This is defensive coding, we don't expect this exception to happen + // NOTE: consider reporting this exception as a warning + None, warnings + | _ -> None, [] + + let tryGetSdkRefsPackDirectory() = trySdkRefsPackDirectory.Force() let getDependenciesOf assemblyReferences = let assemblies = new Dictionary() // Identify path to a dll in the framework directory from a simple name let frameworkPathFromSimpleName simpleName = - let root = Path.Combine(getImplementationAssemblyDir(), simpleName) + let implDir = getImplementationAssemblyDir() |> replayWarnings + let root = Path.Combine(implDir, simpleName) let pathOpt = [| ""; ".dll"; ".exe" |] |> Seq.tryPick(fun ext -> @@ -429,7 +474,9 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, // Reference is a SimpleAssembly name reference, frameworkPathFromSimpleName reference - with _ -> reference, frameworkPathFromSimpleName reference + with _ -> + // This is defensive coding, we don't expect this exception to happen + reference, frameworkPathFromSimpleName reference if not (assemblies.ContainsKey(referenceName)) then try @@ -516,7 +563,7 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, ] let getDotNetCoreImplementationReferences useFsiAuxLib = - let implDir = getImplementationAssemblyDir() + let implDir = getImplementationAssemblyDir() |> replayWarnings let roots = [ yield! Directory.GetFiles(implDir, "*.dll") yield getFSharpCoreImplementationReference() @@ -706,13 +753,13 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, member _.GetSystemAssemblies() = systemAssemblies member _.IsInReferenceAssemblyPackDirectory filename = - match tryGetNetCoreRefsPackDirectoryRoot() with + match tryGetNetCoreRefsPackDirectoryRoot() |> replayWarnings with | _, Some root -> let path = Path.GetDirectoryName(filename) path.StartsWith(root, StringComparison.OrdinalIgnoreCase) | _ -> false - member _.TryGetSdkDir() = tryGetSdkDir() + member _.TryGetSdkDir() = tryGetSdkDir() |> replayWarnings /// Gets the selected target framework moniker, e.g netcore3.0, net472, and the running rid of the current machine member _.GetTfmAndRid() = @@ -724,7 +771,7 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, | Some tfm -> tfm | _ -> getRunningDotNetFrameworkTfm () else - let sdkDir = tryGetSdkDir() + let sdkDir = tryGetSdkDir() |> replayWarnings match sdkDir with | Some dir -> let dotnetConfigFile = Path.Combine(dir, "dotnet.runtimeconfig.json") @@ -761,19 +808,20 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, static member ClearStaticCaches() = desiredDotNetSdkVersionForDirectoryCache.Clear() - member _.GetFrameworkRefsPackDirectory() = tryGetSdkRefsPackDirectory() + member _.GetFrameworkRefsPackDirectory() = tryGetSdkRefsPackDirectory() |> replayWarnings member _.TryGetDesiredDotNetSdkVersionForDirectory() = tryGetDesiredDotNetSdkVersionForDirectoryInfo() // The set of references entered into the TcConfigBuilder for scripts prior to computing the load closure. - member _.GetDefaultReferences (useFsiAuxLib, assumeDotNetFramework) = + member _.GetDefaultReferences (useFsiAuxLib) = let defaultReferences = if assumeDotNetFramework then getDotNetFrameworkDefaultReferences useFsiAuxLib, assumeDotNetFramework else if useSdkRefs then // Go fetch references - match tryGetSdkRefsPackDirectory() with + let sdkDir = tryGetSdkRefsPackDirectory() |> replayWarnings + match sdkDir with | Some path -> try let sdkReferences = @@ -783,6 +831,7 @@ type internal FxResolver(assumeDotNetFramework: bool option, projectDir: string, ] sdkReferences, false with _ -> + // This is defensive coding, we don't expect this exception to happen if isRunningOnCoreClr then // If running on .NET Core and something goes wrong with getting the // .NET Core references then use .NET Core implementation assemblies for running process diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index 494c47906a0..2738bd1adf8 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -130,38 +130,45 @@ module ScriptPreprocessClosure = let rangeForErrors = mkFirstLineOfFile filename let tcConfigB = - let tcb = - TcConfigBuilder.CreateNew(legacyReferenceResolver, - defaultFSharpBinariesDir, - reduceMemoryUsage, - projectDir, - isInteractive, - isInvalidationSupported, - CopyFSharpCoreFlag.No, - tryGetMetadataSnapshot, - sdkDirOverride, - rangeForErrors) - tcb.useSdkRefs <- useSdkRefs - tcb + TcConfigBuilder.CreateNew(legacyReferenceResolver, + defaultFSharpBinariesDir, + reduceMemoryUsage, + projectDir, + isInteractive, + isInvalidationSupported, + CopyFSharpCoreFlag.No, + tryGetMetadataSnapshot, + sdkDirOverride, + rangeForErrors) + tcConfigB.SetPrimaryAssembly (if assumeDotNetFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime) + tcConfigB.SetUseSdkRefs useSdkRefs applyCommandLineArgs tcConfigB // Work out the references for the script in its location. This may produce diagnostics. - let assumeDotNetFramework, scriptDefaultReferencesDiagnostics = + let scriptDefaultReferencesDiagnostics = match basicReferences with | None -> let errorLogger = CapturingErrorLogger("ScriptDefaultReferences") use unwindEL = PushErrorLoggerPhaseUntilUnwind (fun _ -> errorLogger) - let references, assumeDotNetFramework = tcConfigB.FxResolver.GetDefaultReferences (useFsiAuxLib, assumeDotNetFramework) + let references, useDotNetFramework = tcConfigB.FxResolver.GetDefaultReferences (useFsiAuxLib) + + // If the user requested .NET Core scripting but something went wrong and we reverted to + // .NET Framework scripting then we must adjsut both the primaryAssembly and fxResolver + if useDotNetFramework <> assumeDotNetFramework then + tcConfigB.SetPrimaryAssembly (if useDotNetFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime) + // Add script references for reference in references do tcConfigB.AddReferencedAssemblyByPath(range0, reference) - assumeDotNetFramework , errorLogger.Diagnostics + + errorLogger.Diagnostics + | Some (rs, diagnostics) -> for m, reference in rs do tcConfigB.AddReferencedAssemblyByPath(m, reference) - assumeDotNetFramework, diagnostics + diagnostics tcConfigB.resolutionEnvironment <- match codeContext with @@ -173,8 +180,7 @@ module ScriptPreprocessClosure = // Indicates that there are some references not in basicReferencesForScriptLoadClosure which should // be added conditionally once the relevant version of mscorlib.dll has been detected. tcConfigB.implicitlyResolveAssemblies <- false - tcConfigB.useSdkRefs <- useSdkRefs - tcConfigB.primaryAssembly <- if assumeDotNetFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime + tcConfigB.SetUseSdkRefs useSdkRefs TcConfig.Create(tcConfigB, validate=true), scriptDefaultReferencesDiagnostics diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index bf5f44a3875..4803a5632dc 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -236,7 +236,7 @@ let AdjustForScriptCompile(ctok, tcConfigB: TcConfigBuilder, commandLineSourceFi // If there is a target framework for the script then push that as a requirement into the overall compilation and add all the framework references implied // by the script too. - tcConfigB.primaryAssembly <- (if closure.UseDesktopFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime) + tcConfigB.SetPrimaryAssembly (if closure.UseDesktopFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime) if tcConfigB.framework then let references = closure.References |> List.collect snd references |> List.iter (fun r -> tcConfigB.AddReferencedAssemblyByPath(r.originalReference.Range, r.resolvedPath)) @@ -449,16 +449,15 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, let tcConfigB = TcConfigBuilder.CreateNew(legacyReferenceResolver, - defaultFSharpBinariesDir, - reduceMemoryUsage=reduceMemoryUsage, - implicitIncludeDir=directoryBuildingFrom, - isInteractive=false, - isInvalidationSupported=false, - defaultCopyFSharpCore=defaultCopyFSharpCore, - tryGetMetadataSnapshot=tryGetMetadataSnapshot, - sdkDirOverride=None, - rangeForErrors=range0 - ) + defaultFSharpBinariesDir, + reduceMemoryUsage=reduceMemoryUsage, + implicitIncludeDir=directoryBuildingFrom, + isInteractive=false, + isInvalidationSupported=false, + defaultCopyFSharpCore=defaultCopyFSharpCore, + tryGetMetadataSnapshot=tryGetMetadataSnapshot, + sdkDirOverride=None, + rangeForErrors=range0) // Preset: --optimize+ -g --tailcalls+ (see 4505) SetOptimizeSwitch tcConfigB OptionSwitch.On @@ -656,7 +655,7 @@ let main1OfAst PrimaryAssembly.Mscorlib tcConfigB.target <- target - tcConfigB.primaryAssembly <- primaryAssembly + tcConfigB.SetPrimaryAssembly primaryAssembly if noframework then tcConfigB.framework <- false tcConfigB.implicitlyResolveAssemblies <- false diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 839f40c0b09..dcde18e9a44 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -2782,7 +2782,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i do tcConfigB.useFsiAuxLib <- fsi.UseFsiAuxLib #if NETSTANDARD - do tcConfigB.useSdkRefs <- true + do tcConfigB.SetUseSdkRefs true do tcConfigB.useSimpleResolution <- true do if FSharpEnvironment.isRunningOnCoreClr then SetTargetProfile tcConfigB "netcore" // always assume System.Runtime codegen #endif diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index e07dc1179d6..42bcbc9bf3c 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -1326,7 +1326,17 @@ type FSharpChecker(legacyReferenceResolver, member _.GetParsingOptionsFromCommandLineArgs(sourceFiles, argv, ?isInteractive) = let isInteractive = defaultArg isInteractive false use errorScope = new ErrorScope() - let tcConfigBuilder = TcConfigBuilder.Initial + let tcConfigBuilder = + TcConfigBuilder.CreateNew(legacyReferenceResolver, + defaultFSharpBinariesDir=FSharpCheckerResultsSettings.defaultFSharpBinariesDir, + reduceMemoryUsage=ReduceMemoryFlag.Yes, + implicitIncludeDir="", + isInteractive=isInteractive, + isInvalidationSupported=false, + defaultCopyFSharpCore=CopyFSharpCoreFlag.No, + tryGetMetadataSnapshot=tryGetMetadataSnapshot, + sdkDirOverride=None, + rangeForErrors=range0) // Apply command-line arguments and collect more source files if they are in the arguments let sourceFilesNew = ApplyCommandLineArgs(tcConfigBuilder, sourceFiles, argv) @@ -1427,8 +1437,8 @@ type CompilerEnvironment() = // Legacy entry point, no longer used by FSharp.Editor static member DefaultReferencesForOrphanSources assumeDotNetFramework = let currentDirectory = Directory.GetCurrentDirectory() - let fxResolver = FxResolver(Some assumeDotNetFramework, currentDirectory, rangeForErrors=range0, useSdkRefs=true, isInteractive=false, sdkDirOverride=None) - let references, _ = fxResolver.GetDefaultReferences (useFsiAuxLib=false, assumeDotNetFramework=assumeDotNetFramework) + let fxResolver = FxResolver(assumeDotNetFramework, currentDirectory, rangeForErrors=range0, useSdkRefs=true, isInteractive=false, sdkDirOverride=None) + let references, _ = fxResolver.GetDefaultReferences (useFsiAuxLib=false) references /// Publish compiler-flags parsing logic. Must be fast because its used by the colorizer. From ea42d54ed8bc8e218cfb28d4baf4fc2374f68a98 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 01:11:42 +0000 Subject: [PATCH 11/31] fix issues with .NET core scripting references in editing --- tests/service/ScriptOptionsTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/service/ScriptOptionsTests.fs b/tests/service/ScriptOptionsTests.fs index 853df656a18..c7d9ee4755a 100644 --- a/tests/service/ScriptOptionsTests.fs +++ b/tests/service/ScriptOptionsTests.fs @@ -51,7 +51,7 @@ let ``all default assembly references are system assemblies``(assumeNetFx, useSd let ref = Path.GetFullPath(r.[3..]) let baseName = Path.GetFileNameWithoutExtension(ref) let projectDir = System.Environment.CurrentDirectory - if not (FSharp.Compiler.FxResolver(Some assumeNetFx, projectDir, rangeForErrors=range0, useSdkRefs=useSdkRefs, isInteractive=false, sdkDirOverride=None).GetSystemAssemblies().Contains(baseName)) then + if not (FSharp.Compiler.FxResolver(assumeNetFx, projectDir, rangeForErrors=range0, useSdkRefs=useSdkRefs, isInteractive=false, sdkDirOverride=None).GetSystemAssemblies().Contains(baseName)) then printfn "Failing, printing options from GetProjectOptionsFromScript..." for opt in options.OtherOptions do printfn "option: %s" opt @@ -82,7 +82,7 @@ let ``sdk dir with dodgy global json gives warning``() = printfn "Failure!" printfn "tempPath = %A" tempPath printfn "options = %A" options - let fxResolver = FSharp.Compiler.FxResolver(Some false, tempPath, rangeForErrors=range0, useSdkRefs=true, isInteractive=false, sdkDirOverride=None) + let fxResolver = FSharp.Compiler.FxResolver(false, tempPath, rangeForErrors=range0, useSdkRefs=true, isInteractive=false, sdkDirOverride=None) let result = fxResolver.TryGetDesiredDotNetSdkVersionForDirectory() printfn "sdkVersion = %A" result From 0634df8aeecc91a41b014d495ec88e578fc4b932 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 01:34:29 +0000 Subject: [PATCH 12/31] fix issues with .NET core scripting references in editing --- src/fsharp/FSComp.txt | 1 + src/fsharp/FxResolver.fs | 49 +++++++++++++++++---------- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.de.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.es.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.fr.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.it.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ja.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ko.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.pl.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ru.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.tr.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 +++ 15 files changed, 97 insertions(+), 18 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index cadbc16384c..7fb9ecce89c 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1544,6 +1544,7 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3382,parsEmptyFillInInterpolatedString,"Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected." 3383,lexRBraceInInterpolatedString,"A '}}' character must be escaped (by doubling) in an interpolated string." 3384,scriptSdkNotDetermined,"The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. The output from '%s --version' in the directory '%s' was: '%s' and the exit code was '%d'." +3384,scriptSdkNotDeterminedUnexpected,"The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '%s'." #3501 "This construct is not supported by your version of the F# compiler" CompilerMessage(ExperimentalAttributeMessages.NotSupportedYet, 3501, IsError=true) 3390,xmlDocBadlyFormed,"This XML comment is invalid: '%s'" 3390,xmlDocMissingParameterName,"This XML comment is invalid: missing 'name' attribute for parameter or parameter reference" diff --git a/src/fsharp/FxResolver.fs b/src/fsharp/FxResolver.fs index d12505e8bb9..b885434a300 100644 --- a/src/fsharp/FxResolver.fs +++ b/src/fsharp/FxResolver.fs @@ -180,7 +180,12 @@ type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdk let sdkDir = DirectoryInfo(sdksDir).GetDirectories() // Filter to the version reported by `dotnet --version` in the location, if that succeeded - |> Array.filter (fun di -> match desiredSdkVer with None -> true | Some v -> di.Name = v) + // If it didn't succeed we will revert back to implementation assemblies, but still need an SDK + // to use, so we find the SDKs by looking for dotnet.runtimeconfig.json + |> Array.filter (fun di -> + match desiredSdkVer with + | None -> File.Exists(Path.Combine(di.FullName,"dotnet.runtimeconfig.json")) + | Some v -> di.Name = v) |> Array.sortBy (fun di -> di.FullName) |> Array.tryLast |> Option.map (fun di -> di.FullName) @@ -207,18 +212,23 @@ type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdk let sdkDir, warnings = tryGetSdkDir() match sdkDir with | Some dir -> - let dotnetConfigFile = Path.Combine(dir, "dotnet.runtimeconfig.json") - let dotnetConfig = File.ReadAllText(dotnetConfigFile) - let pattern = "\"version\": \"" - let startPos = dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length - let endPos = dotnetConfig.IndexOf("\"", startPos) - let ver = dotnetConfig.[startPos..endPos-1] - let path = Path.GetFullPath(Path.Combine(dir, "..", "..", "shared", "Microsoft.NETCore.App", ver)) - if Directory.Exists(path) then - path, warnings - else - getRunningImplementationAssemblyDir(), warnings - | None -> + try + let dotnetConfigFile = Path.Combine(dir, "dotnet.runtimeconfig.json") + let dotnetConfig = File.ReadAllText(dotnetConfigFile) + let pattern = "\"version\": \"" + let startPos = dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length + let endPos = dotnetConfig.IndexOf("\"", startPos) + let ver = dotnetConfig.[startPos..endPos-1] + let path = Path.GetFullPath(Path.Combine(dir, "..", "..", "shared", "Microsoft.NETCore.App", ver)) + if Directory.Exists(path) then + path, warnings + else + getRunningImplementationAssemblyDir(), warnings + with e -> + let warn = Error(FSComp.SR.scriptSdkNotDeterminedUnexpected(e.Message), rangeForErrors) + let path = getRunningImplementationAssemblyDir() + path, [warn] + | _ -> let path = getRunningImplementationAssemblyDir() path, [] @@ -294,10 +304,11 @@ type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdk (Some (directory.ToString()), Some microsoftNETCoreAppRef), warnings else (None, None), warnings - with _ -> + with e -> + let warn = Error(FSComp.SR.scriptSdkNotDeterminedUnexpected(e.Message), rangeForErrors) // This is defensive coding, we don't expect this exception to happen // NOTE: consider reporting this exception as a warning - (None, None), [] + (None, None), [warn] let tryGetNetCoreRefsPackDirectoryRoot() = tryNetCoreRefsPackDirectoryRoot.Force() @@ -437,10 +448,11 @@ type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdk match highestTfm with | Some tfm -> Some (Path.Combine(ref, tfm.Name)), warnings | None -> None, warnings - with _ -> + with e -> + let warn = Error(FSComp.SR.scriptSdkNotDeterminedUnexpected(e.Message), rangeForErrors) // This is defensive coding, we don't expect this exception to happen // NOTE: consider reporting this exception as a warning - None, warnings + None, warnings @ [warn] | _ -> None, [] let tryGetSdkRefsPackDirectory() = trySdkRefsPackDirectory.Force() @@ -830,7 +842,8 @@ type internal FxResolver(assumeDotNetFramework: bool, projectDir: string, useSdk if useFsiAuxLib then yield getFsiLibraryImplementationReference() ] sdkReferences, false - with _ -> + with e -> + warning (Error(FSComp.SR.scriptSdkNotDeterminedUnexpected(e.Message), rangeForErrors)) // This is defensive coding, we don't expect this exception to happen if isRunningOnCoreClr then // If running on .NET Core and something goes wrong with getting the diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 9afe6f66276..e5743c212c4 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -327,6 +327,11 @@ Sadu .NET SDK pro tento skript nešlo určit. Pokud se skript nachází v adresáři používajícím global.json, zkontrolujte, jestli je nainstalovaná odpovídající sada .NET SDK. Výstup ze zadání {0} --version v adresáři {1} byl {2} a ukončovací kód byl {3}. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Tato funkce se v této verzi jazyka F# nepodporuje. Abyste mohli tuto funkci používat, možná bude nutné přidat /langversion:preview. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index da757ed8d60..e4061568dfc 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -327,6 +327,11 @@ Das .NET SDK für dieses Skript konnte nicht ermittelt werden. Wenn sich das Skript in einem Verzeichnis mit "global.json" befindet, stellen Sie sicher, dass das entsprechende .NET SDK installiert ist. Ausgabe von "{0} --version" im Verzeichnis "{1}": {2}. Exitcode: {3}. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Dieses Feature wird in dieser Version von F# nicht unterstützt. Möglicherweise müssen Sie "/langversion:preview" hinzufügen, um dieses Feature zu verwenden. diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 9b3402a2d18..55cb7f62aa1 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -327,6 +327,11 @@ No se pudo determinar el SDK de .NET para este script. Si el script está en un directorio que usa una instancia de "global.json", asegúrese de que el SDK de .NET pertinente esté instalado. La salida de "{0} --version" en el directorio "{1}" era "{2}", con el código de salida "{3}". + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Esta versión de F# no admite esta característica. Es posible que tenga que agregar /langversion:preview para usarla. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 01fa27b2362..76f755025a9 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -327,6 +327,11 @@ Le kit SDK .NET de ce script n'a pas pu être déterminé. Si le script se trouve dans un répertoire utilisant un fichier 'global.json', vérifiez que le kit SDK .NET approprié est installé. La sortie de '{0} --version' dans le répertoire '{1}' était '{2}', et le code de sortie était '{3}'. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Cette fonctionnalité n'est pas prise en charge dans cette version de F#. Vous devrez peut-être ajouter /langversion:preview pour pouvoir utiliser cette fonctionnalité. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 857dea97f1c..1a112ef13a9 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -327,6 +327,11 @@ Non è stato possibile determinare la versione di .NET SDK per questo script. Se lo script si trova in una directory che usa un file 'global.json', assicurarsi che sia installata la versione pertinente di .NET SDK. L'output di '{0} --version' nella directory '{1}' è '{2}' e il codice di uscita è '{3}'. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Questa funzionalità non è supportata in questa versione di F#. Per usare questa funzionalità, potrebbe essere necessario aggiungere /langversion:preview. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 75708df21f4..5ac6967a019 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -327,6 +327,11 @@ このスクリプトの .NET SDK を特定できませんでした。このスクリプトが、'global.json' が使用されているディレクトリにある場合は、関連する .NET SDK がインストールされていることを確認してください。ディレクトリ '{1}' の '{0} --version' からの出力は '{2}' で、終了コードは '{3}' でした。 + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. この機能は、このバージョンの F# ではサポートされていません。この機能を使用するには、/langversion:preview の追加が必要な場合があります。 diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 36bc1eb7f2a..21b4ffeaba9 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -327,6 +327,11 @@ 이 스크립트에 대한 .NET SDK를 확인할 수 없습니다. 스크립트가 'global.json'을 사용하는 디렉터리에 있는 경우 관련 .NET SDK가 설치되어 있는지 확인하세요. '{1}' 디렉터리에 있는 '{0} --version'의 출력은 '{2}'이고 종료 코드는 '{3}'입니다. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 이 기능은 이 F# 버전에서 지원되지 않습니다. 이 기능을 사용하기 위해 /langversion:preview를 추가해야 할 수도 있습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index dff154aff37..882b461778d 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -327,6 +327,11 @@ Nie można określić zestawu .NET SDK dla tego skryptu. Jeśli skrypt znajduje się w katalogu korzystającym z pliku „global.json”, upewnij się, że zainstalowano odpowiedni zestaw .NET SDK. Dane wyjściowe polecenia „{0} --version” w katalogu „{1}” to „{2}”, a kod zakończenia to „{3}”. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Ta funkcja nie jest obsługiwana w tej wersji języka F#. Aby korzystać z tej funkcji, może być konieczne dodanie parametru /langversion:preview. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index fda87eb62cb..2df5c973a32 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -327,6 +327,11 @@ Não foi possível determinar o SDK do .NET para esse script. Se o script estiver em um diretório usando um 'global.json', verifique se o SDK relevante do .NET está instalado. A saída de '{0} --version' no diretório '{1}' foi: '{2}' e o código de saída foi '{3}'. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Este recurso não tem suporte nesta versão do F#. Talvez seja necessário adicionar /langversion:preview para usar este recurso. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index e78c8952134..d5bdb943475 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -327,6 +327,11 @@ Не удалось определить пакет SDK .NET для этого сценария. Если сценарий находится в каталоге с использованием "global.json", убедитесь, что установлен соответствующий пакет SDK .NET. Выходные данные команды "{0} --version" в каталоге "{1}" — "{2}", а код выхода — "{3}". + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Эта функция не поддерживается в данной версии F#. Возможно, потребуется добавить/langversion:preview, чтобы использовать эту функцию. diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 7493558ed05..b51c67434b5 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -327,6 +327,11 @@ Bu betik için .NET SDK belirlenemedi. Betik 'global.json' kullanan bir dizindeyse, ilgili .NET SDK'nın yüklü olduğundan emin olun. '{1}' dizinindeki '{0} --version' çıkışı: '{2}' ve çıkış kodu: '{3}'. + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Bu özellik, bu F# sürümünde desteklenmiyor. Bu özelliği kullanabilmeniz için /langversion:preview eklemeniz gerekebilir. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index de0492e6daf..68f0e225ab5 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -327,6 +327,11 @@ 无法确定此脚本的 .NET SDK。如果脚本在使用 "global.json" 的目录中,请确保已安装相关的 .NET SDK。目录“{1}”中 "{0} --version" 的输出为“{2}”,退出代码为“{3}”。 + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 此版本的 F# 不支持此功能。你可能需要添加 /langversion:preview 才可使用此功能。 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 1698ca1cad1..1efa245134e 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -327,6 +327,11 @@ 無法判斷這個指令碼的 .NET SDK。如果指令碼位於使用 'global.json' 的目錄中,請確認已安裝相關的 .NET SDK。目錄 '{1}' 中 '{0} --version' 的輸出為: '{2}',結束代碼為 '{3}'。 + + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '{0}'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 此版本的 F# 不支援此功能。您可能需要新增 /langversion:preview 才能使用此功能。 From 3da2ab5cdd1ee6deabad59c884d7d823c80351ba Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 01:47:13 +0000 Subject: [PATCH 13/31] fix issues with .NET core scripting references in editing --- src/fsharp/ScriptClosure.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index 2738bd1adf8..52bfc807349 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -155,7 +155,7 @@ module ScriptPreprocessClosure = let references, useDotNetFramework = tcConfigB.FxResolver.GetDefaultReferences (useFsiAuxLib) // If the user requested .NET Core scripting but something went wrong and we reverted to - // .NET Framework scripting then we must adjsut both the primaryAssembly and fxResolver + // .NET Framework scripting then we must adjust both the primaryAssembly and fxResolver if useDotNetFramework <> assumeDotNetFramework then tcConfigB.SetPrimaryAssembly (if useDotNetFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime) From 84fe60222a9d3d2b92fbccbcd5d1e045c8ee4f9d Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 01:50:31 +0000 Subject: [PATCH 14/31] add tests --- .../sdk-script-manual-tests/README.md.txt | 84 +++++++++++++++++++ ...etcore-script-reference-netcore-script.fsx | 9 ++ .../netcore-script.fsx | 26 ++++++ .../with-sdk-3.1.0/global.json | 5 ++ .../netcore-script-sdk-3.1.0.fsx | 26 ++++++ .../with-sdk-5.0.101/global.json | 5 ++ .../netcore-script-sdk-5.0.101.fsx | 26 ++++++ .../with-sdk-666.666.666/global.json | 5 ++ .../netcore-script-sdk-666.666.666 - Copy.fsx | 13 +++ .../netcore-script-sdk-666.666.666.fsx | 14 ++++ .../with-sdk-666.666.667/global.json | 5 ++ .../netcore-script-sdk-666.666.666.fsx | 14 ++++ 12 files changed, 232 insertions(+) create mode 100644 tests/walkthroughs/sdk-script-manual-tests/README.md.txt create mode 100644 tests/walkthroughs/sdk-script-manual-tests/netcore-script-reference-netcore-script.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/netcore-script.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/global.json create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/netcore-script-sdk-3.1.0.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/global.json create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/netcore-script-sdk-5.0.101.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/global.json create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666 - Copy.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666.fsx create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/global.json create mode 100644 tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/netcore-script-sdk-666.666.666.fsx diff --git a/tests/walkthroughs/sdk-script-manual-tests/README.md.txt b/tests/walkthroughs/sdk-script-manual-tests/README.md.txt new file mode 100644 index 00000000000..7d0428ddc0c --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/README.md.txt @@ -0,0 +1,84 @@ + + + +#### no warnings + +``` +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netcore-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netfx-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\neutral-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netcore-script-reference-netcore-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netcore-script-reference-neutral-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netfx-script-reference-netfx-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netfx-script-reference-neutral-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\neutral-script-reference-netcore-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\neutral-script-reference-netfx-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\neutral-script-reference-neutral-script.fsx +``` +#### warnings + +``` +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netcore-script-reference-netfx-script.fsx +artifacts\bin\fsc\Debug\net472\fsc.exe c:\misc\tests\netfx-script-reference-netcore-script.fsx +``` + + +``` +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netcore-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netfx-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\neutral-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netcore-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netcore-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netcore-script-reference-neutral-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netfx-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netfx-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\netfx-script-reference-neutral-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\neutral-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\neutral-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsc\Debug\netcoreapp3.1\fsc.exe c:\misc\tests\neutral-script-reference-neutral-script.fsx +``` + +#### no warnings + +``` +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netfx-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\neutral-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netfx-script-reference-netfx-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netfx-script-reference-neutral-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\neutral-script-reference-netfx-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\neutral-script-reference-neutral-script.fsx +``` + +#### warnings + +``` +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netcore-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netcore-script-reference-netcore-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netcore-script-reference-netfx-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netcore-script-reference-neutral-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\netfx-script-reference-netcore-script.fsx +artifacts\bin\fsi\Debug\net472\fsi.exe c:\misc\tests\neutral-script-reference-netcore-script.fsx +``` + +#### no warnings + +``` +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netcore-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\neutral-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netcore-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netcore-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netcore-script-reference-neutral-script.fsx +``` + +#### warnings + +``` +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netfx-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netfx-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netfx-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\netfx-script-reference-neutral-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\neutral-script-reference-netcore-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\neutral-script-reference-netfx-script.fsx +dotnet artifacts\bin\fsi\Debug\netcoreapp3.1\fsi.exe c:\misc\tests\neutral-script-reference-neutral-script.fsx + +``` \ No newline at end of file diff --git a/tests/walkthroughs/sdk-script-manual-tests/netcore-script-reference-netcore-script.fsx b/tests/walkthroughs/sdk-script-manual-tests/netcore-script-reference-netcore-script.fsx new file mode 100644 index 00000000000..c2dea42e0a1 --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/netcore-script-reference-netcore-script.fsx @@ -0,0 +1,9 @@ + +#r "System.dll" +//#r "nuget: FSharp.Data" +//#r "nuget: Quack" +printfn "hello from %s" __SOURCE_FILE__ +#r "netstandard.dll" + +#load "netcore-script.fsx" + diff --git a/tests/walkthroughs/sdk-script-manual-tests/netcore-script.fsx b/tests/walkthroughs/sdk-script-manual-tests/netcore-script.fsx new file mode 100644 index 00000000000..025547c8450 --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/netcore-script.fsx @@ -0,0 +1,26 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + +1+1 + + +//#r "nuget: DiffSharp.Core,1.0.0-preview-263264614" + +//#r "nuget: Quack" + + + + +//#r "System.EnterpriseServices.dll" +//// A netfx api +//let f2 (x: System.EnterpriseServices.Activity) = () + diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/global.json b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/global.json new file mode 100644 index 00000000000..c120c8115ea --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "3.1.301" + } +} \ No newline at end of file diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/netcore-script-sdk-3.1.0.fsx b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/netcore-script-sdk-3.1.0.fsx new file mode 100644 index 00000000000..14bc4a2334f --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-3.1.0/netcore-script-sdk-3.1.0.fsx @@ -0,0 +1,26 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + + +1+1 + +#r "nuget: DiffSharp.Core,1.0.0-preview-263264614" + +//#r "nuget: Quack" + + + + +//#r "System.EnterpriseServices.dll" +//// A netfx api +//let f2 (x: System.EnterpriseServices.Activity) = () + diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/global.json b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/global.json new file mode 100644 index 00000000000..fbb332028b9 --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "5.0.101" + } +} \ No newline at end of file diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/netcore-script-sdk-5.0.101.fsx b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/netcore-script-sdk-5.0.101.fsx new file mode 100644 index 00000000000..53ee539c4a8 --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-5.0.101/netcore-script-sdk-5.0.101.fsx @@ -0,0 +1,26 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + + +1+1 + +//#r "nuget: DiffSharp.Core,1.0.0-preview-263264614" + +//#r "nuget: Quack" + + + + +//#r "System.EnterpriseServices.dll" +//// A netfx api +//let f2 (x: System.EnterpriseServices.Activity) = () + diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/global.json b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/global.json new file mode 100644 index 00000000000..7337e805efb --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "666.666.666" + } +} \ No newline at end of file diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666 - Copy.fsx b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666 - Copy.fsx new file mode 100644 index 00000000000..53f3881d296 --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666 - Copy.fsx @@ -0,0 +1,13 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + +1+1 diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666.fsx b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666.fsx new file mode 100644 index 00000000000..7756ebcebbf --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.666/netcore-script-sdk-666.666.666.fsx @@ -0,0 +1,14 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + + +1+1 diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/global.json b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/global.json new file mode 100644 index 00000000000..7337e805efb --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "666.666.666" + } +} \ No newline at end of file diff --git a/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/netcore-script-sdk-666.666.666.fsx b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/netcore-script-sdk-666.666.666.fsx new file mode 100644 index 00000000000..7756ebcebbf --- /dev/null +++ b/tests/walkthroughs/sdk-script-manual-tests/with-sdk-666.666.667/netcore-script-sdk-666.666.666.fsx @@ -0,0 +1,14 @@ + +#r "System.dll" + +printfn "hello from %s" __SOURCE_FILE__ + +System.Environment.CurrentDirectory + +#r "netstandard.dll" + +// A .netcoreapp3.1 api +let f x = System.Runtime.InteropServices.NativeLibrary.Free(x) + + +1+1 From 77817f0000a3ccf3224d80de86c5f028afc6efe5 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 17 Feb 2021 19:19:42 +0000 Subject: [PATCH 15/31] add test project --- src/fsharp/CompilerConfig.fs | 18 ++++++++++-------- src/fsharp/CompilerConfig.fsi | 6 +++--- src/fsharp/CompilerImports.fs | 2 +- src/fsharp/CompilerOptions.fs | 4 ++-- src/fsharp/ParseAndCheckInputs.fs | 2 +- src/fsharp/ScriptClosure.fs | 8 ++++---- src/fsharp/ScriptClosure.fsi | 2 +- src/fsharp/fsc.fs | 2 +- src/fsharp/fsi/fsi.fs | 16 ++++++++-------- src/fsharp/service/FSharpAnalyzer.fs | 16 ++++------------ src/fsharp/service/FSharpAnalyzer.fsi | 2 +- src/fsharp/service/IncrementalBuild.fs | 6 +++--- .../data/TestAnalyzer/TestAnalyzer.fsproj | 3 +-- .../UsingTestAnalyzerInProject/README.txt | 16 ++++++++++++++++ .../TestProject.fsproj | 19 +++++++++++++++++++ .../UsingTestAnalyzerInProject/test.fs | 10 ++++++++++ 16 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProject/README.txt create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProject/test.fs diff --git a/src/fsharp/CompilerConfig.fs b/src/fsharp/CompilerConfig.fs index 955b4ce3ed2..c4633de9eec 100644 --- a/src/fsharp/CompilerConfig.fs +++ b/src/fsharp/CompilerConfig.fs @@ -336,7 +336,7 @@ type TcConfigBuilder = mutable light: bool option mutable conditionalCompilationDefines: string list mutable loadedSources: (range * string * string) list - mutable compilerToolPaths: string list + mutable compilerToolPaths: (range * string) list mutable referencedDLLs: AssemblyReference list mutable packageManagerLines: Map mutable projectReferences: IProjectReference list @@ -501,7 +501,7 @@ type TcConfigBuilder = member tcConfigB.GetNativeProbingRoots () = seq { yield! tcConfigB.includes - yield! tcConfigB.compilerToolPaths + yield! List.map snd tcConfigB.compilerToolPaths yield! (tcConfigB.referencedDLLs |> Seq.map(fun ref -> Path.GetDirectoryName(ref.Text))) yield tcConfigB.implicitIncludeDir } @@ -772,11 +772,13 @@ type TcConfigBuilder = member tcConfigB.AddEmbeddedResource filename = tcConfigB.embedResources <- tcConfigB.embedResources ++ filename - member tcConfigB.AddCompilerToolsByPath (path) = - if not (tcConfigB.compilerToolPaths |> List.exists (fun text -> path = text)) then // NOTE: We keep same paths if range is different. - let compilerToolPath = tcConfigB.compilerToolPaths |> List.tryPick (fun text -> if text = path then Some text else None) - if compilerToolPath.IsNone then - tcConfigB.compilerToolPaths <- tcConfigB.compilerToolPaths ++ path + member tcConfigB.AddCompilerToolsByPath (m, path) = + if FileSystem.IsInvalidPathShim path then + warning(Error(FSComp.SR.buildInvalidAssemblyName(path), m)) + // TODO: check this is the right place to resolve paths + let rootedPath = if Path.IsPathRooted(path) then path else Path.Combine(tcConfigB.implicitIncludeDir, path) + if not (tcConfigB.compilerToolPaths |> List.exists (fun (_m, text) -> rootedPath = text)) then + tcConfigB.compilerToolPaths <- tcConfigB.compilerToolPaths ++ (m, rootedPath) member tcConfigB.AddReferencedAssemblyByPath (m, path) = if FileSystem.IsInvalidPathShim path then @@ -798,7 +800,7 @@ type TcConfigBuilder = | ErrorReportType.Warning -> warning(Error(error, m)) | ErrorReportType.Error -> errorR(Error(error, m))) - let dm = dependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, output , reportError, path) + let dm = dependencyProvider.TryFindDependencyManagerInPath(List.map snd tcConfigB.compilerToolPaths, output , reportError, path) match dm with | _, dependencyManager when not(isNull dependencyManager) -> diff --git a/src/fsharp/CompilerConfig.fsi b/src/fsharp/CompilerConfig.fsi index 58ce21a082b..a808b66a408 100644 --- a/src/fsharp/CompilerConfig.fsi +++ b/src/fsharp/CompilerConfig.fsi @@ -150,7 +150,7 @@ type TcConfigBuilder = mutable conditionalCompilationDefines: string list /// Sources added into the build with #load mutable loadedSources: (range * string * string) list - mutable compilerToolPaths: string list + mutable compilerToolPaths: (range * string) list mutable referencedDLLs: AssemblyReference list mutable packageManagerLines: Map mutable projectReferences: IProjectReference list @@ -294,7 +294,7 @@ type TcConfigBuilder = member AddIncludePath: range * string * string -> unit - member AddCompilerToolsByPath: string -> unit + member AddCompilerToolsByPath: range * string -> unit member AddReferencedAssemblyByPath: range * string -> unit @@ -342,7 +342,7 @@ type TcConfig = member conditionalCompilationDefines: string list member subsystemVersion: int * int member useHighEntropyVA: bool - member compilerToolPaths: string list + member compilerToolPaths: (range * string) list member referencedDLLs: AssemblyReference list member reduceMemoryUsage: ReduceMemoryFlag member inputCodePage: int option diff --git a/src/fsharp/CompilerImports.fs b/src/fsharp/CompilerImports.fs index 6aaa5035dec..9fe4a16c0bc 100644 --- a/src/fsharp/CompilerImports.fs +++ b/src/fsharp/CompilerImports.fs @@ -1280,7 +1280,7 @@ and [] TcImports(tcConfigP: TcConfigProvider, initialResolutions: TcAsse tcConfig.isInteractive, systemRuntimeContainsType, primaryAssemblyVersion, - tcConfig.compilerToolPaths, + List.map snd tcConfig.compilerToolPaths, m) ] // Note, type providers are disposable objects. The TcImports owns the provider objects - when/if it is disposed, the providers are disposed. // We ignore all exceptions from provider disposal. diff --git a/src/fsharp/CompilerOptions.fs b/src/fsharp/CompilerOptions.fs index 41fb657d69b..1c458197c36 100644 --- a/src/fsharp/CompilerOptions.fs +++ b/src/fsharp/CompilerOptions.fs @@ -567,14 +567,14 @@ let PrintOptionInfo (tcConfigB:TcConfigBuilder) = let inputFileFlagsBoth (tcConfigB : TcConfigBuilder) = [ CompilerOption("reference", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), None, Some (FSComp.SR.optsReference())) - CompilerOption("compilertool", tagFile, OptionString (fun s -> tcConfigB.AddCompilerToolsByPath s), None, Some (FSComp.SR.optsCompilerTool())) + CompilerOption("compilertool", tagFile, OptionString (fun s -> tcConfigB.AddCompilerToolsByPath (rangeStartup, s)), None, Some (FSComp.SR.optsCompilerTool())) ] let referenceFlagAbbrev (tcConfigB : TcConfigBuilder) = CompilerOption("r", tagFile, OptionString (fun s -> tcConfigB.AddReferencedAssemblyByPath (rangeStartup, s)), None, Some(FSComp.SR.optsShortFormOf("--reference"))) let compilerToolFlagAbbrev (tcConfigB : TcConfigBuilder) = - CompilerOption("t", tagFile, OptionString (fun s -> tcConfigB.AddCompilerToolsByPath s), None, Some(FSComp.SR.optsShortFormOf("--compilertool"))) + CompilerOption("t", tagFile, OptionString (fun s -> tcConfigB.AddCompilerToolsByPath (rangeStartup, s)), None, Some(FSComp.SR.optsShortFormOf("--compilertool"))) let inputFileFlagsFsc tcConfigB = inputFileFlagsBoth tcConfigB diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index b07972ae03a..ba048a6d1e6 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -542,7 +542,7 @@ let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, let tcConfigB = tcConfig.CloneToBuilder() let getWarningNumber = fun () _ -> () let addReferenceDirective = fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive) - let addCompilerTool = fun () (_m, s) -> tcConfigB.AddCompilerToolsByPath(s) + let addCompilerTool = fun () (m, s) -> tcConfigB.AddCompilerToolsByPath(m, s) let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s,pathOfMetaCommandSource) ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addCompilerTool, addLoadedSource) diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index 0bfaf3982a7..20b7ae949ce 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -39,7 +39,7 @@ type LoadClosure = References: (string * AssemblyResolution list) list /// The referenced compiler tools. - CompilerTools: string list + CompilerTools: (range * string) list /// The resolved pacakge references along with the ranges of the #r positions in each file. PackageReferences: (range * string list)[] @@ -209,7 +209,7 @@ module ScriptPreprocessClosure = let mutable nowarns = [] let getWarningNumber = fun () (m, s) -> nowarns <- (s, m) :: nowarns let addReferenceDirective = fun () (m, s, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive) - let addCompilerTool = fun () (_m, s) -> tcConfigB.AddCompilerToolsByPath(s) + let addCompilerTool = fun () (m, s) -> tcConfigB.AddCompilerToolsByPath(m, s) let addLoadedSource = fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource) try ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addCompilerTool, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ()) @@ -253,9 +253,9 @@ module ScriptPreprocessClosure = | Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> () | _ -> let outputDir = tcConfig.outputDir |> Option.defaultValue "" - match dependencyProvider.TryFindDependencyManagerByKey(tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with + match dependencyProvider.TryFindDependencyManagerByKey(List.map snd tcConfig.compilerToolPaths, outputDir, reportError, packageManagerKey) with | null -> - errorR(Error(dependencyProvider.CreatePackageManagerUnknownError(tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) + errorR(Error(dependencyProvider.CreatePackageManagerUnknownError(List.map snd tcConfig.compilerToolPaths, outputDir, packageManagerKey, reportError), m)) | dependencyManager -> let directive d = diff --git a/src/fsharp/ScriptClosure.fsi b/src/fsharp/ScriptClosure.fsi index 84059c564df..0f3baf17981 100644 --- a/src/fsharp/ScriptClosure.fsi +++ b/src/fsharp/ScriptClosure.fsi @@ -41,7 +41,7 @@ type LoadClosure = References: (string * AssemblyResolution list) list /// The referenced compiler tools. - CompilerTools: string list + CompilerTools: (range * string) list /// The resolved pacakge references along with the ranges of the #r positions in each file. PackageReferences: (range * string list)[] diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index f7d2f249435..217882abd90 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -583,7 +583,7 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, AbortOnError(errorLogger, exiter) ReportTime tcConfig "Typechecked" - let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) FSharpAnalyzers.RunAnalyzers(analyzers, tcConfig, tcImports, tcGlobals, tcState.Ccu, sourceFiles, tcFileResults, tcEnvAtEnd) diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 30c997a7ad7..fa4352ca1f4 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -813,7 +813,7 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, fsiConsoleOutput.uprintfn """ #help;; // %s""" (FSIstrings.SR.fsiIntroTextHashhelpInfo()) if tcConfigB.langVersion.SupportsFeature(LanguageFeature.PackageManagement) then - for msg in dependencyProvider.GetRegisteredDependencyManagerHelpText(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do + for msg in dependencyProvider.GetRegisteredDependencyManagerHelpText(List.map snd tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m) do fsiConsoleOutput.uprintfn "%s" msg fsiConsoleOutput.uprintfn """ #quit;; // %s""" (FSIstrings.SR.fsiIntroTextHashquitInfo()) (* last thing you want to do, last thing in the list - stands out more *) @@ -1491,9 +1491,9 @@ type internal FsiDynamicCompiler | { Directive=_; LineStatus=_; Line=_; Range=m } :: _ -> let outputDir = tcConfigB.outputDir |> Option.defaultValue "" - match fsiOptions.DependencyProvider.TryFindDependencyManagerByKey(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with + match fsiOptions.DependencyProvider.TryFindDependencyManagerByKey(List.map snd tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, packageManagerKey) with | null -> - errorR(Error(fsiOptions.DependencyProvider.CreatePackageManagerUnknownError(tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) + errorR(Error(fsiOptions.DependencyProvider.CreatePackageManagerUnknownError(List.map snd tcConfigB.compilerToolPaths, outputDir, packageManagerKey, reportError m), m)) istate | dependencyManager -> let directive d = @@ -1543,7 +1543,7 @@ type internal FsiDynamicCompiler ((fun st (m,nm) -> tcConfigB.TurnWarningOff(m,nm); st), (fun st (m, path, directive) -> - let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + let dm = tcImports.DependencyProvider.TryFindDependencyManagerInPath(List.map snd tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) match dm with | _, dependencyManager when not(isNull dependencyManager) -> @@ -1562,7 +1562,7 @@ type internal FsiDynamicCompiler | path, _ -> snd (fsiDynamicCompiler.EvalRequireReference (ctok, st, m, path)) ), - (fun st (_m,nm) -> tcConfigB.AddCompilerToolsByPath(nm); st), + (fun st (m,nm) -> tcConfigB.AddCompilerToolsByPath(m, nm); st), (fun _ _ -> ())) (tcConfigB, inp, Path.GetDirectoryName sourceFile, istate)) @@ -1705,7 +1705,7 @@ type internal FsiDynamicCompiler tcGlobals = tcGlobals tcState = tcState tcImports = tcImports - tcAnalyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + tcAnalyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) ilxGenerator = ilxGenerator boundValues = NameMap.empty timing = false @@ -2177,7 +2177,7 @@ type internal FsiInteractionProcessor /// Execute a single parsed interaction. Called on the GUI/execute/main thread. let ExecInteraction (ctok, tcConfig:TcConfig, istate, action:ParsedScriptInteraction, errorLogger: ErrorLogger) = let packageManagerDirective directive path m = - let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) + let dm = fsiOptions.DependencyProvider.TryFindDependencyManagerInPath(List.map snd tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError m, path) match dm with | null, null -> // error already reported @@ -2244,7 +2244,7 @@ type internal FsiInteractionProcessor if FileSystem.SafeExists(path) then { istate with tcAnalyzers = istate.tcAnalyzers @ FSharpAnalyzers.CreateAnalyzers (path, m) } else - // TODO: give a warning here (or in CreateAnalyzers) + // TODO: give a warning here (or in CreateAnalyzer) istate istate, Completed None diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index 03246aca703..4b4eb541143 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -68,11 +68,10 @@ module FSharpAnalyzers = open FSharp.Compiler.ErrorLogger open FSharp.Core.CompilerServices -#if !NO_EXTENSIONTYPING let CreateAnalyzer (analyzerType: System.Type, m) = if analyzerType.GetConstructor([| typeof |]) <> null then - + let ctxt = FSharpAnalysisContext() try Activator.CreateInstance(analyzerType, [| box ctxt|]) :?> FSharpAnalyzer |> Some @@ -109,12 +108,12 @@ module FSharpAnalyzers = | None -> () | Some a -> a ] - let ImportAnalyzers(tcConfig: TcConfig, m) = + let ImportAnalyzers(tcConfig: TcConfig) = - [ for analyzerPath in tcConfig.compilerToolPaths do + [ for (m, analyzerPath) in tcConfig.compilerToolPaths do if FileSystem.SafeExists(analyzerPath) then yield! CreateAnalyzers (analyzerPath, m) - // TODO: give a warning here (or in CreateAnalyzers) + // TODO: give a warning here (or in CreateAnalyzer) ] let RunAnalyzers(analyzers: FSharpAnalyzer list, tcConfig: TcConfig, tcImports: TcImports, tcGlobals: TcGlobals, tcCcu: CcuThunk, sourceFiles: string list, tcFileResults, tcEnvAtEnd: TcEnv) = @@ -187,10 +186,3 @@ module FSharpAnalyzers = | FSharpDiagnosticSeverity.Info -> warning(exn) | FSharpDiagnosticSeverity.Hidden -> () -#else - - let ImportAnalyzers(tcConfig: TcConfig, g: TcGlobals, m) : FSharpAnalyzer list = - - [ ] - -#endif diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index 42ba700aecb..b26b202d386 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -74,5 +74,5 @@ type public FSharpAnalyzer = module internal FSharpAnalyzers = val CreateAnalyzers: analyzerPath: string * m: range -> FSharpAnalyzer list - val ImportAnalyzers: tcConfig: TcConfig * m: range -> FSharpAnalyzer list + val ImportAnalyzers: tcConfig: TcConfig -> FSharpAnalyzer list val RunAnalyzers: analyzers: FSharpAnalyzer list * tcConfig: TcConfig * tcImports: TcImports * tcGlobals: TcGlobals * tcCcu: CcuThunk * sourceFiles: string list * tcFileResults: (ParsedInput * TypedImplFile option * ModuleOrNamespaceType) list * tcEnvAtEnd: TcEnv -> unit diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index ed47a81d4f0..384b60b4bd1 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1392,8 +1392,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, dllReferences |> List.iter (fun dllReference -> tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text)) tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences - loadClosure.CompilerTools |> List.iter (fun compilerTool -> - tcConfigB.AddCompilerToolsByPath(compilerTool)) + loadClosure.CompilerTools |> List.iter (fun (m, compilerTool) -> + tcConfigB.AddCompilerToolsByPath(m, compilerTool)) | None -> () let tcConfig = TcConfig.Create(tcConfigB, validate=true) @@ -1430,7 +1430,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, for pr in projectReferences do yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] - let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, Range.rangeStartup) + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) let analyzersRequireAssemblyContents = analyzers |> List.exists (fun analyzer -> analyzer.RequiresAssemblyContents) diff --git a/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj b/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj index 1b00b0bd4e0..9cd4e4ec099 100644 --- a/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj +++ b/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj @@ -2,9 +2,8 @@ - net472 + netstandard2.0 true - nunit $(OtherFlags) --nowarn:3390 --nowarn:3218 diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt b/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt new file mode 100644 index 00000000000..eb3e9cfb667 --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt @@ -0,0 +1,16 @@ + +This project tests using the TestAnalyzer in a project context + + +dotnet build tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj -v n + + --> should result in a whole lot of WIBBLE/WAZZAM diagnostics + + +F5 to stat devenv.exe from VisualFSharp.sln + +Then open project tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj + + --> should result in a whole lot of WIBBLE/WAZZAM diagnostics in the IDE + + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj new file mode 100644 index 00000000000..14a540a5dfe --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj @@ -0,0 +1,19 @@ + + + net5.0 + Library + false + + fsc.exe + ..\..\..\artifacts\bin\fsc\Debug\net472 + true + + + + + + + + + + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs b/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs new file mode 100644 index 00000000000..c72bf83810a --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs @@ -0,0 +1,10 @@ + +module M + +let x1 = 1 +let x2 = 1 +let x3 = 1 +let x4 = 1 + +// wibble +// wazzam \ No newline at end of file From 6d899dffab903675f9671c1af7a7f2ff0580ce4d Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 18 Feb 2021 14:50:38 +0000 Subject: [PATCH 16/31] interpret compilerToolPath as a path, not a file --- VisualFSharp.sln | 2 +- src/fsharp/FSComp.txt | 1 + src/fsharp/service/FSharpAnalyzer.fs | 43 +++++++++++++++---- src/fsharp/utils/CompilerLocationUtils.fs | 12 +++--- src/fsharp/utils/CompilerLocationUtils.fsi | 5 ++- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.de.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.es.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.fr.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.it.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ja.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ko.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.pl.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.ru.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.tr.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 +++ src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 +++ .../Analyzer.fs | 2 +- .../Test.Analyzer.fsproj} | 7 +++ .../UsingTestAnalyzerInProject/README.txt | 2 +- .../TestProject.fsproj | 2 +- .../README.txt | 16 +++++++ .../StandardError.txt | 0 .../StandardOutput.txt | 1 + .../TestProject.fsproj | 26 +++++++++++ .../TestProject.sln | 25 +++++++++++ .../test.fs | 10 +++++ 28 files changed, 198 insertions(+), 21 deletions(-) rename tests/service/data/{TestAnalyzer => Test.Analyzer}/Analyzer.fs (97%) rename tests/service/data/{TestAnalyzer/TestAnalyzer.fsproj => Test.Analyzer/Test.Analyzer.fsproj} (59%) create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.fsproj create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln create mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/test.fs diff --git a/VisualFSharp.sln b/VisualFSharp.sln index 614c6d91b3f..173418e9b97 100644 --- a/VisualFSharp.sln +++ b/VisualFSharp.sln @@ -158,7 +158,7 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service", " EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}" EndProject -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestAnalyzer", "tests\service\data\TestAnalyzer\TestAnalyzer.fsproj", "{A341304E-7223-4931-88B5-690EE88C2241}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Test.Analyzer", "tests\service\data\Test.Analyzer\Test.Analyzer.fsproj", "{A341304E-7223-4931-88B5-690EE88C2241}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 791ec85442a..9dd8614e485 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1484,6 +1484,7 @@ notAFunctionButMaybeDeclaration,"This value is not a function and cannot be appl 3245,tcCopyAndUpdateNeedsRecordType,"The input to a copy-and-update expression that creates an anonymous record must be either an anonymous record or a record" 3246,tcAugmentationsCannotHaveAttributes,"Attributes cannot be applied to type extensions." 3247,couldNotLoadDependencyManagerExtension,"The dependency manager extension %s could not be loaded. Message: %s" +3248,couldNotLoadAnalyzerExtension,"The analyzer extension %s could not be loaded. Message: %s" 3250,expressionHasNoName,"Expression does not have a name." 3251,chkNoFirstClassNameOf,"Using the 'nameof' operator as a first-class function value is not permitted." 3252,tcIllegalByrefsInOpenTypeDeclaration,"Byref types are not allowed in an open type declaration." diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index 4b4eb541143..f7d7e3d4a92 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -6,6 +6,7 @@ namespace FSharp.Compiler.CodeAnalysis open System +open System.IO open System.Reflection open System.Threading open Internal.Utilities.Library @@ -18,6 +19,10 @@ open FSharp.Compiler.CheckExpressions open FSharp.Compiler.CompilerImports open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree +open FSharp.Compiler.IO.FileSystemAutoOpens +open FSharp.Compiler.ErrorLogger +open FSharp.Core.CompilerServices +open Internal.Utilities.FSharpEnvironment type FSharpAnalyzerTextChange = Range * string @@ -64,9 +69,27 @@ type public FSharpAnalyzer(context:FSharpAnalysisContext) = default _.RequiresAssemblyContents = false module FSharpAnalyzers = - open FSharp.Compiler.IO.FileSystemAutoOpens - open FSharp.Compiler.ErrorLogger - open FSharp.Core.CompilerServices + + let fsharpAnalyzerPattern = "*.Analyzer.dll" + + let assemblyHasAttribute (theAssembly: Assembly) attributeName = + try + CustomAttributeExtensions.GetCustomAttributes(theAssembly) + |> Seq.exists (fun a -> a.GetType().Name = attributeName) + with | _ -> false + + let stripTieWrapper (e:Exception) = + match e with + | :? TargetInvocationException as e-> + e.InnerException + | _ -> e + + let enumerateAnalyzerAssemblies (compilerToolPaths: (range * string) list) = + [ for m, compilerToolPath in compilerToolPaths do + for path in searchToolPath compilerToolPath do + if Directory.Exists(path) then + for filePath in Directory.EnumerateFiles(path, fsharpAnalyzerPattern) do + yield (m, filePath) ] let CreateAnalyzer (analyzerType: System.Type, m) = @@ -91,14 +114,17 @@ module FSharpAnalyzers = errorR (Error(FSComp.SR.etAnalyzerDoesNotHaveValidConstructor(analyzerType.FullName), m)) None - let CreateAnalyzers (analyzerPath, m:range) = + let CreateAnalyzers (analyzerPath: string, m:range) = let analyzerAssembly = try - Assembly.UnsafeLoadFrom analyzerPath + Some (Assembly.UnsafeLoadFrom analyzerPath) with exn -> - error (Error(FSComp.SR.etAnalyzerLoadFailure(analyzerPath, exn.ToString()), m)) - + warning (Error(FSComp.SR.etAnalyzerLoadFailure(analyzerPath, exn.ToString()), m)) + None + match analyzerAssembly with + | None -> [] + | Some analyzerAssembly -> [ if analyzerAssembly.GetCustomAttribute(typeof) <> null then let exportedTypes = analyzerAssembly.GetExportedTypes() for t in exportedTypes do @@ -109,8 +135,7 @@ module FSharpAnalyzers = | Some a -> a ] let ImportAnalyzers(tcConfig: TcConfig) = - - [ for (m, analyzerPath) in tcConfig.compilerToolPaths do + [ for (m, analyzerPath) in enumerateAnalyzerAssemblies tcConfig.compilerToolPaths do if FileSystem.SafeExists(analyzerPath) then yield! CreateAnalyzers (analyzerPath, m) // TODO: give a warning here (or in CreateAnalyzer) diff --git a/src/fsharp/utils/CompilerLocationUtils.fs b/src/fsharp/utils/CompilerLocationUtils.fs index 04c27204330..b2375417d76 100644 --- a/src/fsharp/utils/CompilerLocationUtils.fs +++ b/src/fsharp/utils/CompilerLocationUtils.fs @@ -267,14 +267,14 @@ module internal FSharpEnvironment = yield Path.Combine(toolPath, protocol, netRuntime) ] + let searchToolPath compilerToolPath = + seq { + yield compilerToolPath + for toolPath in toolingCompatiblePaths() do + yield Path.Combine (compilerToolPath, toolPath) + } let rec searchToolPaths path compilerToolPaths = seq { - let searchToolPath path = - seq { - yield path - for toolPath in toolingCompatiblePaths() do - yield Path.Combine (path, toolPath) - } for toolPath in compilerToolPaths do yield! searchToolPath toolPath diff --git a/src/fsharp/utils/CompilerLocationUtils.fsi b/src/fsharp/utils/CompilerLocationUtils.fsi index c044f82f2ce..551e38b1305 100644 --- a/src/fsharp/utils/CompilerLocationUtils.fsi +++ b/src/fsharp/utils/CompilerLocationUtils.fsi @@ -29,8 +29,9 @@ module internal FSharpEnvironment = val toolingCompatiblePaths: unit -> string list - val searchToolPaths: - path:string option -> compilerToolPaths:seq -> seq + val searchToolPath: compilerToolPath:string -> seq + + val searchToolPaths: path:string option -> compilerToolPaths:seq -> seq val getTypeProviderAssembly: runTimeAssemblyFileName:string * diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 4100bc30562..6817172de42 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Dostupná přetížení:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 4d4418e24d7..8195503d341 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Verfügbare Überladungen:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 66c02bb1902..02ed6ec5d5e 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Sobrecargas disponibles:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 453a9a315e0..737c5acd35b 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Surcharges disponibles :\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 724ba2d2178..792a8037e5d 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Overload disponibili:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 781061328a6..349f0f470b1 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} 使用可能なオーバーロード:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index dae534f3bf6..8e7542ca61b 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} 사용 가능한 오버로드:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 0d203a7657a..568be3b2f92 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Dostępne przeciążenia:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index 0dd19f919f4..e209b54835c 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Sobrecargas disponíveis:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index c7ce19affb6..77d58233fce 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Доступные перегрузки:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 84de83a89a5..e966c5361e9 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} Kullanılabilir aşırı yüklemeler:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 1d2a6ca3c2e..5828a1c2d12 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} 可用重载:\n{0} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 1c625f07f4b..45ad752b4e2 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -27,6 +27,11 @@ Key container signing is not supported on this platform. + + The analyzer extension {0} could not be loaded. Message: {1} + The analyzer extension {0} could not be loaded. Message: {1} + + Available overloads:\n{0} 可用的多載:\n{0} diff --git a/tests/service/data/TestAnalyzer/Analyzer.fs b/tests/service/data/Test.Analyzer/Analyzer.fs similarity index 97% rename from tests/service/data/TestAnalyzer/Analyzer.fs rename to tests/service/data/Test.Analyzer/Analyzer.fs index a73ed4a12a0..fa2c628dca0 100644 --- a/tests/service/data/TestAnalyzer/Analyzer.fs +++ b/tests/service/data/Test.Analyzer/Analyzer.fs @@ -1,4 +1,4 @@ -namespace TestAnalyzer +namespace Test.Analyzer open FSharp.Core.CompilerServices open FSharp.Compiler.CodeAnalysis diff --git a/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj b/tests/service/data/Test.Analyzer/Test.Analyzer.fsproj similarity index 59% rename from tests/service/data/TestAnalyzer/TestAnalyzer.fsproj rename to tests/service/data/Test.Analyzer/Test.Analyzer.fsproj index 9cd4e4ec099..fae8dff2ecd 100644 --- a/tests/service/data/TestAnalyzer/TestAnalyzer.fsproj +++ b/tests/service/data/Test.Analyzer/Test.Analyzer.fsproj @@ -5,9 +5,16 @@ netstandard2.0 true $(OtherFlags) --nowarn:3390 --nowarn:3218 + $(FSCoreUnitTestsPackageVersion) + true + true + + + tools/fsharp41/$(TargetFramework)/Test.Analyzer.dll + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt b/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt index eb3e9cfb667..17c7e3257c4 100644 --- a/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/README.txt @@ -1,5 +1,5 @@ -This project tests using the TestAnalyzer in a project context +This project tests using the Test.Analyzer in a project context dotnet build tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj -v n diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj index 14a540a5dfe..6c0302d850a 100644 --- a/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj @@ -13,7 +13,7 @@ - + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt new file mode 100644 index 00000000000..17c7e3257c4 --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt @@ -0,0 +1,16 @@ + +This project tests using the Test.Analyzer in a project context + + +dotnet build tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj -v n + + --> should result in a whole lot of WIBBLE/WAZZAM diagnostics + + +F5 to stat devenv.exe from VisualFSharp.sln + +Then open project tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj + + --> should result in a whole lot of WIBBLE/WAZZAM diagnostics in the IDE + + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt new file mode 100644 index 00000000000..b1e76861e73 --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt @@ -0,0 +1 @@ +5.0.103 diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.fsproj b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.fsproj new file mode 100644 index 00000000000..c6ff712a1a0 --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.fsproj @@ -0,0 +1,26 @@ + + + net5.0 + Library + false + + fsc.exe + ..\..\..\artifacts\bin\fsc\Debug\net472 + true + + https://api.nuget.org/v3/index.json + + + $(RestoreSources);../../../artifacts/packages/$(Configuration)/Shipping + + + + + + + + true + + + + diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln new file mode 100644 index 00000000000..8a3181cd8ce --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31005.135 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestProject", "TestProject.fsproj", "{383B1AA6-AB09-4AB8-B333-20624A3E141F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2B656675-9778-43CE-855E-1EA7E310FD43} + EndGlobalSection +EndGlobal diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/test.fs b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/test.fs new file mode 100644 index 00000000000..c72bf83810a --- /dev/null +++ b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/test.fs @@ -0,0 +1,10 @@ + +module M + +let x1 = 1 +let x2 = 1 +let x3 = 1 +let x4 = 1 + +// wibble +// wazzam \ No newline at end of file From 647f820af21b5beadfb9dd52be11648a6ba4cce9 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 18 Feb 2021 14:51:19 +0000 Subject: [PATCH 17/31] interpret compilerToolPath as a path, not a file --- .../README.txt | 16 ------------ .../StandardError.txt | 0 .../StandardOutput.txt | 1 - .../TestProject.sln | 25 ------------------- 4 files changed, 42 deletions(-) delete mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt delete mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt delete mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt delete mode 100644 tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt deleted file mode 100644 index 17c7e3257c4..00000000000 --- a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/README.txt +++ /dev/null @@ -1,16 +0,0 @@ - -This project tests using the Test.Analyzer in a project context - - -dotnet build tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj -v n - - --> should result in a whole lot of WIBBLE/WAZZAM diagnostics - - -F5 to stat devenv.exe from VisualFSharp.sln - -Then open project tests\walkthroughs\UsingTestAnalyzerInProject\TestProject.fsproj - - --> should result in a whole lot of WIBBLE/WAZZAM diagnostics in the IDE - - diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardError.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt deleted file mode 100644 index b1e76861e73..00000000000 --- a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/StandardOutput.txt +++ /dev/null @@ -1 +0,0 @@ -5.0.103 diff --git a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln b/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln deleted file mode 100644 index 8a3181cd8ce..00000000000 --- a/tests/walkthroughs/UsingTestAnalyzerInProjectViaPackage/TestProject.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31005.135 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestProject", "TestProject.fsproj", "{383B1AA6-AB09-4AB8-B333-20624A3E141F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {383B1AA6-AB09-4AB8-B333-20624A3E141F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2B656675-9778-43CE-855E-1EA7E310FD43} - EndGlobalSection -EndGlobal From 534226e9bb3edc1f5b04994f6255aefdf27ffc21 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 25 Feb 2021 13:42:55 +0000 Subject: [PATCH 18/31] better incrementality for analyzers --- src/fsharp/CompilerConfig.fs | 11 +- src/fsharp/CompilerDiagnostics.fs | 34 +-- src/fsharp/CompilerDiagnostics.fsi | 8 +- src/fsharp/CompilerOptions.fs | 9 +- src/fsharp/CompilerOptions.fsi | 3 +- src/fsharp/Diagnostics.fs | 7 + src/fsharp/Diagnostics.fsi | 7 + src/fsharp/ErrorLogger.fs | 49 ++-- src/fsharp/ErrorLogger.fsi | 11 +- src/fsharp/FSComp.txt | 1 + src/fsharp/LegacyHostedCompilerForTesting.fs | 9 +- src/fsharp/ParseAndCheckInputs.fs | 32 ++- src/fsharp/ParseAndCheckInputs.fsi | 9 +- src/fsharp/ScriptClosure.fs | 20 +- src/fsharp/ScriptClosure.fsi | 11 +- src/fsharp/SyntaxTree.fs | 1 + src/fsharp/fsc.fs | 48 ++-- src/fsharp/fsi/fsi.fs | 39 ++-- src/fsharp/infos.fs | 8 +- src/fsharp/service/FSharpAnalyzer.fs | 138 ++++++----- src/fsharp/service/FSharpAnalyzer.fsi | 42 ++-- src/fsharp/service/FSharpCheckerResults.fs | 57 ++--- src/fsharp/service/FSharpCheckerResults.fsi | 13 +- src/fsharp/service/FSharpParseFileResults.fs | 217 ++++++++---------- src/fsharp/service/FSharpParseFileResults.fsi | 7 +- src/fsharp/service/IncrementalBuild.fs | 113 +++++---- src/fsharp/service/IncrementalBuild.fsi | 15 +- src/fsharp/service/ServiceParsedInputOps.fs | 27 +-- src/fsharp/service/ServiceParsedInputOps.fsi | 6 +- src/fsharp/service/ServiceXmlDocParser.fs | 9 +- src/fsharp/service/ServiceXmlDocParser.fsi | 2 +- src/fsharp/service/service.fs | 122 +++++----- src/fsharp/service/service.fsi | 6 +- src/fsharp/symbols/Exprs.fsi | 2 + src/fsharp/symbols/SymbolHelpers.fs | 41 ++-- src/fsharp/symbols/SymbolHelpers.fsi | 19 +- src/fsharp/symbols/Symbols.fs | 10 +- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 + src/fsharp/xlf/FSComp.txt.de.xlf | 5 + src/fsharp/xlf/FSComp.txt.es.xlf | 5 + src/fsharp/xlf/FSComp.txt.fr.xlf | 5 + src/fsharp/xlf/FSComp.txt.it.xlf | 5 + src/fsharp/xlf/FSComp.txt.ja.xlf | 5 + src/fsharp/xlf/FSComp.txt.ko.xlf | 5 + src/fsharp/xlf/FSComp.txt.pl.xlf | 5 + src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 + src/fsharp/xlf/FSComp.txt.ru.xlf | 5 + src/fsharp/xlf/FSComp.txt.tr.xlf | 5 + src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 + src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 + .../SurfaceArea.netstandard.fs | 18 +- .../HashIfExpression.fs | 3 +- tests/FSharp.Test.Utilities/CompilerAssert.fs | 6 +- tests/service/Common.fs | 5 +- tests/service/InteractiveCheckerTests.fs | 4 +- tests/service/ServiceUntypedParseTests.fs | 4 +- tests/service/StructureTests.fs | 5 +- tests/service/Symbols.fs | 18 +- tests/service/TreeVisitorTests.fs | 5 +- tests/service/data/Test.Analyzer/Analyzer.fs | 25 +- .../TestProject.fsproj | 1 + .../UsingTestAnalyzerInProject/test.fs | 12 +- .../CodeFix/RemoveUnusedOpens.fs | 2 +- .../Commands/XmlDocCommandService.fs | 2 +- .../src/FSharp.Editor/Common/RoslynHelpers.fs | 7 +- .../Completion/CompletionProvider.fs | 6 +- .../Diagnostics/DocumentDiagnosticAnalyzer.fs | 62 ++--- .../UnusedOpensDiagnosticAnalyzer.fs | 12 +- .../DocComments/XMLDocumentation.fs | 8 +- .../FSharpCheckerExtensions.fs | 6 +- .../Navigation/NavigateToSearchService.fs | 4 +- .../src/FSharp.Editor/QuickInfo/Navigation.fs | 3 +- .../QuickInfo/QuickInfoProvider.fs | 6 +- 73 files changed, 794 insertions(+), 658 deletions(-) diff --git a/src/fsharp/CompilerConfig.fs b/src/fsharp/CompilerConfig.fs index c4633de9eec..75dbe140287 100644 --- a/src/fsharp/CompilerConfig.fs +++ b/src/fsharp/CompilerConfig.fs @@ -774,11 +774,14 @@ type TcConfigBuilder = member tcConfigB.AddCompilerToolsByPath (m, path) = if FileSystem.IsInvalidPathShim path then - warning(Error(FSComp.SR.buildInvalidAssemblyName(path), m)) + warning(Error(FSComp.SR.etCompilerToolPathDidntExist(path), m)) // TODO: check this is the right place to resolve paths - let rootedPath = if Path.IsPathRooted(path) then path else Path.Combine(tcConfigB.implicitIncludeDir, path) - if not (tcConfigB.compilerToolPaths |> List.exists (fun (_m, text) -> rootedPath = text)) then - tcConfigB.compilerToolPaths <- tcConfigB.compilerToolPaths ++ (m, rootedPath) + else + let rootedPath = if Path.IsPathRooted(path) then path else Path.Combine(tcConfigB.implicitIncludeDir, path) + if not (Directory.Exists rootedPath) then + warning(Error(FSComp.SR.etCompilerToolPathDidntExist(rootedPath), m)) + elif not (tcConfigB.compilerToolPaths |> List.exists (fun (_m, text) -> rootedPath = text)) then + tcConfigB.compilerToolPaths <- tcConfigB.compilerToolPaths ++ (m, rootedPath) member tcConfigB.AddReferencedAssemblyByPath (m, path) = if FileSystem.IsInvalidPathShim path then diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index 0ecc8da47c3..03e582e17d8 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -1712,11 +1712,11 @@ type DiagnosticDetailedInfo = [] type Diagnostic = - | Short of bool * string - | Long of bool * DiagnosticDetailedInfo + | Short of FSharpDiagnosticSeverity * string + | Long of FSharpDiagnosticSeverity * DiagnosticDetailedInfo /// returns sequence that contains Diagnostic for the given error + Diagnostic for all related errors -let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError, err: PhasedDiagnostic, suggestNames: bool) = +let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, severity: FSharpDiagnosticSeverity, err: PhasedDiagnostic, suggestNames: bool) = let outputWhere (showFullPaths, errorStyle) m: DiagnosticLocation = if Range.equals m rangeStartup || Range.equals m rangeCmdArgs then { Range = m; TextRepresentation = ""; IsEmpty = true; File = "" } @@ -1777,11 +1777,17 @@ let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorSt | None -> None let OutputCanonicalInformation(subcategory, errorNumber) : DiagnosticCanonicalInformation = + let message = + match severity with + | FSharpDiagnosticSeverity.Error -> "error" + | FSharpDiagnosticSeverity.Warning -> "warning" + | FSharpDiagnosticSeverity.Info + | FSharpDiagnosticSeverity.Hidden -> "info" let text = match errorStyle with // Show the subcategory for --vserrors so that we can fish it out in Visual Studio and use it to determine error stickiness. - | ErrorStyle.VSErrors -> sprintf "%s %s FS%04d: " subcategory (if isError then "error" else "warning") errorNumber - | _ -> sprintf "%s FS%04d: " (if isError then "error" else "warning") errorNumber + | ErrorStyle.VSErrors -> sprintf "%s %s FS%04d: " subcategory message errorNumber + | _ -> sprintf "%s FS%04d: " message errorNumber { ErrorNumber = errorNumber; Subcategory = subcategory; TextRepresentation = text} let mainError, relatedErrors = SplitRelatedDiagnostics err @@ -1794,7 +1800,7 @@ let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorSt let entry: DiagnosticDetailedInfo = { Location = where; Canonical = canonical; Message = message } - errors.Add ( Diagnostic.Long(isError, entry ) ) + errors.Add ( Diagnostic.Long(severity, entry ) ) let OutputRelatedError(err: PhasedDiagnostic) = match errorStyle with @@ -1808,12 +1814,12 @@ let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorSt os.ToString() let entry: DiagnosticDetailedInfo = { Location = relWhere; Canonical = relCanonical; Message = relMessage} - errors.Add( Diagnostic.Long (isError, entry) ) + errors.Add( Diagnostic.Long (severity, entry) ) | _ -> let os = System.Text.StringBuilder() OutputPhasedDiagnostic os err flattenErrors suggestNames - errors.Add( Diagnostic.Short(isError, os.ToString()) ) + errors.Add( Diagnostic.Short(severity, os.ToString()) ) relatedErrors |> List.iter OutputRelatedError @@ -1831,10 +1837,10 @@ let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorSt /// used by fsc.exe and fsi.exe, but not by VS /// prints error and related errors to the specified StringBuilder -let rec OutputDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError) os (err: PhasedDiagnostic) = +let rec OutputDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, severity) os (err: PhasedDiagnostic) = // 'true' for "canSuggestNames" is passed last here because we want to report suggestions in fsc.exe and fsi.exe, just not in regular IDE usage. - let errors = CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError, err, true) + let errors = CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, severity, err, true) for e in errors do Printf.bprintf os "\n" match e with @@ -1886,9 +1892,9 @@ let ReportWarningAsError options err = type ErrorLoggerFilteringByScopedPragmas (checkFile, scopedPragmas, errorLogger: ErrorLogger) = inherit ErrorLogger("ErrorLoggerFilteringByScopedPragmas") - override x.DiagnosticSink (phasedError, isError) = - if isError then - errorLogger.DiagnosticSink (phasedError, isError) + override x.DiagnosticSink (phasedError, severity) = + if severity = FSharpDiagnosticSeverity.Error then + errorLogger.DiagnosticSink (phasedError, severity) else let report = let warningNum = GetDiagnosticNumber phasedError @@ -1901,7 +1907,7 @@ type ErrorLoggerFilteringByScopedPragmas (checkFile, scopedPragmas, errorLogger: (not checkFile || m.FileIndex = pragmaRange.FileIndex) && Position.posGeq m.Start pragmaRange.Start)) | None -> true - if report then errorLogger.DiagnosticSink(phasedError, false) + if report then errorLogger.DiagnosticSink(phasedError, severity) override x.ErrorCount = errorLogger.ErrorCount diff --git a/src/fsharp/CompilerDiagnostics.fsi b/src/fsharp/CompilerDiagnostics.fsi index bc60b6c6ad8..3eb231abf97 100644 --- a/src/fsharp/CompilerDiagnostics.fsi +++ b/src/fsharp/CompilerDiagnostics.fsi @@ -60,7 +60,7 @@ val SplitRelatedDiagnostics: PhasedDiagnostic -> PhasedDiagnostic * PhasedDiagno val OutputPhasedDiagnostic: StringBuilder -> PhasedDiagnostic -> flattenErrors: bool -> suggestNames: bool -> unit /// Output an error or warning to a buffer -val OutputDiagnostic: implicitIncludeDir:string * showFullPaths: bool * flattenErrors: bool * errorStyle: ErrorStyle * isError:bool -> StringBuilder -> PhasedDiagnostic -> unit +val OutputDiagnostic: implicitIncludeDir:string * showFullPaths: bool * flattenErrors: bool * errorStyle: ErrorStyle * severity: FSharpDiagnosticSeverity -> StringBuilder -> PhasedDiagnostic -> unit /// Output extra context information for an error or warning to a buffer val OutputDiagnosticContext: prefix:string -> fileLineFunction:(string -> int -> string) -> StringBuilder -> PhasedDiagnostic -> unit @@ -90,11 +90,11 @@ type DiagnosticDetailedInfo = /// Part of LegacyHostedCompilerForTesting [] type Diagnostic = - | Short of bool * string - | Long of bool * DiagnosticDetailedInfo + | Short of FSharpDiagnosticSeverity * string + | Long of FSharpDiagnosticSeverity * DiagnosticDetailedInfo /// Part of LegacyHostedCompilerForTesting -val CollectDiagnostic: implicitIncludeDir:string * showFullPaths: bool * flattenErrors: bool * errorStyle: ErrorStyle * isError:bool * PhasedDiagnostic * suggestNames: bool -> seq +val CollectDiagnostic: implicitIncludeDir:string * showFullPaths: bool * flattenErrors: bool * errorStyle: ErrorStyle * severity: FSharpDiagnosticSeverity * PhasedDiagnostic * suggestNames: bool -> seq /// Get an error logger that filters the reporting of warnings based on scoped pragma information val GetErrorLoggerFilteringByScopedPragmas: checkFile:bool * ScopedPragma list * ErrorLogger -> ErrorLogger diff --git a/src/fsharp/CompilerOptions.fs b/src/fsharp/CompilerOptions.fs index 1c458197c36..8531fc253af 100644 --- a/src/fsharp/CompilerOptions.fs +++ b/src/fsharp/CompilerOptions.fs @@ -1717,11 +1717,16 @@ let DoWithColor newColor f = finally ignoreFailureOnMono1_1_16 (fun () -> Console.ForegroundColor <- c) -let DoWithErrorColor isError f = +let DoWithDiagnosticColor severity f = match foreBackColor() with | None -> f() | Some (_, backColor) -> + let infoColor = if backColor = ConsoleColor.White then ConsoleColor.Blue else ConsoleColor.Green let warnColor = if backColor = ConsoleColor.White then ConsoleColor.DarkBlue else ConsoleColor.Cyan let errorColor = ConsoleColor.Red - let color = if isError then errorColor else warnColor + let color = + match severity with + | FSharpDiagnosticSeverity.Error -> errorColor + | FSharpDiagnosticSeverity.Warning -> warnColor + | _ -> infoColor DoWithColor color f diff --git a/src/fsharp/CompilerOptions.fsi b/src/fsharp/CompilerOptions.fsi index 2b1c1d9e2be..11e44719384 100644 --- a/src/fsharp/CompilerOptions.fsi +++ b/src/fsharp/CompilerOptions.fsi @@ -5,6 +5,7 @@ module internal FSharp.Compiler.CompilerOptions open System open FSharp.Compiler.CompilerConfig +open FSharp.Compiler.Diagnostics // For command-line options that can be suffixed with +/- [] @@ -76,7 +77,7 @@ val mutable enableConsoleColoring : bool val DoWithColor : ConsoleColor -> (unit -> 'a) -> 'a -val DoWithErrorColor : bool -> (unit -> 'a) -> 'a +val DoWithDiagnosticColor : FSharpDiagnosticSeverity -> (unit -> 'a) -> 'a val ReportTime : TcConfig -> string -> unit diff --git a/src/fsharp/Diagnostics.fs b/src/fsharp/Diagnostics.fs index 62fbc310a0f..8dc12c04402 100644 --- a/src/fsharp/Diagnostics.fs +++ b/src/fsharp/Diagnostics.fs @@ -5,6 +5,13 @@ // F# compiler. namespace FSharp.Compiler.Diagnostics +[] +type FSharpDiagnosticSeverity = + | Hidden + | Info + | Warning + | Error + type public FSharpDiagnosticOptions = { WarnLevel: int diff --git a/src/fsharp/Diagnostics.fsi b/src/fsharp/Diagnostics.fsi index dc112138146..b1dc86be20b 100644 --- a/src/fsharp/Diagnostics.fsi +++ b/src/fsharp/Diagnostics.fsi @@ -6,6 +6,13 @@ namespace FSharp.Compiler.Diagnostics +[] +type FSharpDiagnosticSeverity = + | Hidden + | Info + | Warning + | Error + type FSharpDiagnosticOptions = { WarnLevel: int GlobalWarnAsError: bool diff --git a/src/fsharp/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index 0602c668d95..e23d673830a 100644 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -2,6 +2,7 @@ module FSharp.Compiler.ErrorLogger +open FSharp.Compiler.Diagnostics open FSharp.Compiler.Features open FSharp.Compiler.Text.Range open FSharp.Compiler.Text @@ -276,18 +277,18 @@ type ErrorLogger(nameForDebugging:string) = abstract ErrorCount: int // The 'Impl' factoring enables a developer to place a breakpoint at the non-Impl // code just below and get a breakpoint for all error logger implementations. - abstract DiagnosticSink: phasedError: PhasedDiagnostic * isError: bool -> unit + abstract DiagnosticSink: phasedError: PhasedDiagnostic * severity: FSharpDiagnosticSeverity -> unit member _.DebugDisplay() = sprintf "ErrorLogger(%s)" nameForDebugging let DiscardErrorsLogger = { new ErrorLogger("DiscardErrorsLogger") with - member x.DiagnosticSink(phasedError, isError) = () + member x.DiagnosticSink(phasedError, severity) = () member x.ErrorCount = 0 } let AssertFalseErrorLogger = { new ErrorLogger("AssertFalseErrorLogger") with // TODO: reenable these asserts in the compiler service - member x.DiagnosticSink(phasedError, isError) = (* assert false; *) () + member x.DiagnosticSink(phasedError, severity) = (* assert false; *) () member x.ErrorCount = (* assert false; *) 0 } @@ -295,17 +296,20 @@ type CapturingErrorLogger(nm) = inherit ErrorLogger(nm) let mutable errorCount = 0 let diagnostics = ResizeArray() - override x.DiagnosticSink(phasedError, isError) = - if isError then errorCount <- errorCount + 1 - diagnostics.Add (phasedError, isError) + + override x.DiagnosticSink(phasedError, severity) = + if severity = FSharpDiagnosticSeverity.Error then errorCount <- errorCount + 1 + diagnostics.Add (phasedError, severity) + override x.ErrorCount = errorCount + member x.Diagnostics = diagnostics |> Seq.toList + member x.CommitDelayedDiagnostics(errorLogger:ErrorLogger) = // Eagerly grab all the errors and warnings from the mutable collection let errors = diagnostics.ToArray() errors |> Array.iter errorLogger.DiagnosticSink - /// Type holds thread-static globals for use by the compile. type internal CompileThreadStatic = [] @@ -370,7 +374,7 @@ module ErrorLoggerExtensions = type ErrorLogger with - member x.ErrorR exn = + member x.EmitDiagnostic (exn, severity) = match exn with | InternalError (s, _) | Failure s as exn -> System.Diagnostics.Debug.Assert(false, sprintf "Unexpected exception raised in compiler: %s\n%s" s (exn.ToString())) @@ -381,22 +385,20 @@ module ErrorLoggerExtensions = | ReportedError _ -> PreserveStackTrace exn raise exn - | _ -> x.DiagnosticSink(PhasedDiagnostic.Create(exn, CompileThreadStatic.BuildPhase), true) + | _ -> x.DiagnosticSink(PhasedDiagnostic.Create(exn, CompileThreadStatic.BuildPhase), severity) + + member x.ErrorR exn = + x.EmitDiagnostic (exn, FSharpDiagnosticSeverity.Error) member x.Warning exn = - match exn with - | StopProcessing - | ReportedError _ -> - PreserveStackTrace exn - raise exn - | _ -> x.DiagnosticSink(PhasedDiagnostic.Create(exn, CompileThreadStatic.BuildPhase), false) + x.EmitDiagnostic (exn, FSharpDiagnosticSeverity.Warning) - member x.Error exn = - x.ErrorR exn + member x.Error exn = + x.EmitDiagnostic (exn, FSharpDiagnosticSeverity.Error) raise (ReportedError (Some exn)) - member x.SimulateError (ph: PhasedDiagnostic) = - x.DiagnosticSink (ph, true) + member x.SimulateError (ph: PhasedDiagnostic) = + x.DiagnosticSink (ph, FSharpDiagnosticSeverity.Error) raise (ReportedError (Some ph.Exception)) member x.ErrorRecovery (exn: exn) (m: range) = @@ -471,17 +473,20 @@ let errorR exn = CompileThreadStatic.ErrorLogger.ErrorR exn /// Raises a warning with error recovery and returns unit. let warning exn = CompileThreadStatic.ErrorLogger.Warning exn +/// Raises a warning with error recovery and returns unit. +let diagnostic (exn, severity) = CompileThreadStatic.ErrorLogger.EmitDiagnostic (exn, severity) + /// Raises a special exception and returns 'T - can be caught later at an errorRecovery point. let error exn = CompileThreadStatic.ErrorLogger.Error exn /// Simulates an error. For test purposes only. let simulateError (p : PhasedDiagnostic) = CompileThreadStatic.ErrorLogger.SimulateError p -let diagnosticSink (phasedError, isError) = CompileThreadStatic.ErrorLogger.DiagnosticSink (phasedError, isError) +let diagnosticSink (phasedError, severity) = CompileThreadStatic.ErrorLogger.DiagnosticSink (phasedError, severity) -let errorSink pe = diagnosticSink (pe, true) +let errorSink pe = diagnosticSink (pe, FSharpDiagnosticSeverity.Error) -let warnSink pe = diagnosticSink (pe, false) +let warnSink pe = diagnosticSink (pe, FSharpDiagnosticSeverity.Warning) let errorRecovery exn m = CompileThreadStatic.ErrorLogger.ErrorRecovery exn m diff --git a/src/fsharp/ErrorLogger.fsi b/src/fsharp/ErrorLogger.fsi index b578ae5ac66..8a6d1ce0723 100644 --- a/src/fsharp/ErrorLogger.fsi +++ b/src/fsharp/ErrorLogger.fsi @@ -3,6 +3,7 @@ module internal FSharp.Compiler.ErrorLogger open System +open FSharp.Compiler.Diagnostics open FSharp.Compiler.Features open FSharp.Compiler.Text @@ -140,7 +141,7 @@ type ErrorLogger = member DebugDisplay: unit -> string - abstract member DiagnosticSink: phasedError:PhasedDiagnostic * isError:bool -> unit + abstract member DiagnosticSink: phasedError:PhasedDiagnostic * severity:FSharpDiagnosticSeverity -> unit abstract member ErrorCount: int @@ -155,9 +156,9 @@ type CapturingErrorLogger = member CommitDelayedDiagnostics: errorLogger:ErrorLogger -> unit - override DiagnosticSink: phasedError:PhasedDiagnostic * isError:bool -> unit + override DiagnosticSink: phasedError:PhasedDiagnostic * severity:FSharpDiagnosticSeverity -> unit - member Diagnostics: (PhasedDiagnostic * bool) list + member Diagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list override ErrorCount: int @@ -204,11 +205,13 @@ val errorR: exn:exn -> unit val warning: exn:exn -> unit +val diagnostic: exn:exn * severity: FSharpDiagnosticSeverity -> unit + val error: exn:exn -> 'a val simulateError: p:PhasedDiagnostic -> 'a -val diagnosticSink: phasedError:PhasedDiagnostic * isError:bool -> unit +val diagnosticSink: phasedError:PhasedDiagnostic * severity: FSharpDiagnosticSeverity -> unit val errorSink: pe:PhasedDiagnostic -> unit diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 9dd8614e485..b563d63d5df 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1533,6 +1533,7 @@ featureInterfacesWithMultipleGenericInstantiation,"interfaces with multiple gene 3367,etAnalyzerConstructionException,"The analyzer '%s' raised an exception during analyzer construction: '%s'." 3368,etAnalyzerTypeInitializationException,"The analyzer '%s' raised an exception during analyzer type initialization: '%s'." 3369,etAnalyzerException,"The analyzer '%s' raised an exception during analysis of file '%s': '%s'." +3370,etCompilerToolPathDidntExist,"The compiler tool path '%s' did not exist." forFormatInvalidForInterpolated,"Interpolated strings may not use '%%' format specifiers unless each is given an expression, e.g. '%%d{{1+1}}'." forFormatInvalidForInterpolated2,".NET-style format specifiers such as '{{x,3}}' or '{{x:N5}}' may not be mixed with '%%' format specifiers." forFormatInvalidForInterpolated3,"The '%%P' specifier may not be used explicitly." diff --git a/src/fsharp/LegacyHostedCompilerForTesting.fs b/src/fsharp/LegacyHostedCompilerForTesting.fs index ced4f14db2a..480eb2612d1 100644 --- a/src/fsharp/LegacyHostedCompilerForTesting.fs +++ b/src/fsharp/LegacyHostedCompilerForTesting.fs @@ -8,6 +8,7 @@ namespace FSharp.Compiler.CodeAnalysis.Hosted open System open System.IO open System.Text.RegularExpressions +open FSharp.Compiler.Diagnostics open FSharp.Compiler.Driver open FSharp.Compiler.ErrorLogger open FSharp.Compiler.CompilerConfig @@ -90,16 +91,16 @@ type internal FscCompiler(legacyReferenceResolver) = /// converts short and long issue types to the same CompilationIssue representation let convert issue : CompilationIssue = match issue with - | Diagnostic.Short(isError, text) -> + | Diagnostic.Short(severity, text) -> { Location = emptyLocation Code = "" Subcategory = "" File = "" Text = text - Type = if isError then CompilationIssueType.Error else CompilationIssueType.Warning + Type = if (severity = FSharpDiagnosticSeverity.Error) then CompilationIssueType.Error else CompilationIssueType.Warning } - | Diagnostic.Long(isError, details) -> + | Diagnostic.Long(severity, details) -> let loc, file = match details.Location with | Some l when not l.IsEmpty -> @@ -116,7 +117,7 @@ type internal FscCompiler(legacyReferenceResolver) = Subcategory = details.Canonical.Subcategory File = file Text = details.Message - Type = if isError then CompilationIssueType.Error else CompilationIssueType.Warning + Type = if (severity = FSharpDiagnosticSeverity.Error) then CompilationIssueType.Error else CompilationIssueType.Warning } /// test if --test:ErrorRanges flag is set diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index ba048a6d1e6..4e1af1136c8 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -320,6 +320,32 @@ let ReportParsingStatistics res = | ParsedInput.ImplFile (ParsedImplFileInput (modules = impls)) -> printfn "parsing yielded %d definitions" (List.collect flattenModImpl impls).Length +let EmptyParsedInput(filename, isLastCompiland) = + let lower = String.lowercase filename + if FSharpSigFileSuffixes |> List.exists (Filename.checkSuffix lower) then + ParsedInput.SigFile( + ParsedSigFileInput( + filename, + QualFileNameOfImpls filename [], + [], + [], + [] + ) + ) + else + ParsedInput.ImplFile( + ParsedImplFileInput( + filename, + false, + QualFileNameOfImpls filename [], + [], + [], + [], + isLastCompiland + ) + ) + + /// Parse an input, drawing tokens from the LexBuffer let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, lexbuf, filename, isLastCompiland, errorLogger) = use unwindbuildphase = PushThreadBuildPhaseUntilUnwind BuildPhase.Parse @@ -360,11 +386,11 @@ let ParseOneInputLexbuf (tcConfig: TcConfig, lexResourceManager, conditionalComp res ) - Some input + input with e -> errorRecovery e rangeStartup - None + EmptyParsedInput(filename, isLastCompiland) let ValidSuffixes = FSharpSigFileSuffixes@FSharpImplFileSuffixes @@ -391,7 +417,7 @@ let ParseOneInputFile (tcConfig: TcConfig, lexResourceManager, conditionalCompil with e -> errorRecovery e rangeStartup - None + EmptyParsedInput(filename, isLastCompiland) let ProcessMetaCommandsFromInput (nowarnF: 'state -> range * string -> 'state, diff --git a/src/fsharp/ParseAndCheckInputs.fsi b/src/fsharp/ParseAndCheckInputs.fsi index ca218331564..5fc4a6b1a0c 100644 --- a/src/fsharp/ParseAndCheckInputs.fsi +++ b/src/fsharp/ParseAndCheckInputs.fsi @@ -48,7 +48,7 @@ val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string * Depe val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig /// Parse one input file -val ParseOneInputFile: TcConfig * Lexhelp.LexResourceManager * string list * string * isLastCompiland: (bool * bool) * ErrorLogger * (*retryLocked*) bool -> ParsedInput option +val ParseOneInputFile: TcConfig * Lexhelp.LexResourceManager * string list * string * isLastCompiland: (bool * bool) * ErrorLogger * retryLocked: bool -> ParsedInput /// Get the initial type checking environment including the loading of mscorlib/System.Core, FSharp.Core /// applying the InternalsVisibleTo in referenced assemblies and opening 'Checked' if requested. @@ -135,4 +135,9 @@ val ParseOneInputLexbuf: filename: string * isLastCompiland: (bool * bool) * errorLogger: ErrorLogger - -> ParsedInput option + -> ParsedInput + +val EmptyParsedInput: + filename: string * + isLastCompiland: (bool * bool) + -> ParsedInput \ No newline at end of file diff --git a/src/fsharp/ScriptClosure.fs b/src/fsharp/ScriptClosure.fs index 20b7ae949ce..2ede7cc5402 100644 --- a/src/fsharp/ScriptClosure.fs +++ b/src/fsharp/ScriptClosure.fs @@ -15,6 +15,7 @@ open FSharp.Compiler.CompilerConfig open FSharp.Compiler.CompilerDiagnostics open FSharp.Compiler.CompilerImports open FSharp.Compiler.DependencyManager +open FSharp.Compiler.Diagnostics open FSharp.Compiler.ErrorLogger open FSharp.Compiler.IO open FSharp.Compiler.CodeAnalysis @@ -27,8 +28,8 @@ open FSharp.Compiler.Text.Range type LoadClosureInput = { FileName: string SyntaxTree: ParsedInput option - ParseDiagnostics: (PhasedDiagnostic * bool) list - MetaCommandDiagnostics: (PhasedDiagnostic * bool) list } + ParseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list + MetaCommandDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list } [] type LoadClosure = @@ -63,16 +64,15 @@ type LoadClosure = NoWarns: (string * range list) list /// Diagnostics seen while processing resolutions - ResolutionDiagnostics: (PhasedDiagnostic * bool) list + ResolutionDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list /// Diagnostics seen while parsing root of closure - AllRootFileDiagnostics: (PhasedDiagnostic * bool) list + AllRootFileDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list /// Diagnostics seen while processing the compiler options implied root of closure - LoadClosureRootFileDiagnostics: (PhasedDiagnostic * bool) list + LoadClosureRootFileDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list } - [] type CodeContext = | CompilationAndEvaluation // in fsi.exe @@ -85,7 +85,7 @@ module ScriptPreprocessClosure = type ClosureSource = ClosureSource of filename: string * referenceRange: range * sourceText: ISourceText * parseRequired: bool /// Represents an output of the closure finding process - type ClosureFile = ClosureFile of string * range * ParsedInput option * (PhasedDiagnostic * bool) list * (PhasedDiagnostic * bool) list * (string * range) list // filename, range, errors, warnings, nowarns + type ClosureFile = ClosureFile of string * range * ParsedInput option * (PhasedDiagnostic * FSharpDiagnosticSeverity) list * (PhasedDiagnostic * FSharpDiagnosticSeverity) list * (string * range) list // filename, range, errors, warnings, nowarns type Observed() = let seen = System.Collections.Generic.Dictionary<_, bool>() @@ -317,7 +317,7 @@ module ScriptPreprocessClosure = result, errorLogger.Diagnostics match parseResult with - | Some parsedScriptAst -> + | parsedScriptAst -> let errorLogger = CapturingErrorLogger("FindClosureMetaCommands") use _unwindEL = PushErrorLoggerPhaseUntilUnwind (fun _ -> errorLogger) let pathOfMetaCommandSource = Path.GetDirectoryName filename @@ -339,10 +339,6 @@ module ScriptPreprocessClosure = else yield ClosureFile(subFile, m, None, [], [], []) yield ClosureFile(filename, m, Some parsedScriptAst, parseDiagnostics, errorLogger.Diagnostics, noWarns) - - | None -> - printfn "yielding source %s (failed parse)" filename - yield ClosureFile(filename, m, None, parseDiagnostics, [], []) else // Don't traverse into .fs leafs. printfn "yielding non-script source %s" filename diff --git a/src/fsharp/ScriptClosure.fsi b/src/fsharp/ScriptClosure.fsi index 0f3baf17981..36379517457 100644 --- a/src/fsharp/ScriptClosure.fsi +++ b/src/fsharp/ScriptClosure.fsi @@ -9,6 +9,7 @@ open FSharp.Compiler.AbstractIL.ILBinaryReader open FSharp.Compiler.CompilerConfig open FSharp.Compiler.CompilerImports open FSharp.Compiler.DependencyManager +open FSharp.Compiler.Diagnostics open FSharp.Compiler.ErrorLogger open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Syntax @@ -27,9 +28,9 @@ type LoadClosureInput = SyntaxTree: ParsedInput option - ParseDiagnostics: (PhasedDiagnostic * bool) list + ParseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list - MetaCommandDiagnostics: (PhasedDiagnostic * bool) list + MetaCommandDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list } [] @@ -65,13 +66,13 @@ type LoadClosure = NoWarns: (string * range list) list /// Diagnostics seen while processing resolutions - ResolutionDiagnostics: (PhasedDiagnostic * bool) list + ResolutionDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list /// Diagnostics to show for root of closure (used by fsc.fs) - AllRootFileDiagnostics: (PhasedDiagnostic * bool) list + AllRootFileDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list /// Diagnostics seen while processing the compiler options implied root of closure - LoadClosureRootFileDiagnostics: (PhasedDiagnostic * bool) list } + LoadClosureRootFileDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list } /// Analyze a script text and find the closure of its references. /// Used from FCS, when editing a script file. diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index e6b2e74784f..14cb93fcb51 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -1875,3 +1875,4 @@ type ParsedInput = | ParsedInput.SigFile (ParsedSigFileInput (modules=SynModuleOrNamespaceSig(range=m) :: _)) -> m | ParsedInput.ImplFile (ParsedImplFileInput (fileName=filename)) | ParsedInput.SigFile (ParsedSigFileInput (fileName=filename)) -> rangeN filename 0 + diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 217882abd90..8c8350c3abd 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -72,20 +72,20 @@ type ErrorLoggerUpToMaxErrors(tcConfigB: TcConfigBuilder, exiter: Exiter, nameFo let mutable errors = 0 /// Called when an error or warning occurs - abstract HandleIssue: tcConfigB: TcConfigBuilder * error: PhasedDiagnostic * isError: bool -> unit + abstract HandleIssue: tcConfigB: TcConfigBuilder * error: PhasedDiagnostic * severity: FSharpDiagnosticSeverity -> unit /// Called when 'too many errors' has occurred abstract HandleTooManyErrors: text: string -> unit override x.ErrorCount = errors - override x.DiagnosticSink(err, isError) = - if isError || ReportWarningAsError tcConfigB.errorSeverityOptions err then + override x.DiagnosticSink(err, severity) = + if severity = FSharpDiagnosticSeverity.Error || ReportWarningAsError tcConfigB.errorSeverityOptions err then if errors >= tcConfigB.maxErrors then x.HandleTooManyErrors(FSComp.SR.fscTooManyErrors()) exiter.Exit 1 - x.HandleIssue(tcConfigB, err, true) + x.HandleIssue(tcConfigB, err, severity) errors <- errors + 1 @@ -96,7 +96,7 @@ type ErrorLoggerUpToMaxErrors(tcConfigB: TcConfigBuilder, exiter: Exiter, nameFo | _ -> () elif ReportWarning tcConfigB.errorSeverityOptions err then - x.HandleIssue(tcConfigB, err, isError) + x.HandleIssue(tcConfigB, err, severity) /// Create an error logger that counts and prints errors @@ -104,11 +104,11 @@ let ConsoleErrorLoggerUpToMaxErrors (tcConfigB: TcConfigBuilder, exiter : Exiter { new ErrorLoggerUpToMaxErrors(tcConfigB, exiter, "ConsoleErrorLoggerUpToMaxErrors") with member _.HandleTooManyErrors(text : string) = - DoWithErrorColor false (fun () -> Printf.eprintfn "%s" text) + DoWithDiagnosticColor FSharpDiagnosticSeverity.Warning (fun () -> Printf.eprintfn "%s" text) - member _.HandleIssue(tcConfigB, err, isError) = - DoWithErrorColor isError (fun () -> - let diag = OutputDiagnostic (tcConfigB.implicitIncludeDir, tcConfigB.showFullPaths, tcConfigB.flatErrors, tcConfigB.errorStyle, isError) + member _.HandleIssue(tcConfigB, err, severity) = + DoWithDiagnosticColor severity (fun () -> + let diag = OutputDiagnostic (tcConfigB.implicitIncludeDir, tcConfigB.showFullPaths, tcConfigB.flatErrors, tcConfigB.errorStyle, severity) writeViaBuffer stderr diag err stderr.WriteLine()) } :> ErrorLogger @@ -144,16 +144,21 @@ type InProcErrorLoggerProvider() = { new ErrorLoggerUpToMaxErrors(tcConfigBuilder, exiter, "InProcCompilerErrorLoggerUpToMaxErrors") with - member this.HandleTooManyErrors text = warnings.Add(Diagnostic.Short(false, text)) + member this.HandleTooManyErrors text = + warnings.Add(Diagnostic.Short(FSharpDiagnosticSeverity.Warning, text)) - member this.HandleIssue(tcConfigBuilder, err, isError) = + member this.HandleIssue(tcConfigBuilder, err, severity) = // 'true' is passed for "suggestNames", since we want to suggest names with fsc.exe runs and this doesn't affect IDE perf - let errs = + let diagnostics = CollectDiagnostic (tcConfigBuilder.implicitIncludeDir, tcConfigBuilder.showFullPaths, - tcConfigBuilder.flatErrors, tcConfigBuilder.errorStyle, isError, err, true) - let container = if isError then errors else warnings - container.AddRange(errs) } + tcConfigBuilder.flatErrors, tcConfigBuilder.errorStyle, severity, err, true) + match severity with + | FSharpDiagnosticSeverity.Error -> + errors.AddRange(diagnostics) + | FSharpDiagnosticSeverity.Warning -> + warnings.AddRange(diagnostics) + | _ -> ()} :> ErrorLogger } member _.CapturedErrors = errors.ToArray() @@ -516,13 +521,12 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, List.zip sourceFiles isLastCompiland // PERF: consider making this parallel, once uses of global state relevant to parsing are cleaned up - |> List.choose (fun (sourceFile, isLastCompiland) -> + |> List.map (fun (sourceFile, isLastCompiland) -> let sourceFileDirectory = Path.GetDirectoryName sourceFile - match ParseOneInputFile(tcConfig, lexResourceManager, ["COMPILED"], sourceFile, (isLastCompiland, isExe), errorLogger, (*retryLocked*)false) with - | Some input -> Some (input, sourceFileDirectory) - | None -> None) + let input = ParseOneInputFile(tcConfig, lexResourceManager, ["COMPILED"], sourceFile, (isLastCompiland, isExe), errorLogger, (*retryLocked*)false) + (input, sourceFileDirectory)) with e -> errorRecoveryNoRange e @@ -580,13 +584,15 @@ let main1(ctok, argv, legacyReferenceResolver, bannerAlreadyPrinted, let tcState, topAttrs, tcFileResults, tcEnvAtEnd = TypeCheck(ctok, tcConfig, tcImports, tcGlobals, errorLogger, assemblyName, NiceNameGenerator(), tcEnv0, inputs, exiter) + ReportTime tcConfig "Run Analyzers" AbortOnError(errorLogger, exiter) - ReportTime tcConfig "Typechecked" - let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, tcConfig.compilerToolPaths) FSharpAnalyzers.RunAnalyzers(analyzers, tcConfig, tcImports, tcGlobals, tcState.Ccu, sourceFiles, tcFileResults, tcEnvAtEnd) + AbortOnError(errorLogger, exiter) + let typedImplFiles = tcFileResults |> List.collect (fun (_a,b,_c) -> Option.toList b) // TODO: run project analysis diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index fa4352ca1f4..a2e0134a6f5 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -526,11 +526,11 @@ type internal FsiStdinSyphon(errorWriter: TextWriter) = /// Display the given error. member syphon.PrintError (tcConfig:TcConfigBuilder, err) = Utilities.ignoreAllErrors (fun () -> - let isError = true - DoWithErrorColor isError (fun () -> + let severity = FSharpDiagnosticSeverity.Error + DoWithDiagnosticColor severity (fun () -> errorWriter.WriteLine(); writeViaBuffer errorWriter (OutputDiagnosticContext " " syphon.GetLine) err; - writeViaBuffer errorWriter (OutputDiagnostic (tcConfig.implicitIncludeDir,tcConfig.showFullPaths,tcConfig.flatErrors,tcConfig.errorStyle,isError)) err; + writeViaBuffer errorWriter (OutputDiagnostic (tcConfig.implicitIncludeDir,tcConfig.showFullPaths,tcConfig.flatErrors,tcConfig.errorStyle,severity)) err; errorWriter.WriteLine() errorWriter.WriteLine() errorWriter.Flush())) @@ -564,19 +564,19 @@ type internal ErrorLoggerThatStopsOnFirstError(tcConfigB:TcConfigBuilder, fsiStd member x.ResetErrorCount() = (errorCount <- 0) - override x.DiagnosticSink(err, isError) = - if isError || ReportWarningAsError tcConfigB.errorSeverityOptions err then + override x.DiagnosticSink(err, severity) = + if (severity = FSharpDiagnosticSeverity.Error) || ReportWarningAsError tcConfigB.errorSeverityOptions err then fsiStdinSyphon.PrintError(tcConfigB,err) errorCount <- errorCount + 1 if tcConfigB.abortOnError then exit 1 (* non-zero exit code *) // STOP ON FIRST ERROR (AVOIDS PARSER ERROR RECOVERY) raise StopProcessing else - DoWithErrorColor isError (fun () -> + DoWithDiagnosticColor severity (fun () -> if ReportWarning tcConfigB.errorSeverityOptions err then fsiConsoleOutput.Error.WriteLine() writeViaBuffer fsiConsoleOutput.Error (OutputDiagnosticContext " " fsiStdinSyphon.GetLine) err - writeViaBuffer fsiConsoleOutput.Error (OutputDiagnostic (tcConfigB.implicitIncludeDir,tcConfigB.showFullPaths,tcConfigB.flatErrors,tcConfigB.errorStyle,isError)) err + writeViaBuffer fsiConsoleOutput.Error (OutputDiagnostic (tcConfigB.implicitIncludeDir,tcConfigB.showFullPaths,tcConfigB.flatErrors,tcConfigB.errorStyle,severity)) err fsiConsoleOutput.Error.WriteLine() fsiConsoleOutput.Error.WriteLine() fsiConsoleOutput.Error.Flush()) @@ -1603,13 +1603,11 @@ type internal FsiDynamicCompiler let parsedInput = match input.SyntaxTree with | None -> ParseOneInputFile(tcConfig,lexResourceManager,["INTERACTIVE"],input.FileName,(true,false),errorLogger,(*retryLocked*)false) - | _-> input.SyntaxTree + | Some parseTree -> parseTree input.FileName, parsedInput) |> List.unzip errorLogger.AbortOnError(fsiConsoleOutput); - if inputs |> List.exists Option.isNone then failwith "parse error" - let inputs = List.map Option.get inputs let istate = (istate, sourceFiles, inputs) |||> List.fold2 (fun istate sourceFile input -> fsiDynamicCompiler.ProcessMetaCommandsFromInputAsInteractiveCommands(ctok, istate, sourceFile, input)) fsiDynamicCompiler.EvalParsedSourceFiles (ctok, errorLogger, istate, inputs) @@ -1705,7 +1703,7 @@ type internal FsiDynamicCompiler tcGlobals = tcGlobals tcState = tcState tcImports = tcImports - tcAnalyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) + tcAnalyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, tcConfig.compilerToolPaths) ilxGenerator = ilxGenerator boundValues = NameMap.empty timing = false @@ -2240,13 +2238,18 @@ type internal FsiInteractionProcessor packageManagerDirective Directive.Resolution path m | ParsedScriptInteraction.HashDirective (ParsedHashDirective("compilertool", [path], m), _) -> - let istate = - if FileSystem.SafeExists(path) then - { istate with tcAnalyzers = istate.tcAnalyzers @ FSharpAnalyzers.CreateAnalyzers (path, m) } + if FileSystem.IsInvalidPathShim path then + warning(Error(FSComp.SR.etCompilerToolPathDidntExist(path), m)) + istate, Completed None + // TODO: check this is the right place to resolve paths + else + let rootedPath = if Path.IsPathRooted(path) then path else Path.Combine(tcConfigB.implicitIncludeDir, path) + if not (Directory.Exists rootedPath) then + warning(Error(FSComp.SR.etCompilerToolPathDidntExist(rootedPath), m)) + istate, Completed None else - // TODO: give a warning here (or in CreateAnalyzer) - istate - istate, Completed None + let istate = { istate with tcAnalyzers = istate.tcAnalyzers @ FSharpAnalyzers.ImportAnalyzers(tcConfig, [(m, rootedPath)]) } + istate, Completed None | ParsedScriptInteraction.HashDirective (ParsedHashDirective("i", [path], m), _) -> packageManagerDirective Directive.Include path m @@ -2936,7 +2939,7 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i | Choice2Of2 (Some userExn) -> raise (makeNestedException userExn) let commitResultNonThrowing errorOptions scriptFile (errorLogger: CompilationErrorLogger) res = - let errs = errorLogger.GetErrors() + let errs = errorLogger.GetDiagnostics() let errorInfos = DiagnosticHelpers.CreateDiagnostics (errorOptions, true, scriptFile, errs, true) let userRes = match res with diff --git a/src/fsharp/infos.fs b/src/fsharp/infos.fs index 78d3754baa3..9d8a3d483a1 100755 --- a/src/fsharp/infos.fs +++ b/src/fsharp/infos.fs @@ -1138,8 +1138,9 @@ type MethInfo = match x with | ILMeth(_g, ilmeth, _) -> ilmeth.IsVirtual | FSMeth(g, _, vref, _) as x -> - isInterfaceTy g x.ApparentEnclosingType || - vref.MemberInfo.Value.MemberFlags.IsDispatchSlot + not x.IsExtensionMember && + (isInterfaceTy g x.ApparentEnclosingType || + vref.MemberInfo.Value.MemberFlags.IsDispatchSlot) | DefaultStructCtor _ -> false #if !NO_EXTENSIONTYPING | ProvidedMeth _ -> x.IsVirtual // Note: follow same implementation as ILMeth @@ -2055,7 +2056,8 @@ type PropInfo = | ILProp ilpinfo -> ilpinfo.IsVirtual | FSProp(g, ty, Some vref, _) | FSProp(g, ty, _, Some vref) -> - isInterfaceTy g ty || (vref.MemberInfo.Value.MemberFlags.IsDispatchSlot) + not x.IsExtensionMember && + (isInterfaceTy g ty || vref.MemberInfo.Value.MemberFlags.IsDispatchSlot) | FSProp _ -> failwith "unreachable" #if !NO_EXTENSIONTYPING | ProvidedProp(_, pi, m) -> diff --git a/src/fsharp/service/FSharpAnalyzer.fs b/src/fsharp/service/FSharpAnalyzer.fs index f7d7e3d4a92..533de25a258 100644 --- a/src/fsharp/service/FSharpAnalyzer.fs +++ b/src/fsharp/service/FSharpAnalyzer.fs @@ -27,41 +27,34 @@ open Internal.Utilities.FSharpEnvironment type FSharpAnalyzerTextChange = Range * string [] -type public FSharpAnalyzerCheckFileContext(sourceTexts: (string * ISourceText)[], - checkResults: FSharpCheckFileResults, - cancellationToken: CancellationToken, - tcConfig: TcConfig) = - let sourceTextMap = Map.ofArray sourceTexts +type public FSharpAnalyzerCheckFilesContext(checkResults: FSharpCheckFileResults[], + cancellationToken: CancellationToken) = member _.CancellationToken = cancellationToken - member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage member _.CheckerModel = checkResults [] -type public FSharpAnalyzerCheckProjectContext(sourceTexts: (string * ISourceText)[], - checkResults: FSharpCheckProjectResults, - cancellationToken: CancellationToken, - tcConfig: TcConfig) = - let sourceTextMap = Map.ofArray sourceTexts +type public FSharpAnalyzerCheckProjectContext(checkResults: FSharpCheckProjectResults, + cancellationToken: CancellationToken) = member _.CancellationToken = cancellationToken - member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage + //member _.GetFileSource(fileName) = if sourceTextMap.ContainsKey fileName then sourceTextMap.[fileName] else SourceText.readFile fileName tcConfig.inputCodePage member _.CheckerModel = checkResults [] -type public FSharpAnalysisContext() = - class end +type public FSharpAnalysisContext(tt: bool) = + member _.EditorServicesRequested = tt /// Represents an analyzer [] type public FSharpAnalyzer(context:FSharpAnalysisContext) = member _.Context = context - abstract OnCheckFile: context: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] + abstract OnCheckFiles: context: FSharpAnalyzerCheckFilesContext -> FSharpDiagnostic[] abstract OnCheckProject: context: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] - abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option - abstract TryCodeFix: context: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option + abstract TryAdditionalToolTip: context: FSharpAnalyzerCheckFilesContext * position: Position -> TaggedText[] option + abstract TryCodeFix: context: FSharpAnalyzerCheckFilesContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option abstract FixableDiagnosticIds: string[] abstract RequiresAssemblyContents: bool - default _.OnCheckFile(_) = [| |] + default _.OnCheckFiles(_) = [| |] default _.OnCheckProject(_) = [| |] default _.TryAdditionalToolTip(_, _) = None default _.TryCodeFix(_, _) = None @@ -87,15 +80,16 @@ module FSharpAnalyzers = let enumerateAnalyzerAssemblies (compilerToolPaths: (range * string) list) = [ for m, compilerToolPath in compilerToolPaths do for path in searchToolPath compilerToolPath do - if Directory.Exists(path) then + if (try Directory.Exists(path) with _ -> false) then for filePath in Directory.EnumerateFiles(path, fsharpAnalyzerPattern) do - yield (m, filePath) ] + yield (m, filePath) + ] - let CreateAnalyzer (analyzerType: System.Type, m) = + let CreateAnalyzer (tcConfig: TcConfig, analyzerType: System.Type, m) = if analyzerType.GetConstructor([| typeof |]) <> null then - let ctxt = FSharpAnalysisContext() + let ctxt = FSharpAnalysisContext(tt=tcConfig.isInvalidationSupported) try Activator.CreateInstance(analyzerType, [| box ctxt|]) :?> FSharpAnalyzer |> Some with @@ -114,7 +108,7 @@ module FSharpAnalyzers = errorR (Error(FSComp.SR.etAnalyzerDoesNotHaveValidConstructor(analyzerType.FullName), m)) None - let CreateAnalyzers (analyzerPath: string, m:range) = + let CreateAnalyzers (tcConfig, analyzerPath: string, m:range) = let analyzerAssembly = try @@ -130,21 +124,19 @@ module FSharpAnalyzers = for t in exportedTypes do let ca = t.GetCustomAttributes(typeof, true) if ca <> null && ca.Length > 0 then - match CreateAnalyzer(t, m) with + match CreateAnalyzer(tcConfig, t, m) with | None -> () | Some a -> a ] - let ImportAnalyzers(tcConfig: TcConfig) = - [ for (m, analyzerPath) in enumerateAnalyzerAssemblies tcConfig.compilerToolPaths do + let ImportAnalyzers(tcConfig, compilerToolPaths) = + [ for (m, analyzerPath) in enumerateAnalyzerAssemblies compilerToolPaths do if FileSystem.SafeExists(analyzerPath) then - yield! CreateAnalyzers (analyzerPath, m) + yield! CreateAnalyzers (tcConfig, analyzerPath, m) // TODO: give a warning here (or in CreateAnalyzer) ] let RunAnalyzers(analyzers: FSharpAnalyzer list, tcConfig: TcConfig, tcImports: TcImports, tcGlobals: TcGlobals, tcCcu: CcuThunk, sourceFiles: string list, tcFileResults, tcEnvAtEnd: TcEnv) = - let sourceTexts = [| for sourceFile in sourceFiles -> sourceFile, SourceText.readFile sourceFile tcConfig.inputCodePage |] - let projectOptions = { ProjectFileName = "compile.fsproj" @@ -165,49 +157,49 @@ module FSharpAnalyzers = let implFilesRev2 = Option.toList b @ implFilesRev (a, List.rev implFilesRev2, c), implFilesRev2) - for (inp, implFileOpt, ccuSig) in tcFileResults do + let checkFilesResults = + [| for (inp, implFileOpt, ccuSig) in tcFileResults do - let parseResults = - FSharpParseFileResults(diagnostics = [||], - input = Some inp, - parseHadErrors = false, - dependencyFiles = [| |]) - - let checkResults = - FSharpCheckFileResults.Make - (inp.FileName, - "compile.fsproj", - tcConfig, - tcGlobals, - false, - None, - parseResults.ParseTree, - projectOptions, - [| |], - [| |], - [| |], - [| |], - true, - ccuSig, - tcCcu, - tcImports, - tcEnvAtEnd.AccessRights, - TcResolutions.Empty, - TcSymbolUses.Empty, - tcEnvAtEnd.NameEnv, - None, - implFileOpt, - [| |]) - - let ctxt = FSharpAnalyzerCheckFileContext(sourceTexts, checkResults, CancellationToken.None, tcConfig) - - for analyzer in analyzers do - let diagnostics = analyzer.OnCheckFile(ctxt) - for diag in diagnostics do - let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) - match diag.Severity with - | FSharpDiagnosticSeverity.Error -> errorR(exn) - | FSharpDiagnosticSeverity.Warning -> warning(exn) - | FSharpDiagnosticSeverity.Info -> warning(exn) - | FSharpDiagnosticSeverity.Hidden -> () + let parseResults = + FSharpParseFileResults(diagnostics=[||], + input=inp, + sourceText=None, + parseHadErrors=false, + dependencyFiles=[| |]) + + let checkResults = + FSharpCheckFileResults.Make + (inp.FileName, + "compile.fsproj", + tcConfig, + tcGlobals, + false, + None, + parseResults.ParseTree, + None, + projectOptions, + [| |], + [| |], + [| |], + [| |], + true, + ccuSig, + tcCcu, + tcImports, + tcEnvAtEnd.AccessRights, + TcResolutions.Empty, + TcSymbolUses.Empty, + tcEnvAtEnd.NameEnv, + None, + implFileOpt, + [| |]) + yield checkResults |] + + let ctxt = FSharpAnalyzerCheckFilesContext(checkFilesResults, CancellationToken.None) + + for analyzer in analyzers do + let diagnostics = analyzer.OnCheckFiles(ctxt) + for diag in diagnostics do + let exn = CompilerToolDiagnostic((diag.ErrorNumber, diag.Message), diag.Range) + diagnostic(exn, diag.Severity) diff --git a/src/fsharp/service/FSharpAnalyzer.fsi b/src/fsharp/service/FSharpAnalyzer.fsi index b26b202d386..8515fe76edf 100644 --- a/src/fsharp/service/FSharpAnalyzer.fsi +++ b/src/fsharp/service/FSharpAnalyzer.fsi @@ -16,34 +16,44 @@ open FSharp.Compiler.Text type FSharpAnalyzerTextChange = Range * string -/// The context for an analyzer when a file is checked +/// The context for an analyzer when one or more files are checked [] -type public FSharpAnalyzerCheckFileContext = +type public FSharpAnalyzerCheckFilesContext = - internal new: sourceTexts: (string * ISourceText)[] * checkResults: FSharpCheckFileResults * cancellationToken: CancellationToken * tcConfig: TcConfig -> FSharpAnalyzerCheckFileContext + internal new: checkResults: FSharpCheckFileResults[] * cancellationToken: CancellationToken -> FSharpAnalyzerCheckFilesContext member CancellationToken: CancellationToken - member GetFileSource: fileName: string -> ISourceText + //member GetFileSource: fileName: string -> ISourceText + // Currently this is the file source of the actual last file checked, which is the last in + // the PartialAssemblyContents + // member FileSource: ISourceText - member CheckerModel: FSharpCheckFileResults + /// This contains handles to models resulting from checking each of the files. + /// There is always at least one file, and in an incremental editing environment + /// there will only be one file. + member CheckerModel: FSharpCheckFileResults[] /// The context for an analyzer when a project is checked [] type public FSharpAnalyzerCheckProjectContext = - internal new: sourceTexts: (string * ISourceText)[] * checkResults: FSharpCheckProjectResults * cancellationToken: CancellationToken * tcConfig: TcConfig -> FSharpAnalyzerCheckProjectContext + internal new: checkResults: FSharpCheckProjectResults * cancellationToken: CancellationToken -> FSharpAnalyzerCheckProjectContext member CancellationToken: CancellationToken - member GetFileSource: fileName: string -> ISourceText + //member FileSource: ISourceText + //member GetFileSource: fileName: string -> ISourceText member CheckerModel: FSharpCheckProjectResults /// The context for an analyzer. Currently empty. [] type public FSharpAnalysisContext = - class end + + /// Indicates the analyzer is running in a context where tooltips and other editor services may be requested + member EditorServicesRequested: bool + /// Represents an analyzer. Inherit from this class to create an analyzer. [] @@ -55,24 +65,24 @@ type public FSharpAnalyzer = abstract RequiresAssemblyContents: bool - abstract OnCheckFile: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] + /// Called when one or more files are checked incrementally + abstract OnCheckFiles: FSharpAnalyzerCheckFilesContext -> FSharpDiagnostic[] abstract OnCheckProject: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] - abstract TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option + abstract TryAdditionalToolTip: FSharpAnalyzerCheckFilesContext * position: Position -> TaggedText[] option - abstract TryCodeFix: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option + abstract TryCodeFix: FSharpAnalyzerCheckFilesContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option abstract FixableDiagnosticIds: string[] default RequiresAssemblyContents: bool - default OnCheckFile: FSharpAnalyzerCheckFileContext -> FSharpDiagnostic[] + default OnCheckFiles: FSharpAnalyzerCheckFilesContext -> FSharpDiagnostic[] default OnCheckProject: FSharpAnalyzerCheckProjectContext -> FSharpDiagnostic[] - default TryAdditionalToolTip: FSharpAnalyzerCheckFileContext * position: Position -> TaggedText[] option - default TryCodeFix: FSharpAnalyzerCheckFileContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option + default TryAdditionalToolTip: FSharpAnalyzerCheckFilesContext * position: Position -> TaggedText[] option + default TryCodeFix: FSharpAnalyzerCheckFilesContext * diagnostics: FSharpDiagnostic[] -> FSharpAnalyzerTextChange[] option default FixableDiagnosticIds: string[] module internal FSharpAnalyzers = - val CreateAnalyzers: analyzerPath: string * m: range -> FSharpAnalyzer list - val ImportAnalyzers: tcConfig: TcConfig -> FSharpAnalyzer list + val ImportAnalyzers: tcConfig: TcConfig * compilerToolPaths: (range * string) list -> FSharpAnalyzer list val RunAnalyzers: analyzers: FSharpAnalyzer list * tcConfig: TcConfig * tcImports: TcImports * tcGlobals: TcGlobals * tcCcu: CcuThunk * sourceFiles: string list * tcFileResults: (ParsedInput * TypedImplFile option * ModuleOrNamespaceType) list * tcEnvAtEnd: TcEnv -> unit diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 7450f475d58..d110ce74ed1 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -215,7 +215,8 @@ type internal TypeCheckInfo tcAccessRights: AccessorDomain, projectFileName: string, mainInputFileName: string, - parseTree: ParsedInput option, + parseTree: ParsedInput, + sourceText: ISourceText option, projectOptions: FSharpProjectOptions, sResolutions: TcResolutions, sSymbolUses: TcSymbolUses, @@ -499,9 +500,8 @@ type internal TypeCheckInfo GetPreciseCompletionListFromExprTypingsResult.None | _ -> let bestQual, textChanged = - match parseResults.ParseTree with - | Some input -> - match ParsedInput.GetRangeOfExprLeftOfDot(endOfExprPos,Some(input)) with // TODO we say "colAtEndOfNames" everywhere, but that's not really a good name ("foo . $" hit Ctrl-Space at $) + let input = parseResults.ParseTree + match ParsedInput.GetRangeOfExprLeftOfDot(endOfExprPos,input) with // TODO we say "colAtEndOfNames" everywhere, but that's not really a good name ("foo . $" hit Ctrl-Space at $) | Some( exprRange) -> // We have an up-to-date sync parse, and know the exact range of the prior expression. // The quals all already have the same ending position, so find one with a matching starting position, if it exists. @@ -517,7 +517,6 @@ type internal TypeCheckInfo // In practice, we do get here in some weird cases like "2.0 .. 3.0" and hitting Ctrl-Space in between the two dots of the range operator. // I wasn't able to track down what was happening in those weird cases, not worth worrying about, it doesn't manifest as a product bug or anything. None, false - | _ -> None, false match bestQual with | Some bestQual -> @@ -838,7 +837,7 @@ type internal TypeCheckInfo // Look for a "special" completion context let completionContext = parseResultsOpt - |> Option.bind (fun x -> x.ParseTree) + |> Option.map (fun x -> x.ParseTree) |> Option.bind (fun parseTree -> ParsedInput.TryGetCompletionContext(mkPos line colAtEndOfNamesAndResidue, parseTree, lineStr)) let res = @@ -997,6 +996,8 @@ type internal TypeCheckInfo member _.ParseTree = parseTree + member _.SourceText = sourceText + /// Get the auto-complete items at a location member _.GetDeclarations (parseResultsOpt, line, lineStr, partialName, getAllEntities) = let isInterfaceFile = SourceFileImpl.IsInterfaceFile mainInputFileName @@ -1016,7 +1017,7 @@ type internal TypeCheckInfo let getAccessibility item = FSharpSymbol.Create(cenv, item).Accessibility let currentNamespaceOrModule = parseResultsOpt - |> Option.bind (fun x -> x.ParseTree) + |> Option.map (fun x -> x.ParseTree) |> Option.map (fun parsedInput -> ParsedInput.GetFullNameOfSmallestModuleOrNamespaceAtPoint(mkPos line 0, parsedInput)) let isAttributeApplication = ctx = Some CompletionContext.AttributeApplication DeclarationListInfo.Create(infoReader,m,denv,getAccessibility,items,currentNamespaceOrModule,isAttributeApplication)) @@ -1500,7 +1501,7 @@ module internal ParseAndCheckFile = else exn if reportErrors then let report exn = - for ei in DiagnosticHelpers.ReportError (options, false, mainInputFileName, fileInfo, (exn, sev), suggestNamesForErrors) do + for ei in DiagnosticHelpers.ReportDiagnostic (options, false, mainInputFileName, fileInfo, (exn, sev), suggestNamesForErrors) do errorsAndWarningsCollector.Add ei if sev = FSharpDiagnosticSeverity.Error then errorCount <- errorCount + 1 @@ -1513,7 +1514,7 @@ module internal ParseAndCheckFile = let errorLogger = { new ErrorLogger("ErrorHandler") with - member x.DiagnosticSink (exn, isError) = diagnosticSink (if isError then FSharpDiagnosticSeverity.Error else FSharpDiagnosticSeverity.Warning) exn + member x.DiagnosticSink (exn, severity) = diagnosticSink severity exn member x.ErrorCount = errorCount } // Public members @@ -1657,10 +1658,10 @@ module internal ParseAndCheckFile = let isExe = options.IsExe try - Some (ParseInput(lexfun, errHandler.ErrorLogger, lexbuf, None, fileName, (isLastCompiland, isExe))) + ParseInput(lexfun, errHandler.ErrorLogger, lexbuf, None, fileName, (isLastCompiland, isExe)) with e -> errHandler.ErrorLogger.StopProcessingRecovery e Range.range0 // don't re-raise any exceptions, we must return None. - None) + EmptyParsedInput(fileName, (isLastCompiland, isExe))) errHandler.CollectedDiagnostics, parseResult, errHandler.AnyErrors @@ -1737,6 +1738,7 @@ module internal ParseAndCheckFile = tcGlobals: TcGlobals, tcImports: TcImports, tcState: TcState, + tcPriorImplFiles: TypedImplFile list, moduleNamesDict: ModuleNamesDict, loadClosure: LoadClosure option, // These are the errors and warnings seen by the background compiler for the entire antecedent @@ -1747,12 +1749,7 @@ module internal ParseAndCheckFile = use _logBlock = Logger.LogBlock LogCompilerFunctionId.Service_CheckOneFile - match parseResults.ParseTree with - // When processing the following cases, we don't need to type-check - | None -> return [||], Result.Error() - - // Run the type checker... - | Some parsedMainInput -> + let parsedMainInput = parseResults.ParseTree // Initialize the error handler let errHandler = new ErrorHandler(true, mainInputFileName, tcConfig.errorSeverityOptions, sourceText, suggestNamesForErrors) @@ -1767,8 +1764,8 @@ module internal ParseAndCheckFile = errHandler.ErrorSeverityOptions <- tcConfig.errorSeverityOptions // Play background errors and warnings for this file. - for err, sev in backgroundDiagnostics do - diagnosticSink (err, (sev = FSharpDiagnosticSeverity.Error)) + for err, severity in backgroundDiagnostics do + diagnosticSink (err, severity) // If additional references were brought in by the preprocessor then we need to process them ApplyLoadClosure(tcConfig, parsedMainInput, mainInputFileName, loadClosure, tcImports, backgroundDiagnostics) @@ -1828,12 +1825,13 @@ module internal ParseAndCheckFile = projectFileName, mainInputFileName, parseResults.ParseTree, + parseResults.SourceText, projectOptions, sink.GetResolutions(), sink.GetSymbolUses(), tcEnvAtEnd.NameEnv, loadClosure, - (implFiles |> List.choose p23), + (tcPriorImplFiles @ (implFiles |> List.choose p23)), sink.GetOpenDeclarations()) |> Result.Ok | None -> @@ -1886,7 +1884,11 @@ type FSharpCheckFileResults /// Intellisense autocompletions member _.ParseTree = - threadSafeOp (fun () -> None) (fun scope -> scope.ParseTree) + threadSafeOp (fun () -> EmptyParsedInput(filename, (false, false))) (fun scope -> scope.ParseTree) + + /// Intellisense autocompletions + member _.SourceText = + threadSafeOp (fun () -> None) (fun scope -> scope.SourceText) /// Intellisense autocompletions member _.GetDeclarationListInfo(parsedFileResults, line, lineText, partialName, ?getAllEntities) = @@ -2062,6 +2064,7 @@ type FSharpCheckFileResults isIncompleteTypeCheckEnvironment: bool, builder: obj option, parseTree, + sourceText, projectOptions, dependencyFiles, creationErrors: FSharpDiagnostic[], @@ -2078,7 +2081,7 @@ type FSharpCheckFileResults let tcFileInfo = TypeCheckInfo(tcConfig, tcGlobals, ccuSigForFile, thisCcu, tcImports, tcAccessRights, projectFileName, mainInputFileName, - parseTree, projectOptions, + parseTree, sourceText, projectOptions, sResolutions, sSymbolUses, sFallback, loadClosure, implFiles, openDeclarations) @@ -2095,6 +2098,7 @@ type FSharpCheckFileResults tcGlobals: TcGlobals, tcImports: TcImports, tcState: TcState, + tcPriorImplFiles: TypedImplFile list, moduleNamesDict: ModuleNamesDict, loadClosure: LoadClosure option, backgroundDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity)[], @@ -2112,7 +2116,7 @@ type FSharpCheckFileResults let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile (parseResults, sourceText, mainInputFileName, projectOptions, projectFileName, tcConfig, tcGlobals, tcImports, - tcState, moduleNamesDict, loadClosure, backgroundDiagnostics, reactorOps, + tcState, tcPriorImplFiles, moduleNamesDict, loadClosure, backgroundDiagnostics, reactorOps, userOpName, suggestNamesForErrors) match tcFileInfo with | Result.Error () -> @@ -2257,9 +2261,9 @@ type FsiInteractiveChecker(legacyReferenceResolver, let suggestNamesForErrors = true // Will always be true, this is just for readability // Note: projectSourceFiles is only used to compute isLastCompiland, and is ignored if Build.IsScript(mainInputFileName) is true (which it is in this case). let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, [| filename |], true) - let parseErrors, parseTreeOpt, anyErrors = ParseAndCheckFile.parseFile (sourceText, filename, parsingOptions, userOpName, suggestNamesForErrors) + let parseErrors, parsedInput, anyErrors = ParseAndCheckFile.parseFile (sourceText, filename, parsingOptions, userOpName, suggestNamesForErrors) let dependencyFiles = [| |] // interactions have no dependencies - let parseResults = FSharpParseFileResults(parseErrors, parseTreeOpt, parseHadErrors = anyErrors, dependencyFiles = dependencyFiles) + let parseResults = FSharpParseFileResults(parseErrors, parsedInput, Some sourceText, parseHadErrors = anyErrors, dependencyFiles = dependencyFiles) let backgroundDiagnostics = [| |] let reduceMemoryUsage = ReduceMemoryFlag.Yes @@ -2293,10 +2297,11 @@ type FsiInteractiveChecker(legacyReferenceResolver, OriginalLoadReferences = [] Stamp = None } + let tcPriorImplFiles = [] let! tcErrors, tcFileInfo = ParseAndCheckFile.CheckOneFile (parseResults, sourceText, filename, projectOptions, "project", - tcConfig, tcGlobals, tcImports, tcState, + tcConfig, tcGlobals, tcImports, tcState, tcPriorImplFiles, Map.empty, Some loadClosure, backgroundDiagnostics, reactorOps, userOpName, suggestNamesForErrors) diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index 975f0f49027..a3f248a68af 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -161,8 +161,11 @@ type public FSharpParsingOptions = [] type public FSharpCheckFileResults = - /// The syntax tree for the source file, if available - member ParseTree: ParsedInput option + /// The syntax tree for the source file + member ParseTree: ParsedInput + + /// The source (if the file wasn't read from disk) + member SourceText: ISourceText option /// The errors returned by parsing a source file. member Diagnostics: FSharpDiagnostic[] @@ -327,7 +330,8 @@ type public FSharpCheckFileResults = tcGlobals: TcGlobals * isIncompleteTypeCheckEnvironment: bool * builder: obj option * - parseTree: ParsedInput option * + parseTree: ParsedInput * + sourceText: ISourceText option * projectOptions: FSharpProjectOptions * dependencyFiles: string[] * creationErrors: FSharpDiagnostic[] * @@ -356,6 +360,7 @@ type public FSharpCheckFileResults = tcGlobals: TcGlobals * tcImports: TcImports * tcState: TcState * + tcPriorImplFiles: TypedImplFile list * moduleNamesDict: ModuleNamesDict * loadClosure: LoadClosure option * backgroundDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity)[] * @@ -433,7 +438,7 @@ module internal ParseAndCheckFile = options: FSharpParsingOptions * userOpName: string * suggestNamesForErrors: bool - -> FSharpDiagnostic[] * ParsedInput option * bool + -> FSharpDiagnostic[] * ParsedInput * bool val matchBraces: sourceText: ISourceText * diff --git a/src/fsharp/service/FSharpParseFileResults.fs b/src/fsharp/service/FSharpParseFileResults.fs index 131826d4b7b..8f00ee99fae 100644 --- a/src/fsharp/service/FSharpParseFileResults.fs +++ b/src/fsharp/service/FSharpParseFileResults.fs @@ -75,7 +75,7 @@ type CompletionContext = //---------------------------------------------------------------------------- [] -type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput option, parseHadErrors: bool, dependencyFiles: string[]) = +type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, sourceText: ISourceText option, parseHadErrors: bool, dependencyFiles: string[]) = member _.Diagnostics = diagnostics @@ -83,6 +83,8 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput member _.ParseTree = input + member _.SourceText = sourceText + member scope.TryRangeOfNameOfNearestOuterBindingContainingPos pos = let tryGetIdentRangeFromBinding binding = match binding with @@ -121,24 +123,21 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput | _ -> Some workingRange - match scope.ParseTree with - | Some input -> - SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - defaultTraverse expr + let input = scope.ParseTree + SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, _, defaultTraverse, expr) = + defaultTraverse expr - override _.VisitBinding(_path, defaultTraverse, binding) = - match binding with - | SynBinding(_, _, _, _, _, _, _, _, _, expr, _range, _) as b when rangeContainsPos b.RangeOfBindingWithRhs pos -> - match tryGetIdentRangeFromBinding b with - | Some range -> walkBinding expr range - | None -> None - | _ -> defaultTraverse binding }) - | None -> None + override _.VisitBinding(_path, defaultTraverse, binding) = + match binding with + | SynBinding(_, _, _, _, _, _, _, _, _, expr, _range, _) as b when rangeContainsPos b.RangeOfBindingWithRhs pos -> + match tryGetIdentRangeFromBinding b with + | Some range -> walkBinding expr range + | None -> None + | _ -> defaultTraverse binding }) member scope.TryIdentOfPipelineContainingPosAndNumArgsApplied pos = - match scope.ParseTree with - | Some input -> + let input = scope.ParseTree SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with member _.VisitExpr(_, _, defaultTraverse, expr) = match expr with @@ -157,11 +156,9 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput None | _ -> defaultTraverse expr }) - | None -> None member scope.IsPosContainedInApplication pos = - match scope.ParseTree with - | Some input -> + let input = scope.ParseTree let result = SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with member _.VisitExpr(_, traverseSynExpr, defaultTraverse, expr) = @@ -173,7 +170,6 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput | _ -> defaultTraverse expr }) result.IsSome - | None -> false member scope.TryRangeOfFunctionOrMethodBeingApplied pos = let rec getIdentRangeForFuncExprInApp traverseSynExpr expr pos = @@ -275,22 +271,19 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput traverseSynExpr expr |> Option.map (fun expr -> expr) - match scope.ParseTree with - | Some input -> - SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_, traverseSynExpr, defaultTraverse, expr) = - match expr with - | SynExpr.App (_, _, _funcExpr, _, range) as app when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr app pos - | _ -> defaultTraverse expr - }) - | None -> None + let input = scope.ParseTree + SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, traverseSynExpr, defaultTraverse, expr) = + match expr with + | SynExpr.App (_, _, _funcExpr, _, range) as app when rangeContainsPos range pos -> + getIdentRangeForFuncExprInApp traverseSynExpr app pos + | _ -> defaultTraverse expr + }) member scope.GetAllArgumentsForFunctionApplicationAtPostion pos = - match input with - | Some input -> SynExprAppLocationsImpl.getAllCurriedArgsAtPosition pos input - | None -> None + let input = scope.ParseTree + SynExprAppLocationsImpl.getAllCurriedArgsAtPosition pos input member scope.TryRangeOfParenEnclosingOpEqualsGreaterUsage opGreaterEqualPos = let (|Ident|_|) ofName = @@ -301,102 +294,87 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput Some (actualParamListExpr, actualLambdaBodyExpr) | _ -> None - match scope.ParseTree with - | Some parseTree -> - SyntaxTraversal.Traverse(opGreaterEqualPos, parseTree, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.Paren((InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _, _) -> - Some (app.Range, lambdaArgs.Range, lambdaBody.Range) - | _ -> defaultTraverse expr + let parseTree = scope.ParseTree + SyntaxTraversal.Traverse(opGreaterEqualPos, parseTree, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, _, defaultTraverse, expr) = + match expr with + | SynExpr.Paren((InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _, _) -> + Some (app.Range, lambdaArgs.Range, lambdaBody.Range) + | _ -> defaultTraverse expr - member _.VisitBinding(_path, defaultTraverse, binding) = - match binding with - | SynBinding(_, SynBindingKind.Normal, _, _, _, _, _, _, _, (InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _) -> - Some(app.Range, lambdaArgs.Range, lambdaBody.Range) - | _ -> defaultTraverse binding }) - | None -> None + member _.VisitBinding(_path, defaultTraverse, binding) = + match binding with + | SynBinding(_, SynBindingKind.Normal, _, _, _, _, _, _, _, (InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _) -> + Some(app.Range, lambdaArgs.Range, lambdaBody.Range) + | _ -> defaultTraverse binding }) member scope.TryRangeOfExprInYieldOrReturn pos = - match scope.ParseTree with - | Some parseTree -> - SyntaxTraversal.Traverse(pos, parseTree, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_path, _, defaultTraverse, expr) = - match expr with - | SynExpr.YieldOrReturn(_, expr, range) - | SynExpr.YieldOrReturnFrom(_, expr, range) when rangeContainsPos range pos -> - Some expr.Range - | _ -> defaultTraverse expr }) - | None -> None + let parseTree = scope.ParseTree + SyntaxTraversal.Traverse(pos, parseTree, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_path, _, defaultTraverse, expr) = + match expr with + | SynExpr.YieldOrReturn(_, expr, range) + | SynExpr.YieldOrReturnFrom(_, expr, range) when rangeContainsPos range pos -> + Some expr.Range + | _ -> defaultTraverse expr }) member scope.TryRangeOfRecordExpressionContainingPos pos = - match input with - | Some input -> + let input = scope.ParseTree + SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, _, defaultTraverse, expr) = + match expr with + | SynExpr.Record(_, _, _, range) when rangeContainsPos range pos -> + Some range + | _ -> defaultTraverse expr }) + + member scope.TryRangeOfRefCellDereferenceContainingPos expressionPos = + let input = scope.ParseTree + SyntaxTraversal.Traverse(expressionPos, input, { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_, _, defaultTraverse, expr) = + match expr with + | SynExpr.App(_, false, SynExpr.Ident funcIdent, expr, _) -> + if funcIdent.idText = "op_Dereference" && rangeContainsPos expr.Range expressionPos then + Some funcIdent.idRange + else + None + | _ -> defaultTraverse expr }) + + member scope.FindParameterLocations pos = + let input = scope.ParseTree + ParameterLocations.Find(pos, input) + + member scope.IsPositionContainedInACurriedParameter pos = + let input = scope.ParseTree + let result = SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.Record(_, _, _, range) when rangeContainsPos range pos -> - Some range - | _ -> defaultTraverse expr }) - | None -> - None - - member _.TryRangeOfRefCellDereferenceContainingPos expressionPos = - match input with - | Some input -> - SyntaxTraversal.Traverse(expressionPos, input, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.App(_, false, SynExpr.Ident funcIdent, expr, _) -> - if funcIdent.idText = "op_Dereference" && rangeContainsPos expr.Range expressionPos then - Some funcIdent.idRange - else - None - | _ -> defaultTraverse expr }) - | None -> - None - - member _.FindParameterLocations pos = - match input with - | Some input -> ParameterLocations.Find(pos, input) - | _ -> None - - member _.IsPositionContainedInACurriedParameter pos = - match input with - | Some input -> - let result = - SyntaxTraversal.Traverse(pos, input, { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = - defaultTraverse(expr) - - override _.VisitBinding (_path, _, binding) = - match binding with - | SynBinding(_, _, _, _, _, _, valData, _, _, _, range, _) when rangeContainsPos range pos -> - let info = valData.SynValInfo.CurriedArgInfos - let mutable found = false - for group in info do - for arg in group do - match arg.Ident with - | Some ident when rangeContainsPos ident.idRange pos -> - found <- true - | _ -> () - if found then Some range else None - | _ -> - None - }) - result.IsSome - | _ -> false + member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = + defaultTraverse(expr) + + override _.VisitBinding (_path, _, binding) = + match binding with + | SynBinding(_, _, _, _, _, _, valData, _, _, _, range, _) when rangeContainsPos range pos -> + let info = valData.SynValInfo.CurriedArgInfos + let mutable found = false + for group in info do + for arg in group do + match arg.Ident with + | Some ident when rangeContainsPos ident.idRange pos -> + found <- true + | _ -> () + if found then Some range else None + | _ -> + None + }) + result.IsSome /// Get declared items and the selected item at the specified location member _.GetNavigationItemsImpl() = ErrorScope.Protect range0 (fun () -> match input with - | Some (ParsedInput.ImplFile _ as p) -> + | ParsedInput.ImplFile _ as p -> Navigation.getNavigation p - | Some (ParsedInput.SigFile _) -> - Navigation.empty - | _ -> + | ParsedInput.SigFile _ -> Navigation.empty) (fun err -> Trace.TraceInformation(sprintf "FCS: recovering from error in GetNavigationItemsImpl: '%s'" err) @@ -685,7 +663,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput let walkImplFile (modules: SynModuleOrNamespace list) = List.collect walkModule modules match input with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (modules = modules))) -> walkImplFile modules + | ParsedInput.ImplFile (ParsedImplFileInput (modules = modules)) -> walkImplFile modules | _ -> [] ErrorScope.Protect range0 @@ -719,9 +697,8 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput member _.FileName = match input with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (fileName = modname))) - | Some (ParsedInput.SigFile (ParsedSigFileInput (fileName = modname))) -> modname - | _ -> "" + | ParsedInput.ImplFile (ParsedImplFileInput (fileName = modname)) + | ParsedInput.SigFile (ParsedSigFileInput (fileName = modname)) -> modname // Get items for the navigation drop down bar member scope.GetNavigationItems() = diff --git a/src/fsharp/service/FSharpParseFileResults.fsi b/src/fsharp/service/FSharpParseFileResults.fsi index 8385e82ec35..c8e9f2d0f85 100644 --- a/src/fsharp/service/FSharpParseFileResults.fsi +++ b/src/fsharp/service/FSharpParseFileResults.fsi @@ -12,7 +12,10 @@ open FSharp.Compiler.Text type public FSharpParseFileResults = /// The syntax tree resulting from the parse - member ParseTree: ParsedInput option + member ParseTree: ParsedInput + + /// The source text from which the parse originated, if it wasn't read from disk + member SourceText: ISourceText option /// Attempts to find the range of the name of the nearest outer binding that contains a given position. member TryRangeOfNameOfNearestOuterBindingContainingPos: pos: pos -> range option @@ -70,5 +73,5 @@ type public FSharpParseFileResults = /// Indicates if any errors occurred during the parse member ParseHadErrors: bool - internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput option * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults + internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput * sourceText: ISourceText option * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 384b60b4bd1..c34d628ee87 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -123,13 +123,13 @@ module IncrementalBuildSyntaxTree = [], isLastCompiland ) - ) |> Some + ) else ParseOneInputFile(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, (*retryLocked*)true) fileParsed.Trigger filename - let res = input, sourceRange, filename, errorLogger.GetErrors () + let res = input, sourceRange, filename, errorLogger.GetDiagnostics() // If we do not skip parsing the file, then we can cache the real result. if not canSkip then weakCache <- Some(WeakReference<_>(res)) @@ -180,7 +180,7 @@ type TcInfo = /// Accumulated results of type checking. Optional data that isn't needed to type-check a file, but needed for more information for in tooling. [] -type TcInfoOptional = +type TcInfoExtras = { /// Accumulated resolutions, last file first tcResolutionsRev: TcResolutions list @@ -204,13 +204,21 @@ type TcInfoOptional = member x.TcSymbolUses = List.rev x.tcSymbolUsesRev + member x.TcImplFiles = + List.rev x.tcImplFilesRev + /// Accumulated results of type checking. [] type TcInfoState = | PartialState of TcInfo - | FullState of TcInfo * TcInfoOptional + | FullState of TcInfo * TcInfoExtras - member this.Partial = + member this.TcInfoWithOptionalExtras = + match this with + | PartialState tcInfo -> tcInfo, None + | FullState(tcInfo, tcInfoExtras) -> tcInfo, Some tcInfoExtras + + member this.TcInfo = match this with | PartialState tcInfo -> tcInfo | FullState(tcInfo, _) -> tcInfo @@ -227,16 +235,16 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked: Event, fileChecked: Event, prevTcInfo: TcInfo, - prevTcInfoOptional: (unit -> Eventually), + prevTcInfoExtras: (unit -> Eventually), syntaxTreeOpt: SyntaxTree option, tcInfoStateOpt: TcInfoState option) = let mutable lazyTcInfoState = tcInfoStateOpt let defaultTypeCheck () = eventually { - match prevTcInfoOptional() with - | Eventually.Done(Some prevTcInfoOptional) -> - return FullState(prevTcInfo, prevTcInfoOptional) + match prevTcInfoExtras() with + | Eventually.Done(Some prevTcInfoExtras) -> + return FullState(prevTcInfo, prevTcInfoExtras) | _ -> return PartialState prevTcInfo } @@ -303,7 +311,7 @@ type BoundModel private (tcConfig: TcConfig, eventually { let! prevState = this.GetState(false) match prevState with - | FullState(_, prevTcInfoOptional) -> return Some prevTcInfoOptional + | FullState(_, prevTcInfoExtras) -> return Some prevTcInfoExtras | _ -> return None } @@ -323,7 +331,7 @@ type BoundModel private (tcConfig: TcConfig, enablePartialTypeChecking, beforeFileChecked, fileChecked, - prevState.Partial, + prevState.TcInfo, (fun () -> this.TryOptional()), Some syntaxTree, None) @@ -333,11 +341,11 @@ type BoundModel private (tcConfig: TcConfig, eventually { let! state = this.GetState(true) - let finishTcInfo = { state.Partial with tcErrorsRev = finalTcErrorsRev; topAttribs = finalTopAttribs } + let finishTcInfo = { state.TcInfo with tcErrorsRev = finalTcErrorsRev; topAttribs = finalTopAttribs } let finishState = match state with | PartialState(_) -> PartialState(finishTcInfo) - | FullState(_, tcInfoOptional) -> FullState(finishTcInfo, tcInfoOptional) + | FullState(_, tcInfoExtras) -> FullState(finishTcInfo, tcInfoExtras) return BoundModel( @@ -353,7 +361,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked, fileChecked, prevTcInfo, - prevTcInfoOptional, + prevTcInfoExtras, syntaxTreeOpt, Some finishState) } @@ -361,14 +369,20 @@ type BoundModel private (tcConfig: TcConfig, member this.TcInfo = eventually { let! state = this.GetState(true) - return state.Partial + return state.TcInfo } - member this.TcInfoWithOptional = + member this.TcInfoWithOptionalExtras = + eventually { + let! state = this.GetState(true) + return state.TcInfoWithOptionalExtras + } + + member this.TcInfoWithExtras = eventually { let! state = this.GetState(false) match state with - | FullState(tcInfo, tcInfoOptional) -> return tcInfo, tcInfoOptional + | FullState(tcInfo, tcInfoExtras) -> return tcInfo, tcInfoExtras | PartialState tcInfo -> return tcInfo, @@ -399,7 +413,7 @@ type BoundModel private (tcConfig: TcConfig, else None match syntaxTree.Parse sigNameOpt with - | Some input, _sourceRange, filename, parseErrors -> + | input, _sourceRange, filename, parseErrors -> IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBETypechecked filename) let capturingErrorLogger = CompilationErrorLogger("TypeCheck", tcConfig.errorSeverityOptions) let errorLogger = GetErrorLoggerFilteringByScopedPragmas(false, GetScopedPragmasForInput input, capturingErrorLogger) @@ -429,7 +443,7 @@ type BoundModel private (tcConfig: TcConfig, Logger.LogBlockMessageStop filename LogCompilerFunctionId.IncrementalBuild_TypeCheck fileChecked.Trigger filename - let newErrors = Array.append parseErrors (capturingErrorLogger.GetErrors()) + let newErrors = Array.append parseErrors (capturingErrorLogger.GetDiagnostics()) let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnvAtEndOfFile else tcState.TcEnvFromImpls @@ -453,9 +467,9 @@ type BoundModel private (tcConfig: TcConfig, if partialCheck then return PartialState tcInfo else - match! prevTcInfoOptional() with + match! prevTcInfoExtras() with | None -> return PartialState tcInfo - | Some prevTcInfoOptional -> + | Some prevTcInfoExtras -> // Build symbol keys let itemKeyStore, semanticClassification = if enableBackgroundItemKeyStoreAndSemanticClassification then @@ -482,18 +496,18 @@ type BoundModel private (tcConfig: TcConfig, else None, None - let tcInfoOptional = + let tcInfoExtras = { /// Only keep the typed interface files when doing a "full" build for fsc.exe, otherwise just throw them away - tcImplFilesRev = match implFile with Some f when keepAssemblyContents -> f :: prevTcInfoOptional.tcImplFilesRev | _ -> prevTcInfoOptional.tcImplFilesRev - tcResolutionsRev = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty) :: prevTcInfoOptional.tcResolutionsRev - tcSymbolUsesRev = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty) :: prevTcInfoOptional.tcSymbolUsesRev - tcOpenDeclarationsRev = sink.GetOpenDeclarations() :: prevTcInfoOptional.tcOpenDeclarationsRev + tcImplFilesRev = match implFile with Some f when keepAssemblyContents -> f :: prevTcInfoExtras.tcImplFilesRev | _ -> prevTcInfoExtras.tcImplFilesRev + tcResolutionsRev = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty) :: prevTcInfoExtras.tcResolutionsRev + tcSymbolUsesRev = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty) :: prevTcInfoExtras.tcSymbolUsesRev + tcOpenDeclarationsRev = sink.GetOpenDeclarations() :: prevTcInfoExtras.tcOpenDeclarationsRev itemKeyStore = itemKeyStore semanticClassificationKeyStore = semanticClassification } - return FullState(tcInfo, tcInfoOptional) + return FullState(tcInfo, tcInfoExtras) } @@ -511,8 +525,6 @@ type BoundModel private (tcConfig: TcConfig, use unwind = new CompilationGlobalsScope (errorLogger, BuildPhase.TypeCheck) f ctok) return! timeSlicedComputation - | _ -> - return! defaultTypeCheck () } static member Create(tcConfig: TcConfig, @@ -525,7 +537,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked: Event, fileChecked: Event, prevTcInfo: TcInfo, - prevTcInfoOptional: (unit -> Eventually), + prevTcInfoExtras: (unit -> Eventually), syntaxTreeOpt: SyntaxTree option) = BoundModel(tcConfig, tcGlobals, tcImports, keepAssemblyContents, keepAllBackgroundResolutions, @@ -535,7 +547,7 @@ type BoundModel private (tcConfig: TcConfig, beforeFileChecked, fileChecked, prevTcInfo, - prevTcInfoOptional, + prevTcInfoExtras, syntaxTreeOpt, None) @@ -605,16 +617,18 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime) = member _.TimeStamp = timeStamp - member _.TcInfo ctok = boundModel.TcInfo |> eval ctok + member _.ComputeTcInfoWithOptionalExtras ctok = boundModel.TcInfoWithOptionalExtras |> eval ctok + + member _.ComputeTcInfoWithExtras ctok = boundModel.TcInfoWithExtras |> eval ctok - member _.TcInfoWithOptional ctok = boundModel.TcInfoWithOptional |> eval ctok + member _.ComputeTcInfo ctok = boundModel.TcInfo |> eval ctok member _.TryGetItemKeyStore ctok = - let _, info = boundModel.TcInfoWithOptional |> eval ctok + let _, info = boundModel.TcInfoWithExtras |> eval ctok info.itemKeyStore member _.GetSemanticClassification ctok = - let _, info = boundModel.TcInfoWithOptional |> eval ctok + let _, info = boundModel.TcInfoWithExtras |> eval ctok info.semanticClassificationKeyStore [] @@ -779,10 +793,9 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, | None -> () | Some loadClosure -> for inp in loadClosure.Inputs do - for (err, isError) in inp.MetaCommandDiagnostics do - yield err, (if isError then FSharpDiagnosticSeverity.Error else FSharpDiagnosticSeverity.Warning) ] + yield! inp.MetaCommandDiagnostics ] - let initialErrors = Array.append (Array.ofList loadClosureErrors) (errorLogger.GetErrors()) + let initialErrors = Array.append (Array.ofList loadClosureErrors) (errorLogger.GetDiagnostics()) let tcInfo = { tcState=tcState @@ -794,7 +807,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, tcDependencyFiles = basicDependencies sigNameOpt = None } - let tcInfoOptional = + let tcInfoExtras = { tcResolutionsRev=[] tcSymbolUsesRev=[] @@ -817,7 +830,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, beforeFileChecked, fileChecked, tcInfo, - (fun () -> Eventually.Done (Some tcInfoOptional)), + (fun () -> Eventually.Done (Some tcInfoExtras)), None) } /// Type check all files. @@ -855,8 +868,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, let tcInfo = boundModel.TcInfo |> Eventually.force ctok tcInfo, [] else - let tcInfo, tcInfoOptional = boundModel.TcInfoWithOptional |> Eventually.force ctok - tcInfo, tcInfoOptional.tcImplFilesRev + let tcInfo, tcInfoExtras = boundModel.TcInfoWithExtras |> Eventually.force ctok + tcInfo, tcInfoExtras.tcImplFilesRev assert tcInfo.latestCcuSigForFile.IsSome assert boundModel.SyntaxTree.IsSome @@ -921,7 +934,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, errorRecoveryNoRange e mkSimpleAssemblyRef assemblyName, None, None - let finalBoundModelWithErrors = finalBoundModel.Finish((errorLogger.GetErrors() :: finalInfo.tcErrorsRev), Some topAttrs) |> Eventually.force ctok + let finalBoundModelWithErrors = finalBoundModel.Finish((errorLogger.GetDiagnostics() :: finalInfo.tcErrorsRev), Some topAttrs) |> Eventually.force ctok return ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, finalBoundModelWithErrors } @@ -1213,7 +1226,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, cancellable { try let! result = builder.GetCheckResultsAfterFileInProject(ctok, filename) - result.TcInfoWithOptional ctok |> ignore // Make sure we forcefully evaluate the info + result.ComputeTcInfoWithExtras ctok |> ignore // Make sure we forcefully evaluate the info return result finally enablePartialTypeChecking <- defaultPartialTypeChecking @@ -1240,7 +1253,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, try let! result = this.GetCheckResultsAndImplementationsForProject(ctok) let results, _, _, _ = result - results.TcInfoWithOptional ctok |> ignore // Make sure we forcefully evaluate the info + results.ComputeTcInfoWithExtras ctok |> ignore // Make sure we forcefully evaluate the info return result finally enablePartialTypeChecking <- defaultPartialTypeChecking @@ -1405,7 +1418,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, // included in these references. let! (tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences) = frameworkTcImportsCache.Get(ctok, tcConfig) - // Note we are not calling errorLogger.GetErrors() anywhere for this task. + // Note we are not calling errorLogger.GetDiagnostics() anywhere for this task. // This is ok because not much can actually go wrong here. let errorOptions = tcConfig.errorSeverityOptions let errorLogger = CompilationErrorLogger("nonFrameworkAssemblyInputs", errorOptions) @@ -1417,7 +1430,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, // // This operation is done when constructing the builder itself, rather than as an incremental task. let nonFrameworkAssemblyInputs = - // Note we are not calling errorLogger.GetErrors() anywhere for this task. + // Note we are not calling errorLogger.GetDiagnostics() anywhere for this task. // This is ok because not much can actually go wrong here. let errorLogger = CompilationErrorLogger("nonFrameworkAssemblyInputs", errorOptions) // Return the disposable object that cleans up @@ -1430,7 +1443,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, for pr in projectReferences do yield Choice2Of2 pr, (fun (cache: TimeStampCache) ctok -> cache.GetProjectReferenceTimeStamp (pr, ctok)) ] - let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig) + let analyzers = FSharpAnalyzers.ImportAnalyzers(tcConfig, tcConfig.compilerToolPaths) let analyzersRequireAssemblyContents = analyzers |> List.exists (fun analyzer -> analyzer.RequiresAssemblyContents) @@ -1471,10 +1484,10 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, let errorSeverityOptions = builder.TcConfig.errorSeverityOptions let errorLogger = CompilationErrorLogger("IncrementalBuilderCreation", errorSeverityOptions) delayedLogger.CommitDelayedDiagnostics errorLogger - errorLogger.GetErrors() |> Array.map (fun (d, severity) -> d, severity = FSharpDiagnosticSeverity.Error) + errorLogger.GetDiagnostics() | _ -> Array.ofList delayedLogger.Diagnostics - |> Array.map (fun (d, isError) -> FSharpDiagnostic.CreateFromException(d, isError, range.Zero, suggestNamesForErrors)) + |> Array.map (fun (d, severity) -> FSharpDiagnostic.CreateFromException(d, severity, range.Zero, suggestNamesForErrors)) return builderOpt, diagnostics } diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index f796759f233..332b384d69e 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -69,7 +69,7 @@ type internal TcInfo = /// Accumulated results of type checking. Optional data that isn't needed to type-check a file, but needed for more information for in tooling. [] -type internal TcInfoOptional = +type internal TcInfoExtras = { /// Accumulated resolutions, last file first tcResolutionsRev: TcResolutions list @@ -80,7 +80,7 @@ type internal TcInfoOptional = /// Accumulated 'open' declarations, last file first tcOpenDeclarationsRev: OpenDeclaration[] list - /// Result of checking most recent file, if any, last file first + /// Contents of checking files, if any, last file first tcImplFilesRev: TypedImplFile list /// If enabled, stores a linear list of ranges and strings that identify an Item(symbol) in a file. Used for background find all references. @@ -92,6 +92,8 @@ type internal TcInfoOptional = member TcSymbolUses: TcSymbolUses list + member TcImplFiles: TypedImplFile list + /// Represents the state in the incremental graph associated with checking a file [] type internal PartialCheckResults = @@ -104,11 +106,14 @@ type internal PartialCheckResults = member TimeStamp: DateTime - member TcInfo: CompilationThreadToken -> TcInfo + member ComputeTcInfo: CompilationThreadToken -> TcInfo + + /// If `enablePartialTypeChecking` is false then extras will be available + member ComputeTcInfoWithOptionalExtras: CompilationThreadToken -> TcInfo * TcInfoExtras option /// Can cause a second type-check if `enablePartialTypeChecking` is true in the checker. /// Only use when it's absolutely necessary to get rich information on a file. - member TcInfoWithOptional: CompilationThreadToken -> TcInfo * TcInfoOptional + member ComputeTcInfoWithExtras: CompilationThreadToken -> TcInfo * TcInfoExtras /// Can cause a second type-check if `enablePartialTypeChecking` is true in the checker. /// Only use when it's absolutely necessary to get rich information on a file. @@ -217,7 +222,7 @@ type internal IncrementalBuilder = /// Await the untyped parse results for a particular slot in the vector of parse results. /// /// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed) - member GetParseResultsForFile: filename:string -> ParsedInput option * range * string * (PhasedDiagnostic * FSharpDiagnosticSeverity)[] + member GetParseResultsForFile: filename:string -> ParsedInput * range * string * (PhasedDiagnostic * FSharpDiagnosticSeverity)[] /// Get the active analyzers for the project member Analyzers: FSharpAnalyzer list diff --git a/src/fsharp/service/ServiceParsedInputOps.fs b/src/fsharp/service/ServiceParsedInputOps.fs index 502a920bac3..93cfd5b6558 100644 --- a/src/fsharp/service/ServiceParsedInputOps.fs +++ b/src/fsharp/service/ServiceParsedInputOps.fs @@ -193,10 +193,7 @@ module ParsedInput = let emptyStringSet = HashSet() - let GetRangeOfExprLeftOfDot(pos: pos, parsedInputOpt) = - match parsedInputOpt with - | None -> None - | Some parseTree -> + let GetRangeOfExprLeftOfDot(pos: pos, parsedInput) = let CheckLongIdent(longIdent: LongIdent) = // find the longest prefix before the "pos" dot let mutable r = (List.head longIdent).idRange @@ -207,7 +204,7 @@ module ParsedInput = couldBeBeforeFront <- false couldBeBeforeFront, r - SyntaxTraversal.Traverse(pos, parseTree, { new SyntaxVisitorBase<_>() with + SyntaxTraversal.Traverse(pos, parsedInput, { new SyntaxVisitorBase<_>() with member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = let expr = expr // fix debugger locals match expr with @@ -290,10 +287,7 @@ module ParsedInput = }) /// searches for the expression island suitable for the evaluation by the debugger - let TryFindExpressionIslandInPosition(pos: pos, parsedInputOpt) = - match parsedInputOpt with - | None -> None - | Some parseTree -> + let TryFindExpressionIslandInPosition(pos: pos, parsedInput) = let getLidParts (lid : LongIdent) = lid |> Seq.takeWhile (fun i -> posGeq pos i.idRange.Start) @@ -332,7 +326,7 @@ module ParsedInput = | _ -> defaultTraverse expr else None } - SyntaxTraversal.Traverse(pos, parseTree, walker) + SyntaxTraversal.Traverse(pos, parsedInput, walker) // Given a cursor position here: // f(x) . ident @@ -346,10 +340,7 @@ module ParsedInput = // ^ // would return None // TODO would be great to unify this with GetRangeOfExprLeftOfDot above, if possible, as they are similar - let TryFindExpressionASTLeftOfDotLeftOfCursor(pos, parsedInputOpt) = - match parsedInputOpt with - | None -> None - | Some parseTree -> + let TryFindExpressionASTLeftOfDotLeftOfCursor(pos, parsedInput) = let dive x = SyntaxTraversal.dive x let pick x = SyntaxTraversal.pick pos x let walker = @@ -441,7 +432,7 @@ module ParsedInput = Some (lhs.Range.End, false) | x -> x // we found the answer deeper somewhere in the lhs | _ -> defaultTraverse expr } - SyntaxTraversal.Traverse(pos, parseTree, walker) + SyntaxTraversal.Traverse(pos, parsedInput, walker) let GetEntityKind (pos: pos, parsedInput: ParsedInput) : EntityKind option = let (|ConstructorPats|) = function @@ -1158,7 +1149,7 @@ module ParsedInput = | SynArgPats.NamePatPairs(xs, _) -> List.map snd xs /// Returns all `Ident`s and `LongIdent`s found in an untyped AST. - let getLongIdents (parsedInput: ParsedInput option) : IDictionary = + let getLongIdents (parsedInput: ParsedInput) : IDictionary = let identsByEndPos = Dictionary() let addLongIdent (longIdent: LongIdent) = @@ -1497,14 +1488,14 @@ module ParsedInput = | _ -> () match parsedInput with - | Some (ParsedInput.ImplFile input) -> + | ParsedInput.ImplFile input -> walkImplFileInput input | _ -> () //debug "%A" idents upcast identsByEndPos let GetLongIdentAt parsedInput pos = - let idents = getLongIdents (Some parsedInput) + let idents = getLongIdents parsedInput match idents.TryGetValue pos with | true, idents -> Some idents | _ -> None diff --git a/src/fsharp/service/ServiceParsedInputOps.fsi b/src/fsharp/service/ServiceParsedInputOps.fsi index a807eb920ea..d0c36e03cc9 100644 --- a/src/fsharp/service/ServiceParsedInputOps.fsi +++ b/src/fsharp/service/ServiceParsedInputOps.fsi @@ -112,11 +112,11 @@ type public InsertionContextEntity = /// Operations querying the entire syntax tree module public ParsedInput = - val TryFindExpressionASTLeftOfDotLeftOfCursor: pos: pos * parsedInputOpt: ParsedInput option -> (pos * bool) option + val TryFindExpressionASTLeftOfDotLeftOfCursor: pos: pos * parsedInput: ParsedInput -> (pos * bool) option - val GetRangeOfExprLeftOfDot: pos: pos * parsedInputOpt: ParsedInput option -> range option + val GetRangeOfExprLeftOfDot: pos: pos * parsedInput: ParsedInput -> range option - val TryFindExpressionIslandInPosition: pos: pos * parsedInputOpt: ParsedInput option -> string option + val TryFindExpressionIslandInPosition: pos: pos * parsedInput: ParsedInput -> string option val TryGetCompletionContext: pos: pos * parsedInput: ParsedInput * lineStr: string -> CompletionContext option diff --git a/src/fsharp/service/ServiceXmlDocParser.fs b/src/fsharp/service/ServiceXmlDocParser.fs index 6a3e5688011..dfa65682314 100644 --- a/src/fsharp/service/ServiceXmlDocParser.fs +++ b/src/fsharp/service/ServiceXmlDocParser.fs @@ -40,7 +40,7 @@ module XmlDocParsing = | SynPat.InstanceMember _ | SynPat.FromParseError _ -> [] - let getXmlDocablesImpl(sourceText: ISourceText, input: ParsedInput option) = + let getXmlDocablesImpl(sourceText: ISourceText, input: ParsedInput) = let indentOf (lineNum: int) = let mutable i = 0 let line = sourceText.GetLineString(lineNum-1) // -1 because lineNum reported by xmldocs are 1-based, but array is 0-based @@ -151,12 +151,7 @@ module XmlDocParsing = | ParsedInput.SigFile _ -> [] // Get compiler options for the 'project' implied by a single script file - match input with - | Some input -> - getXmlDocablesInput input - | None -> - // Should not fail here, just in case - [] + getXmlDocablesInput input module XmlDocComment = let ws (s: string, pos) = diff --git a/src/fsharp/service/ServiceXmlDocParser.fsi b/src/fsharp/service/ServiceXmlDocParser.fsi index 33e1e100dbd..bf3ef76e2e4 100644 --- a/src/fsharp/service/ServiceXmlDocParser.fsi +++ b/src/fsharp/service/ServiceXmlDocParser.fsi @@ -17,5 +17,5 @@ module public XmlDocComment = module public XmlDocParser = /// Get the list of Xml documentation from current source code - val GetXmlDocables: ISourceText * input: ParsedInput option -> XmlDocable list + val GetXmlDocables: ISourceText * input: ParsedInput -> XmlDocable list \ No newline at end of file diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index bf3b7df3753..01c7c87443d 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -25,6 +25,7 @@ open FSharp.Compiler.EditorServices open FSharp.Compiler.ErrorLogger open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.IO +open FSharp.Compiler.ParseAndCheckInputs open FSharp.Compiler.ScriptClosure open FSharp.Compiler.Symbols open FSharp.Compiler.Syntax @@ -405,13 +406,13 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | Some res -> return res | None -> foregroundParseCount <- foregroundParseCount + 1 - let parseDiags, parseTreeOpt, anyErrors = ParseAndCheckFile.parseFile(sourceText, filename, options, userOpName, suggestNamesForErrors) - let res = FSharpParseFileResults(parseDiags, parseTreeOpt, anyErrors, options.SourceFiles) + let parseDiags, parseTree, anyErrors = ParseAndCheckFile.parseFile(sourceText, filename, options, userOpName, suggestNamesForErrors) + let res = FSharpParseFileResults(parseDiags, parseTree, Some sourceText, anyErrors, options.SourceFiles) parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (filename, hash, options), res)) return res else - let parseDiags, parseTreeOpt, anyErrors = ParseAndCheckFile.parseFile(sourceText, filename, options, userOpName, false) - return FSharpParseFileResults(parseDiags, parseTreeOpt, anyErrors, options.SourceFiles) + let parseDiags, parseTree, anyErrors = ParseAndCheckFile.parseFile(sourceText, filename, options, userOpName, false) + return FSharpParseFileResults(parseDiags, parseTree, Some sourceText, anyErrors, options.SourceFiles) } /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) @@ -428,11 +429,11 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC async { let! builderOpt, creationDiags = getBuilder options match builderOpt with - | None -> return FSharpParseFileResults(creationDiags, None, true, [| |]) + | None -> return FSharpParseFileResults(creationDiags, EmptyParsedInput(filename, (false, false)), None, true, [| |]) | Some builder -> - let parseTreeOpt,_,_,parseDiags = builder.GetParseResultsForFile (filename) + let parseTree,_,_,parseDiags = builder.GetParseResultsForFile (filename) let diagnostics = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (builder.TcConfig.errorSeverityOptions, false, filename, parseDiags, suggestNamesForErrors) |] - return FSharpParseFileResults(diagnostics = diagnostics, input = parseTreeOpt, parseHadErrors = false, dependencyFiles = builder.AllDependenciesDeprecated) + return FSharpParseFileResults(diagnostics = diagnostics, input = parseTree, sourceText=None, parseHadErrors = false, dependencyFiles = builder.AllDependenciesDeprecated) } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, filename, sourceText: ISourceText, options) = @@ -471,14 +472,9 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC options: FSharpProjectOptions, fileVersion: int, builder: IncrementalBuilder, - tcConfig, - tcGlobals, - tcImports, - tcDependencyFiles, - timeStamp, - prevTcState, - prevModuleNamesDict, - prevTcErrors, + tcPrior: PartialCheckResults, + tcInfo: TcInfo, + tcInfoOptionalExtras: TcInfoExtras option, creationDiags: FSharpDiagnostic[], userOpName: string) = @@ -498,6 +494,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC // Get additional script #load closure information if applicable. // For scripts, this will have been recorded by GetProjectOptionsFromScript. let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options) + let tcConfig = tcPrior.TcConfig + let tcPriorImplFiles = (tcInfoOptionalExtras |> Option.map (fun i -> i.TcImplFiles) |> Option.defaultValue []) let! checkAnswer = FSharpCheckFileResults.CheckOneFile (parseResults, @@ -505,25 +503,26 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC fileName, options.ProjectFileName, tcConfig, - tcGlobals, - tcImports, - prevTcState, - prevModuleNamesDict, + tcPrior.TcGlobals, + tcPrior.TcImports, + tcInfo.tcState, + tcPriorImplFiles, + tcInfo.moduleNamesDict, loadClosure, - prevTcErrors, + tcInfo.TcErrors, reactorOps, userOpName, options.IsIncompleteTypeCheckEnvironment, box builder, options, - Array.ofList tcDependencyFiles, + Array.ofList tcInfo.tcDependencyFiles, creationDiags, parseResults.Diagnostics, builder.KeepAssemblyContents, suggestNamesForErrors) let parsingOptions = FSharpParsingOptions.FromTcConfig(tcConfig, Array.ofList builder.SourceFiles, options.UseScriptResolutionRules) reactor.SetPreferredUILang tcConfig.preferredUiLang - bc.RecordCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, timeStamp, Some checkAnswer, sourceText.GetHashCode()) + bc.RecordCheckFileInProjectResults(fileName, options, parsingOptions, parseResults, fileVersion, tcPrior.TimeStamp, Some checkAnswer, sourceText.GetHashCode()) return checkAnswer finally let dummy = ref () @@ -572,13 +571,13 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC return tcPrior |> Option.map (fun tcPrior -> - (tcPrior, tcPrior.TcInfo ctok) + (tcPrior, tcPrior.ComputeTcInfoWithOptionalExtras ctok) ) } match tcPrior with - | Some(tcPrior, tcInfo) -> - let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior.TcConfig, tcPrior.TcGlobals, tcPrior.TcImports, tcInfo.tcDependencyFiles, tcPrior.TimeStamp, tcInfo.tcState, tcInfo.moduleNamesDict, tcInfo.TcErrors, creationDiags, userOpName) + | Some(tcPrior, (tcInfo, tcInfoOptionalExtras)) -> + let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, tcInfoOptionalExtras, creationDiags, userOpName) return Some checkResults | None -> return None // the incremental builder was not up to date finally @@ -611,13 +610,13 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | Some (_, checkResults) -> return FSharpCheckFileAnswer.Succeeded checkResults | _ -> Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "CheckFileInProject.CacheMiss", filename) - let! tcPrior, tcInfo = + let! tcPrior, (tcInfo, tcInfoOptionalExtras) = execWithReactorAsync <| fun ctok -> cancellable { let! tcPrior = builder.GetCheckResultsBeforeFileInProject (ctok, filename) - return (tcPrior, tcPrior.TcInfo ctok) + return (tcPrior, tcPrior.ComputeTcInfoWithOptionalExtras ctok) } - let! checkAnswer = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior.TcConfig, tcPrior.TcGlobals, tcPrior.TcImports, tcInfo.tcDependencyFiles, tcPrior.TimeStamp, tcInfo.tcState, tcInfo.moduleNamesDict, tcInfo.TcErrors, creationDiags, userOpName) + let! checkAnswer = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, tcInfoOptionalExtras, creationDiags, userOpName) return checkAnswer finally bc.ImplicitlyStartCheckProjectInBackground(options, userOpName) @@ -647,7 +646,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | None -> Logger.LogBlockMessageStop (filename + strGuid + "-Failed_Aborted") LogCompilerFunctionId.Service_ParseAndCheckFileInProject - let parseResults = FSharpParseFileResults(creationDiags, None, true, [| |]) + let parseTree = EmptyParsedInput(filename, (false, false)) + let parseResults = FSharpParseFileResults(creationDiags, parseTree, Some sourceText , true, [| |]) return (parseResults, FSharpCheckFileAnswer.Aborted) | Some builder -> @@ -661,19 +661,19 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | _ -> // todo this blocks the Reactor queue until all files up to the current are type checked. It's OK while editing the file, // but results with non cooperative blocking when a firts file from a project opened. - let! tcPrior, tcInfo = + let! tcPrior, (tcInfo, tcInfoOptionalExtras) = execWithReactorAsync <| fun ctok -> cancellable { let! tcPrior = builder.GetCheckResultsBeforeFileInProject (ctok, filename) - return (tcPrior, tcPrior.TcInfo ctok) + return (tcPrior, tcPrior.ComputeTcInfoWithOptionalExtras ctok) } // Do the parsing. let parsingOptions = FSharpParsingOptions.FromTcConfig(builder.TcConfig, Array.ofList (builder.SourceFiles), options.UseScriptResolutionRules) reactor.SetPreferredUILang tcPrior.TcConfig.preferredUiLang - let parseDiags, parseTreeOpt, anyErrors = ParseAndCheckFile.parseFile (sourceText, filename, parsingOptions, userOpName, suggestNamesForErrors) - let parseResults = FSharpParseFileResults(parseDiags, parseTreeOpt, anyErrors, builder.AllDependenciesDeprecated) - let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior.TcConfig, tcPrior.TcGlobals, tcPrior.TcImports, tcInfo.tcDependencyFiles, tcPrior.TimeStamp, tcInfo.tcState, tcInfo.moduleNamesDict, tcInfo.TcErrors, creationDiags, userOpName) + let parseDiags, parseTree, anyErrors = ParseAndCheckFile.parseFile (sourceText, filename, parsingOptions, userOpName, suggestNamesForErrors) + let parseResults = FSharpParseFileResults(parseDiags, parseTree, Some sourceText, anyErrors, builder.AllDependenciesDeprecated) + let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, tcInfoOptionalExtras, creationDiags, userOpName) Logger.LogBlockMessageStop (filename + strGuid + "-Successful") LogCompilerFunctionId.Service_ParseAndCheckFileInProject @@ -682,7 +682,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC bc.ImplicitlyStartCheckProjectInBackground(options, userOpName) } - member bc.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, userOpName) = + member bc.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, options, userOpName) = let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "AnalyzeFileInProject", parseResults.FileName, action) async { let! analysisDiags = execWithReactorAsync (fun ctok -> @@ -693,21 +693,17 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | Some builder -> let fileName = Path.GetFullPath parseResults.FileName let! ct = Cancellable.token() - let ctxt = - FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], - checkResults, - ct, - builder.TcConfig) + let ctxt = FSharpAnalyzerCheckFilesContext([| checkResults |], ct) let diags = let diagsCollector = ResizeArray() for analyzer in builder.Analyzers do let moreDiags = - try analyzer.OnCheckFile(ctxt) + try analyzer.OnCheckFiles(ctxt) with exn -> let m = Range.rangeN fileName 0 let errExn = Error(FSComp.SR.etAnalyzerException(analyzer.GetType().FullName, fileName, exn.ToString()), m) - let diag = FSharpDiagnostic.CreateFromException(PhasedDiagnostic.Create(errExn, BuildPhase.TypeCheck), false, m, false) + let diag = FSharpDiagnostic.CreateFromException(PhasedDiagnostic.Create(errExn, BuildPhase.TypeCheck), FSharpDiagnosticSeverity.Warning, m, false) [| diag |] diagsCollector.AddRange(moreDiags) diagsCollector.ToArray() @@ -716,8 +712,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC return analysisDiags } - member bc.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, pos: Position, userOpName) = - let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "AnalyzeFileInProject", parseResults.FileName, action) + member bc.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, options, pos: Position, userOpName) = + let execWithReactorAsync action = reactor.EnqueueAndAwaitOpAsync(userOpName, "GetAdditionalAnalyzerToolTips", parseResults.FileName, action) async { let! analysisDiags = execWithReactorAsync (fun ctok -> cancellable { @@ -727,11 +723,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC | Some builder -> let fileName = Path.GetFullPath parseResults.FileName let! ct = Cancellable.token() - let ctxt = - FSharpAnalyzerCheckFileContext([| (fileName, sourceText) |], - checkResults, - ct, - builder.TcConfig) + let ctxt = FSharpAnalyzerCheckFilesContext([| checkResults |], ct) let tooltips = let tooltipsCollector = ResizeArray() @@ -757,28 +749,29 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let! builderOpt, creationDiags = getOrCreateBuilder (ctok, options, userOpName) match builderOpt with | None -> - let parseResults = FSharpParseFileResults(creationDiags, None, true, [| |]) + let parseTree = EmptyParsedInput(filename, (false, false)) + let parseResults = FSharpParseFileResults(creationDiags, parseTree, None, true, [| |]) let typedResults = FSharpCheckFileResults.MakeEmpty(filename, creationDiags, true) return (parseResults, typedResults) | Some builder -> - let (parseTreeOpt, _, _, parseDiags) = builder.GetParseResultsForFile (filename) + let (parseTree, _, _, parseDiags) = builder.GetParseResultsForFile (filename) let! tcProj = builder.GetFullCheckResultsAfterFileInProject (ctok, filename) - let tcInfo, tcInfoOptional = tcProj.TcInfoWithOptional ctok + let tcInfo, tcInfoExtras = tcProj.ComputeTcInfoWithExtras ctok - let tcResolutionsRev = tcInfoOptional.tcResolutionsRev - let tcSymbolUsesRev = tcInfoOptional.tcSymbolUsesRev - let tcOpenDeclarationsRev = tcInfoOptional.tcOpenDeclarationsRev + let tcResolutionsRev = tcInfoExtras.tcResolutionsRev + let tcSymbolUsesRev = tcInfoExtras.tcSymbolUsesRev + let tcOpenDeclarationsRev = tcInfoExtras.tcOpenDeclarationsRev let latestCcuSigForFile = tcInfo.latestCcuSigForFile let tcState = tcInfo.tcState let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile - let tcImplFiles = tcInfoOptional.tcImplFilesRev |> List.rev + let tcImplFiles = tcInfoExtras.tcImplFilesRev |> List.rev let tcDependencyFiles = tcInfo.tcDependencyFiles let tcErrors = tcInfo.TcErrors let errorOptions = builder.TcConfig.errorSeverityOptions let parseDiags = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (errorOptions, false, filename, parseDiags, suggestNamesForErrors) |] let tcErrors = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (errorOptions, false, filename, tcErrors, suggestNamesForErrors) |] - let parseResults = FSharpParseFileResults(diagnostics = parseDiags, input = parseTreeOpt, parseHadErrors = false, dependencyFiles = builder.AllDependenciesDeprecated) + let parseResults = FSharpParseFileResults(diagnostics=parseDiags, input=parseTree, sourceText=None, parseHadErrors=false, dependencyFiles=builder.AllDependenciesDeprecated) let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options) let typedResults = FSharpCheckFileResults.Make @@ -788,7 +781,8 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC tcProj.TcGlobals, options.IsIncompleteTypeCheckEnvironment, Some (box builder), - parseTreeOpt, + parseTree, + None, options, Array.ofList tcDependencyFiles, creationDiags, @@ -860,9 +854,9 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC let errorOptions = tcProj.TcConfig.errorSeverityOptions let fileName = TcGlobals.DummyFileNameForRangesWithoutASpecificLocation - let tcInfo, tcInfoOptional = tcProj.TcInfoWithOptional ctok + let tcInfo, tcInfoExtras = tcProj.ComputeTcInfoWithExtras ctok - let tcSymbolUses = tcInfoOptional.TcSymbolUses + let tcSymbolUses = tcInfoExtras.TcSymbolUses let topAttribs = tcInfo.topAttribs let tcState = tcInfo.tcState let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile @@ -1317,13 +1311,13 @@ type FSharpChecker(legacyReferenceResolver, ic.CheckMaxMemoryReached() backgroundCompiler.CheckFileInProject(parseResults,filename,fileVersion,sourceText,options,userOpName) - member ic.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, userOpName) = + member ic.AnalyzeFileInProject(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, options, userOpName) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.AnalyzeFileInProject(parseResults,checkResults,sourceText,options,userOpName) + backgroundCompiler.AnalyzeFileInProject(parseResults, checkResults, options, userOpName) - member ic.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, sourceText: ISourceText, options, pos: Position, userOpName) = + member ic.GetAdditionalAnalyzerToolTips(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, options, pos: Position, userOpName) = let userOpName = defaultArg userOpName "Unknown" - backgroundCompiler.GetAdditionalAnalyzerToolTips(parseResults,checkResults,sourceText,options,pos,userOpName) + backgroundCompiler.GetAdditionalAnalyzerToolTips(parseResults, checkResults, options, pos, userOpName) /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index 6d23856c9bb..d702cd8eb17 100644 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -129,10 +129,9 @@ type public FSharpChecker = /// /// The results of ParseFile for this file. /// The results of CheckFileInProject for this file. - /// The full source for the file. /// The options for the project or script. /// An optional string used for tracing compiler operations associated with this request. - member AnalyzeFileInProject: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async + member AnalyzeFileInProject: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * options: FSharpProjectOptions * ?userOpName: string -> Async /// /// Get the additional tooltips provided by all analyzers at a specific location @@ -140,11 +139,10 @@ type public FSharpChecker = /// /// The results of ParseFile for this file. /// The results of CheckFileInProject for this file. - /// The full source for the file. /// The options for the project or script. /// The position where the tool tip is requested. /// An optional string used for tracing compiler operations associated with this request. - member GetAdditionalAnalyzerToolTips: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * sourceText: ISourceText * options: FSharpProjectOptions * pos: Position * ?userOpName: string -> Async + member GetAdditionalAnalyzerToolTips: parseResults: FSharpParseFileResults * checkResults: FSharpCheckFileResults * options: FSharpProjectOptions * pos: Position * ?userOpName: string -> Async /// /// diff --git a/src/fsharp/symbols/Exprs.fsi b/src/fsharp/symbols/Exprs.fsi index 30e1ecad8d9..ebe433a21c0 100644 --- a/src/fsharp/symbols/Exprs.fsi +++ b/src/fsharp/symbols/Exprs.fsi @@ -35,6 +35,8 @@ type public FSharpImplementationFileContents = /// Indicates if the implementation file has an explicit entry point member HasExplicitEntryPoint: bool + // TODO: Add a stamp here to allow incrementalization w.r.t. FSharpAssemblyContents + /// Represents a declaration in an implementation file, as seen by the F# language [] type public FSharpImplementationFileDeclaration = diff --git a/src/fsharp/symbols/SymbolHelpers.fs b/src/fsharp/symbols/SymbolHelpers.fs index c671cedfc5f..19e47184d24 100644 --- a/src/fsharp/symbols/SymbolHelpers.fs +++ b/src/fsharp/symbols/SymbolHelpers.fs @@ -22,13 +22,6 @@ open FSharp.Compiler.Text open FSharp.Compiler.Text.Position open FSharp.Compiler.Text.Range -[] -type FSharpDiagnosticSeverity = - | Hidden - | Info - | Warning - | Error - type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: string, subcategory: string, errorNum: int, numberPrefix: string) = member _.Range = m @@ -74,16 +67,15 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str sprintf "%s (%d,%d)-(%d,%d) %s %s %s" fileName s.Line (s.Column + 1) e.Line (e.Column + 1) subcategory severity message /// Decompose a warning or error into parts: position, severity, message, error number - static member CreateFromException(exn, isError, fallbackRange: range, suggestNames: bool) = + static member CreateFromException(exn, severity, fallbackRange: range, suggestNames: bool) = let m = match GetRangeOfDiagnostic exn with Some m -> m | None -> fallbackRange - let severity = if isError then FSharpDiagnosticSeverity.Error else FSharpDiagnosticSeverity.Warning let msg = bufs (fun buf -> OutputPhasedDiagnostic buf exn false suggestNames) let errorNum = GetDiagnosticNumber exn FSharpDiagnostic(m, severity, msg, exn.Subcategory(), errorNum, "FS") /// Decompose a warning or error into parts: position, severity, message, error number - static member CreateFromExceptionAndAdjustEof(exn, isError, fallbackRange: range, (linesCount: int, lastLength: int), suggestNames: bool) = - let r = FSharpDiagnostic.CreateFromException(exn, isError, fallbackRange, suggestNames) + static member CreateFromExceptionAndAdjustEof(exn, severity, fallbackRange: range, (linesCount: int, lastLength: int), suggestNames: bool) = + let r = FSharpDiagnostic.CreateFromException(exn, severity, fallbackRange, suggestNames) // Adjust to make sure that errors reported at Eof are shown at the linesCount let startline, schange = min (Line.toZ r.Range.StartLine, false) (linesCount, true) @@ -112,10 +104,10 @@ type ErrorScope() = let unwindEL = PushErrorLoggerPhaseUntilUnwind (fun _oldLogger -> { new ErrorLogger("ErrorScope") with - member x.DiagnosticSink(exn, isError) = - let err = FSharpDiagnostic.CreateFromException(exn, isError, range.Zero, false) + member x.DiagnosticSink(exn, severity) = + let err = FSharpDiagnostic.CreateFromException(exn, severity, range.Zero, false) errors <- err :: errors - if isError && firstError.IsNone then + if severity = FSharpDiagnosticSeverity.Error && firstError.IsNone then firstError <- Some err.Message member x.ErrorCount = errors.Length }) @@ -171,8 +163,8 @@ type internal CompilationErrorLogger (debugName: string, options: FSharpDiagnost let mutable errorCount = 0 let diagnostics = new ResizeArray<_>() - override x.DiagnosticSink(exn, isError) = - if isError || ReportWarningAsError options exn then + override x.DiagnosticSink(exn, severity) = + if severity = FSharpDiagnosticSeverity.Error || ReportWarningAsError options exn then diagnostics.Add(exn, FSharpDiagnosticSeverity.Error) errorCount <- errorCount + 1 elif ReportWarning options exn then @@ -180,7 +172,7 @@ type internal CompilationErrorLogger (debugName: string, options: FSharpDiagnost override x.ErrorCount = errorCount - member x.GetErrors() = diagnostics.ToArray() + member x.GetDiagnostics() = diagnostics.ToArray() /// This represents the global state established as each task function runs as part of the build. @@ -197,14 +189,17 @@ type CompilationGlobalsScope(errorLogger: ErrorLogger, phase: BuildPhase) = module DiagnosticHelpers = - let ReportError (options: FSharpDiagnosticOptions, allErrors, mainInputFileName, fileInfo, (exn, sev), suggestNames) = - [ let isError = (sev = FSharpDiagnosticSeverity.Error) || ReportWarningAsError options exn - if (isError || ReportWarning options exn) then + let ReportDiagnostic (options: FSharpDiagnosticOptions, allErrors, mainInputFileName, fileInfo, (exn, severity), suggestNames) = + [ let severity = + if (severity = FSharpDiagnosticSeverity.Error) then severity + elif ReportWarningAsError options exn then FSharpDiagnosticSeverity.Error + else severity + if (severity = FSharpDiagnosticSeverity.Error || ReportWarning options exn) then let oneError exn = [ // We use the first line of the file as a fallbackRange for reporting unexpected errors. // Not ideal, but it's hard to see what else to do. let fallbackRange = rangeN mainInputFileName 1 - let ei = FSharpDiagnostic.CreateFromExceptionAndAdjustEof (exn, isError, fallbackRange, fileInfo, suggestNames) + let ei = FSharpDiagnostic.CreateFromExceptionAndAdjustEof (exn, severity, fallbackRange, fileInfo, suggestNames) let fileName = ei.Range.FileName if allErrors || fileName = mainInputFileName || fileName = TcGlobals.DummyFileNameForRangesWithoutASpecificLocation then yield ei ] @@ -216,8 +211,8 @@ module DiagnosticHelpers = let CreateDiagnostics (options, allErrors, mainInputFileName, errors, suggestNames) = let fileInfo = (Int32.MaxValue, Int32.MaxValue) - [| for (exn, isError) in errors do - yield! ReportError (options, allErrors, mainInputFileName, fileInfo, (exn, isError), suggestNames) |] + [| for (exn, severity) in errors do + yield! ReportDiagnostic (options, allErrors, mainInputFileName, fileInfo, (exn, severity), suggestNames) |] namespace FSharp.Compiler.Symbols diff --git a/src/fsharp/symbols/SymbolHelpers.fsi b/src/fsharp/symbols/SymbolHelpers.fsi index a91739b61a8..8a9c547ca34 100755 --- a/src/fsharp/symbols/SymbolHelpers.fsi +++ b/src/fsharp/symbols/SymbolHelpers.fsi @@ -10,13 +10,6 @@ namespace FSharp.Compiler.Diagnostics open FSharp.Compiler.Text open FSharp.Compiler.ErrorLogger - [] - type public FSharpDiagnosticSeverity = - | Hidden - | Info - | Warning - | Error - /// Represents a diagnostic produced by the F# compiler [] type public FSharpDiagnostic = @@ -66,9 +59,9 @@ namespace FSharp.Compiler.Diagnostics /// Creates a diagnostic, e.g. for reporting from an analyzer static member Create: severity: FSharpDiagnosticSeverity * message: string * number: int * range: range * ?numberPrefix: string * ?subcategory: string -> FSharpDiagnostic - static member internal CreateFromExceptionAndAdjustEof: PhasedDiagnostic * isError: bool * range * lastPosInFile: (int*int) * suggestNames: bool -> FSharpDiagnostic + static member internal CreateFromExceptionAndAdjustEof: PhasedDiagnostic * severity: FSharpDiagnosticSeverity * range * lastPosInFile: (int*int) * suggestNames: bool -> FSharpDiagnostic - static member internal CreateFromException: PhasedDiagnostic * isError: bool * range * suggestNames: bool -> FSharpDiagnostic + static member internal CreateFromException: PhasedDiagnostic * severity: FSharpDiagnosticSeverity * range * suggestNames: bool -> FSharpDiagnostic /// Newlines are recognized and replaced with (ASCII 29, the 'group separator'), /// which is decoded by the IDE with 'NewlineifyErrorString' back into newlines, so that multi-line errors can be displayed in QuickInfo @@ -93,11 +86,11 @@ namespace FSharp.Compiler.Diagnostics type internal CompilationErrorLogger = inherit ErrorLogger - /// Create the error logger + /// Create the diagnostics logger new: debugName:string * options: FSharpDiagnosticOptions -> CompilationErrorLogger - /// Get the captured errors - member GetErrors: unit -> (PhasedDiagnostic * FSharpDiagnosticSeverity)[] + /// Get the captured diagnostics + member GetDiagnostics: unit -> (PhasedDiagnostic * FSharpDiagnosticSeverity)[] /// This represents the global state established as each task function runs as part of the build. /// @@ -107,7 +100,7 @@ namespace FSharp.Compiler.Diagnostics interface IDisposable module internal DiagnosticHelpers = - val ReportError: FSharpDiagnosticOptions * allErrors: bool * mainInputFileName: string * fileInfo: (int * int) * (PhasedDiagnostic * FSharpDiagnosticSeverity) * suggestNames: bool -> FSharpDiagnostic list + val ReportDiagnostic: FSharpDiagnosticOptions * allErrors: bool * mainInputFileName: string * fileInfo: (int * int) * (PhasedDiagnostic * FSharpDiagnosticSeverity) * suggestNames: bool -> FSharpDiagnostic list val CreateDiagnostics: FSharpDiagnosticOptions * allErrors: bool * mainInputFileName: string * seq<(PhasedDiagnostic * FSharpDiagnosticSeverity)> * suggestNames: bool -> FSharpDiagnostic[] diff --git a/src/fsharp/symbols/Symbols.fs b/src/fsharp/symbols/Symbols.fs index 0839109f2e6..119b368ff25 100644 --- a/src/fsharp/symbols/Symbols.fs +++ b/src/fsharp/symbols/Symbols.fs @@ -1915,11 +1915,11 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) = match d with | P p -> [ [ for (ParamData(isParamArrayArg, isInArg, isOutArg, optArgInfo, _callerInfo, nmOpt, _reflArgInfo, pty)) in p.GetParamDatas(cenv.amap, range0) do - // INCOMPLETENESS: Attribs is empty here, so we can't look at attributes for - // either .NET or F# parameters - let argInfo: ArgReprInfo = { Name=nmOpt; Attribs= [] } - yield FSharpParameter(cenv, pty, argInfo, None, x.DeclarationLocationOpt, isParamArrayArg, isInArg, isOutArg, optArgInfo.IsOptional, false) ] - |> makeReadOnlyCollection ] + // INCOMPLETENESS: Attribs is empty here, so we can't look at attributes for + // either .NET or F# parameters + let argInfo: ArgReprInfo = { Name=nmOpt; Attribs= [] } + yield FSharpParameter(cenv, pty, argInfo, None, x.DeclarationLocationOpt, isParamArrayArg, isInArg, isOutArg, optArgInfo.IsOptional, false) ] + |> makeReadOnlyCollection ] |> makeReadOnlyCollection | E _ -> [] |> makeReadOnlyCollection diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 6817172de42..7b3640e5ae3 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Navržené sestavení poskytovatele typu {0} nešlo načíst ze složky {1}, protože chyběla závislost nebo ji nešlo načíst. Všechny závislosti tohoto sestavení se musí nacházet ve stejné složce jako toto sestavení. Ohlášená výjimka: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 8195503d341..38180212e84 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Die Typanbieter-Designerassembly "{0}" konnte aus dem Ordner "{1}" nicht geladen werden, weil eine Abhängigkeit fehlte oder nicht geladen werden konnte. Alle Abhängigkeiten der Typanbieter-Designerassembly müssen sich in demselben Ordner wie die Assembly befinden. Gemeldete Ausnahme: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 02ed6ec5d5e..4a9f35b23e1 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} No se pudo cargar el ensamblado del diseñador de proveedores de tipos "{0}" desde la carpeta "{1}" porque falta una dependencia o no se pudo cargar. Todas las dependencias del ensamblado del diseñador de proveedores de tipos deben encontrarse en la misma carpeta que el ensamblado. Se notificó la excepción: {2} - {3}. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 737c5acd35b..2d25799e31f 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Impossible de charger l'assembly de concepteur de fournisseur de type '{0}' à partir du dossier '{1}', car une dépendance est manquante ou n'a pas pu être chargée. Toutes les dépendances de l'assembly de concepteur de fournisseur de type doivent se trouver dans le même dossier que cet assembly. Exception signalée : {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 792a8037e5d..85ea980745e 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Non è stato possibile caricare l'assembly '{0}' della finestra di progettazione del provider di tipi dalla cartella '{1}' perché una dipendenza non è presente o non è stato possibile caricarla. Tutte le dipendenze dell'assembly della finestra di progettazione del provider di tipi devono trovarsi nella stessa cartella dell'assembly. L'eccezione restituita è {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 349f0f470b1..fb1c459f4b1 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 依存関係がないか、または読み込めなかったため、型プロバイダーのデザイナー アセンブリ '{0}' をフォルダー '{1}' から読み込めませんでした。型プロバイダーのデザイナー アセンブリのすべての依存関係は、そのアセンブリと同じフォルダーに配置されている必要があります。次の例外が報告されました: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 8e7542ca61b..66f9500b489 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 종속성이 없거나 로드되지 않았으므로 '{0}' 형식 공급자 디자이너 어셈블리를 '{1}' 폴더에서 로드할 수 없습니다. 형식 공급자 디자이너 어셈블리의 모든 종속성은 해당 어셈블리와 동일한 폴더에 있어야 합니다. 보고된 예외: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 568be3b2f92..aaf1411c2f5 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Nie można załadować zestawu projektanta dostawców typów „{0}” z folderu „{1}”, ponieważ brakuje zależności lub nie można jej załadować. Wszystkie zależności zestawu projektanta dostawców typów muszą znajdować się w tym samym folderze co ten zestaw. Zgłoszony wyjątek: {2} — {3} diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index e209b54835c..e5bd66a27d2 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Não foi possível carregar o assembly do designer do provedor de tipos '{0}' da pasta '{1}' porque uma dependência estava ausente ou não pôde ser carregada. Todas as dependências do assembly do designer do provedor de tipos precisam estar localizadas na mesma pasta que esse assembly. A exceção relatada foi: {2} – {3} diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 77d58233fce..4713989a960 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} Не удалось загрузить сборку конструктора поставщика типа "{0}" из папки "{1}", так как зависимость отсутствует или не может быть загружена. Все зависимости для сборки конструктора поставщика типа должны находиться в папке сборки. Получено исключение: {2} — {3} diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index e966c5361e9..0a464637e36 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} '{0}' tür sağlayıcısı tasarımcı bütünleştirilmiş kodu, bir bağımlılık eksik olduğundan veya yüklenemediğinden '{1}' klasöründen yüklenemedi. Tür sağlayıcısı tasarımcısı bütünleştirilmiş kodunun tüm bağımlılıkları, ilgili bütünleştirilmiş kodun bulunduğu klasörde bulunmalıdır. Bildirilen özel durum: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 5828a1c2d12..678adbad580 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 无法从文件夹“{1}”加载类型提供程序设计器程序集“{0}”,因为依赖项缺失或无法加载。类型提供程序设计器程序集的所有依赖项必须与该程序集位于同一文件夹中。报告的异常是: {2} - {3} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 45ad752b4e2..2a40faf9473 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -102,6 +102,11 @@ The analyzer '{0}' raised an exception during analyzer type initialization: '{1}'. + + The compiler tool path '{0}' did not exist. + The compiler tool path '{0}' did not exist. + + The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3} 因為缺少相依性或相依性無法載入,導致無法從資料夾 '{1}' 載入類型提供者設計工具組件 '{0}'。類型提供者設計工具組件的所有相依性都必須位於該組件所在的資料夾內。回報的例外狀況: {2} - {3} diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 5ede8ba2604..d10ebaa1d15 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1355,19 +1355,19 @@ FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean RequiresAssemblyContents FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean get_RequiresAssemblyContents() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext Context FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext get_Context() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckFile(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckFiles(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext) FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: FSharp.Compiler.Diagnostics.FSharpDiagnostic[] OnCheckProject(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]] TryAdditionalToolTip(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Text.Position) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Text.Range,System.String][]] TryCodeFix(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext, FSharp.Compiler.Diagnostics.FSharpDiagnostic[]) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]] TryAdditionalToolTip(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext, FSharp.Compiler.Text.Position) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Text.Range,System.String][]] TryCodeFix(FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext, FSharp.Compiler.Diagnostics.FSharpDiagnostic[]) FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] FixableDiagnosticIds FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] get_FixableDiagnosticIds() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Void .ctor(FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckerModel -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckerModel() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.Threading.CancellationToken CancellationToken -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFileContext: System.Threading.CancellationToken get_CancellationToken() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckerModel +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckerModel() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken CancellationToken +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults CheckerModel FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults get_CheckerModel() diff --git a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index 9c26cd08bff..6bb73161192 100644 --- a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs +++ b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs @@ -12,6 +12,7 @@ open Internal.Utilities open Internal.Utilities.Text.Lexing open FSharp.Compiler +open FSharp.Compiler.Diagnostics open FSharp.Compiler.Lexer open FSharp.Compiler.Lexhelp open FSharp.Compiler.ErrorLogger @@ -55,7 +56,7 @@ type public HashIfExpression() = let errorLogger = { new ErrorLogger("TestErrorLogger") with - member x.DiagnosticSink(e, isError) = if isError then errors.Add e else warnings.Add e + member x.DiagnosticSink(e, sev) = if sev = FSharpDiagnosticSeverity.Error then errors.Add e else warnings.Add e member x.ErrorCount = errors.Count } diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 7a0cd20257d..e41689f3bba 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -509,7 +509,6 @@ let main argv = 0""" |> Async.RunSynchronously Assert.IsEmpty(parseResults.Diagnostics, sprintf "Parse errors: %A" parseResults.Diagnostics) - Assert.IsTrue(parseResults.ParseTree.IsSome, "no parse tree returned") let dependencies = #if NETCOREAPP @@ -519,7 +518,7 @@ let main argv = 0""" #endif let compileErrors, statusCode = - checker.Compile([parseResults.ParseTree.Value], "test", outputFilePath, dependencies, executable = isExe, noframework = true) + checker.Compile([parseResults.ParseTree], "test", outputFilePath, dependencies, executable = isExe, noframework = true) |> Async.RunSynchronously Assert.IsEmpty(compileErrors, sprintf "Compile errors: %A" compileErrors) @@ -534,7 +533,6 @@ let main argv = 0""" |> Async.RunSynchronously Assert.IsEmpty(parseResults.Diagnostics, sprintf "Parse errors: %A" parseResults.Diagnostics) - Assert.IsTrue(parseResults.ParseTree.IsSome, "no parse tree returned") let dependencies = #if NETCOREAPP @@ -544,7 +542,7 @@ let main argv = 0""" #endif let compileErrors, statusCode, assembly = - checker.CompileToDynamicAssembly([parseResults.ParseTree.Value], assemblyName, dependencies, None, noframework = true) + checker.CompileToDynamicAssembly([parseResults.ParseTree], assemblyName, dependencies, None, noframework = true) |> Async.RunSynchronously Assert.IsEmpty(compileErrors, sprintf "Compile errors: %A" compileErrors) diff --git a/tests/service/Common.fs b/tests/service/Common.fs index 45f9f6cf109..d4ad76a2d3d 100644 --- a/tests/service/Common.fs +++ b/tests/service/Common.fs @@ -233,15 +233,14 @@ let matchBraces (name: string, code: string) = braces -let getSingleModuleLikeDecl (input: ParsedInput option) = +let getSingleModuleLikeDecl (input: ParsedInput) = match input with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (modules = [ decl ]))) -> decl + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ decl ])) -> decl | _ -> failwith "Could not get module decls" let parseSourceCodeAndGetModule (source: string) = parseSourceCode ("test", source) |> getSingleModuleLikeDecl - /// Extract range info let tups (m: range) = (m.StartLine, m.StartColumn), (m.EndLine, m.EndColumn) diff --git a/tests/service/InteractiveCheckerTests.fs b/tests/service/InteractiveCheckerTests.fs index 17921965871..ece651b1398 100644 --- a/tests/service/InteractiveCheckerTests.fs +++ b/tests/service/InteractiveCheckerTests.fs @@ -61,9 +61,7 @@ let internal identsAndRanges (input: ParsedInput) = let internal parseAndExtractRanges code = let file = "Test" let result = parseSourceCode (file, code) - match result with - | Some tree -> tree |> identsAndRanges - | None -> failwith "fail to parse..." + result |> identsAndRanges let input = """ diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 89cbcb44d06..8cb4f828699 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -43,9 +43,7 @@ let private (=>) (source: string) (expected: CompletionContext option) = match markerPos with | None -> failwithf "Marker '%s' was not found in the source code" Marker | Some markerPos -> - match parseSourceCode("C:\\test.fs", source) with - | None -> failwith "No parse tree" - | Some parseTree -> + let parseTree = parseSourceCode("C:\\test.fs", source) let actual = ParsedInput.TryGetCompletionContext(markerPos, parseTree, lines.[Line.toZ markerPos.Line]) try Assert.AreEqual(expected, actual) with e -> diff --git a/tests/service/StructureTests.fs b/tests/service/StructureTests.fs index b4ec0e77ac5..4bb2342a1a1 100644 --- a/tests/service/StructureTests.fs +++ b/tests/service/StructureTests.fs @@ -42,10 +42,8 @@ let (=>) (source: string) (expectedRanges: (Range * Range) list) = let ast = parseSourceCode(fileName, source) try - match ast with - | Some tree -> let actual = - Structure.getOutliningRanges lines tree + Structure.getOutliningRanges lines ast |> Seq.filter (fun sr -> sr.Range.StartLine <> sr.Range.EndLine) |> Seq.map (fun sr -> getRange sr.Range, getRange sr.CollapseRange) |> Seq.sort @@ -53,7 +51,6 @@ let (=>) (source: string) (expectedRanges: (Range * Range) list) = let expected = List.sort expectedRanges if actual <> expected then failwithf "Expected %s, but was %s" (formatList expected) (formatList actual) - | None -> failwithf "Expected there to be a parse tree for source:\n%s" source with _ -> printfn "AST:\n%+A" ast reraise() diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 65d48ea3b46..a13e5f32455 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -270,23 +270,21 @@ module SyntaxExpressions = |> getParseResults match ast with - | Some(ParsedInput.ImplFile(ParsedImplFileInput(modules = [ + | ParsedInput.ImplFile(ParsedImplFileInput(modules = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ SynModuleDecl.Let(bindings = [ SynBinding(expr = SynExpr.Sequential(expr1 = SynExpr.Do(_, doRange) ; expr2 = SynExpr.DoBang(_, doBangRange))) ]) ]) - ]))) -> + ])) -> assertRange (2, 4) (3, 14) doRange assertRange (4, 4) (5, 18) doBangRange | _ -> failwith "Could not find SynExpr.Do" module Strings = - let getBindingExpressionValue (parseResults: ParsedInput option) = - parseResults - |> Option.bind (fun tree -> - match tree with + let getBindingExpressionValue (parseResults: ParsedInput) = + match parseResults with | ParsedInput.ImplFile (ParsedImplFileInput (modules = modules)) -> modules |> List.tryPick (fun (SynModuleOrNamespace (decls = decls)) -> decls |> List.tryPick (fun decl -> @@ -297,7 +295,7 @@ module Strings = | SynBinding.SynBinding (_,_,_,_,_,_,_,SynPat.Named _,_,e,_,_) -> Some e | _ -> None) | _ -> None)) - | _ -> None) + | _ -> None let getBindingConstValue parseResults = match getBindingExpressionValue parseResults with @@ -400,7 +398,7 @@ type Teq<'a, 'b> """ match parseResults with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.DeclaredNamespace; range = r) ]))) -> + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.DeclaredNamespace; range = r) ])) -> assertRange (1, 0) (4, 8) r | _ -> failwith "Could not get valid AST" @@ -419,9 +417,9 @@ let x = 42 """ match parseResults with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (modules = [ + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.DeclaredNamespace; range = r1) - SynModuleOrNamespace.SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.DeclaredNamespace; range = r2) ]))) -> + SynModuleOrNamespace.SynModuleOrNamespace(kind = SynModuleOrNamespaceKind.DeclaredNamespace; range = r2) ])) -> assertRange (1, 0) (4, 20) r1 assertRange (6, 0) (8, 10) r2 | _ -> failwith "Could not get valid AST" \ No newline at end of file diff --git a/tests/service/TreeVisitorTests.fs b/tests/service/TreeVisitorTests.fs index c7fbabc003a..206b7daaf8e 100644 --- a/tests/service/TreeVisitorTests.fs +++ b/tests/service/TreeVisitorTests.fs @@ -13,10 +13,7 @@ let ``Visit type test`` () = member x.VisitType(_, _, _) = Some () } let source = "123 :? int" - let parseTree = - match parseSourceCode("C:\\test.fs", source) with - | None -> failwith "No parse tree" - | Some parseTree -> parseTree + let parseTree = parseSourceCode("C:\\test.fs", source) SyntaxTraversal.Traverse(mkPos 1 11, parseTree, visitor) |> Option.defaultWith (fun _ -> failwith "Did not visit type") diff --git a/tests/service/data/Test.Analyzer/Analyzer.fs b/tests/service/data/Test.Analyzer/Analyzer.fs index fa2c628dca0..f707935ded0 100644 --- a/tests/service/data/Test.Analyzer/Analyzer.fs +++ b/tests/service/data/Test.Analyzer/Analyzer.fs @@ -1,5 +1,6 @@ namespace Test.Analyzer +open System.IO open FSharp.Core.CompilerServices open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Diagnostics @@ -12,19 +13,31 @@ do() type MyAnalyzer(ctxt) = inherit FSharpAnalyzer(ctxt) - override this.OnCheckFile(fileCtxt) = + override this.OnCheckFiles(fileCtxt) = - let fileName = fileCtxt.CheckerModel.ParseTree.Value.FileName + let lastFileModel = (Array.last fileCtxt.CheckerModel) + let fileName = lastFileModel.ParseTree.FileName let m = Range.mkRange fileName (Position.mkPos 3 0) (Position.mkPos 3 80) let m2 = Range.mkRange fileName (Position.mkPos 6 0) (Position.mkPos 6 80) - let source = fileCtxt.GetFileSource(fileName) - let text = source.GetSubTextString(0,source.Length) + let text = + match lastFileModel.SourceText with + | None -> File.ReadAllText(fileName) + | Some source -> source.GetSubTextString(0,source.Length) [| if text.Contains("WIBBLE") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 6 until the magic word WIBBLE appears", 45, m2, "FA") if text.Contains("WAZZAM") |> not then FSharpDiagnostic.Create(FSharpDiagnosticSeverity.Warning, "this diagnostic is always on line 3 until the magic word WAZZAM appears", 45, m, "FA") |] override _.TryAdditionalToolTip(fileCtxt, pos) = - let fileName = fileCtxt.CheckerModel.ParseTree.Value.FileName - Some [| TaggedText.tagText $"This thing is on line {pos.Line} in file {fileName}" |] + let lastFileModel = (Array.last fileCtxt.CheckerModel) + let fileName = lastFileModel.ParseTree.FileName + Some [| TaggedText.tagText $"Yup that's a thing on line {pos.Line} in file {fileName}"; + TaggedText.lineBreak + TaggedText.tagClass $"SYSTEM.CONSOLE!" + TaggedText.lineBreak + NavigableTaggedText(TaggedText.tagText $"Try the first line in the file", Range.mkFirstLineOfFile fileName) + TaggedText.lineBreak + WebLinkTaggedText(TaggedText.tagText $"This thing is on line {pos.Line} in file {fileName}", + System.Uri("https://www.google.com")) + |] diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj index 6c0302d850a..5e771fb6ee6 100644 --- a/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/TestProject.fsproj @@ -4,6 +4,7 @@ Library false + fsc.exe ..\..\..\artifacts\bin\fsc\Debug\net472 true diff --git a/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs b/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs index c72bf83810a..60040024036 100644 --- a/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs +++ b/tests/walkthroughs/UsingTestAnalyzerInProject/test.fs @@ -1,10 +1,14 @@ - module M +open System + +//module M + +type C() = member x.P = 1 let x1 = 1 let x2 = 1 let x3 = 1 -let x4 = 1 +let x4 = C() -// wibble -// wazzam \ No newline at end of file +// +// WAZZAM \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs index 1cc40bfa47b..7566b4bbc3a 100644 --- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedOpens.fs @@ -30,7 +30,7 @@ type internal FSharpRemoveUnusedOpensCodeFixProvider let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName) - let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) + let! _, _, unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) let changes = unusedOpens |> List.map (fun m -> diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs index cca16374d7d..fcf9eeaec39 100644 --- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs +++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs @@ -69,7 +69,7 @@ type internal XmlDocCommandFilter let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName) let! sourceText = document.GetTextAsync(CancellationToken.None) let! parsedInput = checker.ParseDocument(document, parsingOptions, sourceText, userOpName) - let xmlDocables = XmlDocParser.GetXmlDocables (sourceText.ToFSharpSourceText(), Some parsedInput) + let xmlDocables = XmlDocParser.GetXmlDocables (sourceText.ToFSharpSourceText(), parsedInput) let xmlDocablesBelowThisLine = // +1 because looking below current line for e.g. a 'member' xmlDocables |> List.filter (fun (XmlDocable(line,_indent,_paramNames)) -> line = curLineNum+1) diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index f0b8f3d75e3..7eca0659392 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -145,7 +145,12 @@ module internal RoslynHelpers = let id = error.ErrorNumberText let emptyString = LocalizableString.op_Implicit("") let description = LocalizableString.op_Implicit(normalizedMessage) - let severity = if error.Severity = FSharpDiagnosticSeverity.Error then DiagnosticSeverity.Error else DiagnosticSeverity.Warning + let severity = + match error.Severity with + | FSharpDiagnosticSeverity.Error -> DiagnosticSeverity.Error + | FSharpDiagnosticSeverity.Warning -> DiagnosticSeverity.Warning + | FSharpDiagnosticSeverity.Info -> DiagnosticSeverity.Info + | FSharpDiagnosticSeverity.Hidden -> DiagnosticSeverity.Hidden let customTags = match error.ErrorNumber with | 1182 -> FSharpDiagnosticCustomTags.Unnecessary diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs index b1f9dc735f5..bb86ad92c63 100644 --- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs +++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs @@ -195,11 +195,7 @@ type internal FSharpCompletionProvider if results.Count > 0 && not declarations.IsForType && not declarations.IsError && List.isEmpty partialName.QualifyingIdents then - let completionContext = - parseResults.ParseTree - |> Option.bind (fun parseTree -> - ParsedInput.TryGetCompletionContext(Position.fromZ caretLinePos.Line caretLinePos.Character, parseTree, line)) - + let completionContext = ParsedInput.TryGetCompletionContext(Position.fromZ caretLinePos.Line caretLinePos.Character, parseResults.ParseTree, line) match completionContext with | None -> results.AddRange(keywordCompletionItems) | _ -> () diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs index 75d5517d4da..ec98f144473 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs @@ -15,6 +15,9 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Diagnostics +open Microsoft.CodeAnalysis.Diagnostics +open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.CodeAnalysis.Host [] type internal DiagnosticsType = @@ -56,11 +59,37 @@ type internal FSharpDocumentDiagnosticAnalyzer hash } + static member CleanDiagnostics(filePath: string, diagnostics: FSharpDiagnostic[], sourceText: SourceText) = + HashSet(diagnostics, errorInfoEqualityComparer) + |> Seq.choose(fun error -> + if error.StartLine = 0 || error.EndLine = 0 then + // F# error line numbers are one-based. Compiler returns 0 for global errors (reported by ProjectDiagnosticAnalyzer) + None + else + // Roslyn line numbers are zero-based + let linePositionSpan = LinePositionSpan(LinePosition(error.StartLine - 1, error.StartColumn), LinePosition(error.EndLine - 1, error.EndColumn)) + let textSpan = sourceText.Lines.GetTextSpan(linePositionSpan) + + // F# compiler report errors at end of file if parsing fails. It should be corrected to match Roslyn boundaries + let correctedTextSpan = + if textSpan.End <= sourceText.Length then + textSpan + else + let start = + min textSpan.Start (sourceText.Length - 1) + |> max 0 + + TextSpan.FromBounds(start, sourceText.Length) + + let location = Location.Create(filePath, correctedTextSpan , linePositionSpan) + Some(RoslynHelpers.ConvertError(error, location))) + |> Seq.toImmutableArray + static member GetDiagnostics(checker: FSharpChecker, filePath: string, sourceText: SourceText, textVersionHash: int, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) = async { let fsSourceText = sourceText.ToFSharpSourceText() let! parseResults = checker.ParseFile(filePath, fsSourceText, parsingOptions, userOpName=userOpName) - let! errors = + let! diagnostics = async { match diagnosticType with | DiagnosticsType.Semantic -> @@ -71,37 +100,12 @@ type internal FSharpDocumentDiagnosticAnalyzer // In order to eleminate duplicates, we should not return parse errors here because they are returned by `AnalyzeSyntaxAsync` method. let allErrors = HashSet(results.Diagnostics, errorInfoEqualityComparer) allErrors.ExceptWith(parseResults.Diagnostics) - let! analysisErrors = checker.AnalyzeFileInProject(parseResults, results, fsSourceText, options, userOpName=userOpName) - return Array.append (Seq.toArray allErrors) analysisErrors + return Seq.toArray allErrors | DiagnosticsType.Syntax -> return parseResults.Diagnostics } - let results = - HashSet(errors, errorInfoEqualityComparer) - |> Seq.choose(fun error -> - if error.StartLine = 0 || error.EndLine = 0 then - // F# error line numbers are one-based. Compiler returns 0 for global errors (reported by ProjectDiagnosticAnalyzer) - None - else - // Roslyn line numbers are zero-based - let linePositionSpan = LinePositionSpan(LinePosition(error.StartLine - 1, error.StartColumn), LinePosition(error.EndLine - 1, error.EndColumn)) - let textSpan = sourceText.Lines.GetTextSpan(linePositionSpan) - - // F# compiler report errors at end of file if parsing fails. It should be corrected to match Roslyn boundaries - let correctedTextSpan = - if textSpan.End <= sourceText.Length then - textSpan - else - let start = - min textSpan.Start (sourceText.Length - 1) - |> max 0 - - TextSpan.FromBounds(start, sourceText.Length) - - let location = Location.Create(filePath, correctedTextSpan , linePositionSpan) - Some(RoslynHelpers.ConvertError(error, location))) - |> Seq.toImmutableArray + let results = FSharpDocumentDiagnosticAnalyzer.CleanDiagnostics(filePath, diagnostics, sourceText) return results } @@ -124,6 +128,7 @@ type internal FSharpDocumentDiagnosticAnalyzer let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync(cancellationToken) let! textVersion = document.GetTextVersionAsync(cancellationToken) + // Only analyze in-project files and scripts if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then return! FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document.FilePath, sourceText, textVersion.GetHashCode(), parsingOptions, projectOptions, DiagnosticsType.Semantic) @@ -134,4 +139,3 @@ type internal FSharpDocumentDiagnosticAnalyzer |> Async.map (Option.defaultValue ImmutableArray.Empty) |> RoslynHelpers.StartAsyncAsTask cancellationToken - diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index a00523409b2..3eaef335eab 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -26,13 +26,13 @@ type internal UnusedOpensDiagnosticAnalyzer static let userOpName = "UnusedOpensAnalyzer" - static member GetUnusedOpenRanges(document: Document, options, checker: FSharpChecker) : Async> = + static member GetUnusedOpenRanges(document: Document, options, checker: FSharpChecker) : Async> = asyncMaybe { do! Option.guard document.FSharpOptions.CodeFixes.UnusedOpens let! sourceText = document.GetTextAsync() - let! _, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, userOpName = userOpName) + let! parseResults, _, checkResults = checker.ParseAndCheckDocument(document, options, sourceText = sourceText, userOpName = userOpName) let! unusedOpens = UnusedOpens.getUnusedOpens(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync - return unusedOpens + return parseResults, checkResults, unusedOpens } interface IFSharpUnusedOpensDiagnosticAnalyzer with @@ -44,8 +44,11 @@ type internal UnusedOpensDiagnosticAnalyzer let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) let! sourceText = document.GetTextAsync() let checker = checkerProvider.Checker - let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) + let! parseResults, checkResults, unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document, projectOptions, checker) + // We run analyzers as part of unused opens to give lower priority + let! analyzerDiagnostics = checker.AnalyzeFileInProject(parseResults, checkResults, projectOptions, userOpName=userOpName) |> liftAsync + let analyzerDiagnostics = FSharpDocumentDiagnosticAnalyzer.CleanDiagnostics(document.FilePath, analyzerDiagnostics, sourceText) return unusedOpens |> List.map (fun range -> @@ -53,6 +56,7 @@ type internal UnusedOpensDiagnosticAnalyzer descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath))) |> Seq.toImmutableArray + |> fun a -> a.AddRange(analyzerDiagnostics) } |> Async.map (Option.defaultValue ImmutableArray.Empty) |> RoslynHelpers.StartAsyncAsTask cancellationToken diff --git a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs index e1f54c0d7fd..7ff1882621c 100644 --- a/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs +++ b/vsintegration/src/FSharp.Editor/DocComments/XMLDocumentation.fs @@ -64,9 +64,15 @@ type internal TextSanitizingCollector(collector, ?lineLimit: int) = addTaggedTextEntry TaggedText.lineBreak addTaggedTextEntry TaggedText.lineBreak) + // TODO: bail out early if line limit is already hit interface ITaggedTextCollector with member this.Add taggedText = - // TODO: bail out early if line limit is already hit + // Don't apply this cleanup code to navigation elements + match taggedText with + | :? NavigableTaggedText + | :? WebLinkTaggedText -> addTaggedTextEntry taggedText + | _ -> + // Don't apply this cleanup code to non-text elements match taggedText.Tag with | TextTag.Text -> reportTextLines taggedText.Text | _ -> addTaggedTextEntry taggedText diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs index b62c9a8e536..e70577b9363 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpCheckerExtensions.fs @@ -12,7 +12,7 @@ type FSharpChecker with member checker.ParseDocument(document: Document, parsingOptions: FSharpParsingOptions, sourceText: SourceText, userOpName: string) = asyncMaybe { let! fileParseResults = checker.ParseFile(document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName=userOpName) |> liftAsync - return! fileParseResults.ParseTree + return fileParseResults.ParseTree } member checker.ParseAndCheckDocument(filePath: string, textVersionHash: int, sourceText: SourceText, options: FSharpProjectOptions, languageServicePerformanceOptions: LanguageServicePerformanceOptions, userOpName: string) = @@ -40,9 +40,7 @@ type FSharpChecker with let bindParsedInput(results: (FSharpParseFileResults * FSharpCheckFileResults) option) = match results with | Some(parseResults, checkResults) -> - match parseResults.ParseTree with - | Some parsedInput -> Some (parseResults, parsedInput, checkResults) - | None -> None + Some (parseResults, parseResults.ParseTree, checkResults) | None -> None if languageServicePerformanceOptions.AllowStaleCompletionResults then diff --git a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs index 346062c925c..9c8ad673d83 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/NavigateToSearchService.fs @@ -184,9 +184,8 @@ type internal FSharpNavigateToSearchService NavigateTo.GetNavigableItems parsedInput |> Array.filter (fun i -> kinds.Contains(navigateToItemKindToRoslynKind i.Kind)) + let items = parseResults.ParseTree |> navItems return - match parseResults.ParseTree |> Option.map navItems with - | Some items -> [| for item in items do match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, item.Range) with | None -> () @@ -195,7 +194,6 @@ type internal FSharpNavigateToSearchService let kind = navigateToItemKindToRoslynKind item.Kind let additionalInfo = containerToString item.Container document.Project yield NavigableItem(document, sourceSpan, glyph, item.Name, kind, additionalInfo) |] - | None -> [||] } let getCachedIndexedNavigableItems(document: Document, parsingOptions: FSharpParsingOptions, kinds: IImmutableSet) = diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs index a1455cb922a..daa8c2e5fac 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/Navigation.fs @@ -70,8 +70,7 @@ type internal QuickInfoNavigation member _.NavigateToUri (uri: System.Uri) = asyncMaybe { - let componentModel = ServiceProvider.GlobalProvider.GetService() - let navigationService = componentModel.GetService() + let navigationService = ServiceProvider.GlobalProvider.GetService() if navigationService <> null then let _hr, _ppFrame = navigationService.Navigate(uri.ToString(), 0u) diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 60c989907aa..3f1da13af5c 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -69,7 +69,7 @@ module internal FSharpQuickInfo = (declRange.StartLine, extLexerSymbol.Ident.idRange.EndColumn, extLineText, extLexerSymbol.FullIsland, FSharpTokenTag.IDENT) let fcsPos = Position.mkPos declRange.StartLine (extLexerSymbol.Ident.idRange.EndColumn-1) - let! extAnalyzerExtras = checker.GetAdditionalAnalyzerToolTips(extParseResults, extCheckFileResults, extSourceText.ToFSharpSourceText(), options=extProjectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync + let! extAnalyzerExtras = checker.GetAdditionalAnalyzerToolTips(extParseResults, extCheckFileResults, options=extProjectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync let extAnalyzerExtras = extAnalyzerExtras |> Array.filter (fun arr -> arr.Length <> 0) match extQuickInfoText, extAnalyzerExtras with | ToolTipText [], [| |] @@ -116,7 +116,7 @@ module internal FSharpQuickInfo = (fcsTextLineNumber, idRange.EndColumn, lineText, lexerSymbol.FullIsland,tag) let fcsPos = Position.mkPos fcsTextLineNumber textLinePos.Character - let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, sourceText.ToFSharpSourceText(), options=projectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync + let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, options=projectOptions, pos=fcsPos, userOpName=userOpName) |> liftAsync let extras = extras |> Array.filter (fun arr -> arr.Length <> 0) match targetQuickInfo, extras with | ToolTipText [], [| |] @@ -198,7 +198,7 @@ type internal FSharpAsyncQuickInfoSource let! symbol = Tokenizer.getSymbolAtPosition (documentId, sourceText, position, filePath, defines, SymbolLookupKind.Precise, true, true) let res = checkFileResults.GetToolTip (textLineNumber, symbol.Ident.idRange.EndColumn, textLineString, symbol.FullIsland, FSharpTokenTag.IDENT) let fcsPos = Position.mkPos textLineNumber textPos.Character - let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, sourceText.ToFSharpSourceText(), options=options, pos=fcsPos, userOpName=FSharpQuickInfo.userOpName) |> liftAsync + let! extras = checker.GetAdditionalAnalyzerToolTips(parseResults, checkFileResults, options=options, pos=fcsPos, userOpName=FSharpQuickInfo.userOpName) |> liftAsync let extras = extras |> Array.filter (fun arr -> arr.Length <> 0) match res, extras with | ToolTipText [], [| |] From af2679c3ef10c1e3245275cfce77b0167e1ac6e4 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 25 Feb 2021 13:43:16 +0000 Subject: [PATCH 19/31] test script for analyzer --- tests/walkthroughs/using-test-analyzer-in-script.fsx | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/walkthroughs/using-test-analyzer-in-script.fsx diff --git a/tests/walkthroughs/using-test-analyzer-in-script.fsx b/tests/walkthroughs/using-test-analyzer-in-script.fsx new file mode 100644 index 00000000000..4488a6509af --- /dev/null +++ b/tests/walkthroughs/using-test-analyzer-in-script.fsx @@ -0,0 +1,4 @@ + +#compilertool @"..\..\artifacts\bin\Test.Analyzer\Debug\netstandard2.0" + +let x = 1 \ No newline at end of file From c2e9b9ffbb02aa301e8a8ad392fabee085be4def Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 1 Mar 2021 15:08:59 +0000 Subject: [PATCH 20/31] merge main --- VisualFSharp.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/VisualFSharp.sln b/VisualFSharp.sln index c47b6f669eb..7b02b983eb1 100644 --- a/VisualFSharp.sln +++ b/VisualFSharp.sln @@ -159,6 +159,7 @@ EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}" EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Test.Analyzer", "tests\service\data\Test.Analyzer\Test.Analyzer.fsproj", "{A341304E-7223-4931-88B5-690EE88C2241}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualFSharpDebug", "vsintegration\Vsix\VisualFSharpFull\VisualFSharpDebug.csproj", "{A422D673-8E3B-4924-821B-DD3174173426}" EndProject Global From 8e49b2e26f9483f79f45d35688c409d782464b30 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 1 Mar 2021 15:13:50 +0000 Subject: [PATCH 21/31] merge main --- src/fsharp/service/FSharpParseFileResults.fsi | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/fsharp/service/FSharpParseFileResults.fsi b/src/fsharp/service/FSharpParseFileResults.fsi index d7856a91515..c8e9f2d0f85 100644 --- a/src/fsharp/service/FSharpParseFileResults.fsi +++ b/src/fsharp/service/FSharpParseFileResults.fsi @@ -13,12 +13,9 @@ type public FSharpParseFileResults = /// The syntax tree resulting from the parse member ParseTree: ParsedInput -<<<<<<< HEAD /// The source text from which the parse originated, if it wasn't read from disk member SourceText: ISourceText option -======= ->>>>>>> 89ad3715a2a3502090218916b698dcf0fcbd59c9 /// Attempts to find the range of the name of the nearest outer binding that contains a given position. member TryRangeOfNameOfNearestOuterBindingContainingPos: pos: pos -> range option @@ -76,9 +73,5 @@ type public FSharpParseFileResults = /// Indicates if any errors occurred during the parse member ParseHadErrors: bool -<<<<<<< HEAD internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput * sourceText: ISourceText option * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults -======= - internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults ->>>>>>> 89ad3715a2a3502090218916b698dcf0fcbd59c9 From 0c2751cce8b6d6419aa749cdb08728bd62a02911 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 1 Mar 2021 15:23:33 +0000 Subject: [PATCH 22/31] merge main --- src/fsharp/service/FSharpCheckerResults.fs | 2 +- src/fsharp/service/FSharpCheckerResults.fsi | 2 +- src/fsharp/service/service.fs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 27070e1963a..15befe75459 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -2103,7 +2103,7 @@ type FSharpCheckFileResults userOpName: string, isIncompleteTypeCheckEnvironment: bool, projectOptions: FSharpProjectOptions, - builder: IncrementalBuilder, + builder: obj, dependencyFiles: string[], creationErrors: FSharpDiagnostic[], parseErrors: FSharpDiagnostic[], diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index 04c8c5d7be4..385f73625d9 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -367,7 +367,7 @@ type public FSharpCheckFileResults = userOpName: string * isIncompleteTypeCheckEnvironment: bool * projectOptions: FSharpProjectOptions * - builder: IncrementalBuilder * + builder: obj * dependencyFiles: string[] * creationErrors:FSharpDiagnostic[] * parseErrors:FSharpDiagnostic[] * diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index a945e35a9c0..643b4c83e41 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -440,7 +440,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC match builderOpt with | None -> let parseTree = EmptyParsedInput(filename, (false, false)) - return FSharpParseFileResults(creationDiags, parseTree, true, [| |]) + return FSharpParseFileResults(creationDiags, parseTree, None, true, [| |]) | Some builder -> let parseTree,_,_,parseDiags = builder.GetParseResultsForFile (filename) let diagnostics = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (builder.TcConfig.errorSeverityOptions, false, filename, parseDiags, suggestNamesForErrors) |] @@ -503,7 +503,6 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC try // Get additional script #load closure information if applicable. // For scripts, this will have been recorded by GetProjectOptionsFromScript. - let tcConfig = tcPrior.TcConfig let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options) let tcConfig = tcPrior.TcConfig let tcPriorImplFiles = (tcInfoOptionalExtras |> Option.map (fun i -> i.TcImplFiles) |> Option.defaultValue []) From d63f87e6873c5dc8ce85b89f9dff71aaa1972f61 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 3 Mar 2021 17:06:59 +0000 Subject: [PATCH 23/31] fix regression 11176 --- src/fsharp/service/IncrementalBuild.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 3bb1c330818..45b7bd7b783 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -123,7 +123,7 @@ module IncrementalBuildSyntaxTree = [], isLastCompiland ) - ) |> Some + ) else ParseOneInputFile(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, (*retryLocked*)true) From b364d95430cc48df30bc507d50407c9cd96d1ca8 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 4 Mar 2021 13:17:43 +0000 Subject: [PATCH 24/31] fix build --- src/fsharp/service/IncrementalBuild.fs | 8 +++----- src/fsharp/service/IncrementalBuild.fsi | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 279effc3db1..f54b75e8871 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -482,7 +482,7 @@ type BoundModel private (tcConfig: TcConfig, else match! prevTcInfoExtras() with | None -> return PartialState tcInfo - | Some prevTcInfoOptional -> + | Some prevTcInfoExtras -> // Build symbol keys let itemKeyStore, semanticClassification = if enableBackgroundItemKeyStoreAndSemanticClassification then @@ -609,16 +609,14 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime) = member _.TimeStamp = timeStamp - member _.GetTcInfoWithOptionalExtras ctok = boundModel.TcInfoWithOptionalExtras |> eval ctok + member _.GetTcInfoWithOptionalExtras() = boundModel.TcInfoWithOptionalExtras - member _.GetTcInfoWithExtras ctok = boundModel.TcInfoWithExtras |> eval ctok + member _.GetTcInfoWithExtras() = boundModel.GetTcInfoWithExtras() member _.GetTcInfo() = boundModel.GetTcInfo() member _.TryTcInfoWithOptionalExtras = boundModel.TryTcInfoWithOptionalExtras - member _.GetTcInfoWithExtras() = boundModel.GetTcInfoWithExtras() - member _.TryGetItemKeyStore() = eventually { let! _, info = boundModel.GetTcInfoWithExtras() diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 34aae531c02..41fe792b8df 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -113,7 +113,7 @@ type internal PartialCheckResults = /// Compute the "TcInfo" part of the results. If `enablePartialTypeChecking` is false then /// extras will also be available. - member GetTcInfoWithOptionalExtras: CompilationThreadToken -> Eventually + member GetTcInfoWithOptionalExtras: unit -> Eventually /// Compute the "TcInfo" part of the results. If `enablePartialTypeChecking` is false then /// extras will also be available. From 1c90eadb2334c6108ab2a382e29e7a78c894a1d9 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 4 Mar 2021 18:23:52 +0000 Subject: [PATCH 25/31] fix build --- src/fsharp/service/FSharpCheckerResults.fs | 4 ++-- src/fsharp/service/service.fs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 4da79bd0e17..b3d62893861 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -1787,14 +1787,14 @@ module internal ParseAndCheckFile = with e -> errorR e let mty = Construct.NewEmptyModuleOrNamespaceType ModuleOrNamespaceKind.Namespace - return ((tcState.TcEnvFromSignatures, EmptyTopAttrs, [], [(parsedMainInput, None, mty) ]), tcState) + return ((tcState.TcEnvFromSignatures, EmptyTopAttrs, [(parsedMainInput, None, mty) ]), tcState) } let errors = errHandler.CollectedDiagnostics let res = match resOpt with - | Some ((tcEnvAtEnd, _, implFiles, ccuSigsForFiles), tcState) -> + | ((tcEnvAtEnd, _, implFiles), tcState) -> TypeCheckInfo(tcConfig, tcGlobals, (List.head implFiles |> p33), tcState.Ccu, diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 6137db1dbd1..6275d8f0f3e 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -573,7 +573,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC |> Option.map (fun tcPrior -> (tcPrior, tcPrior.TryTcInfoWithOptionalExtras)) match tcPrior with - | Some(tcPrior, (tcInfo, tcInfoOptionalExtras)) -> + | Some(tcPrior, Some (tcInfo, tcInfoOptionalExtras)) -> let! checkResults = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, tcInfoOptionalExtras, creationDiags) return Some checkResults | _ -> return None // the incremental builder was not up to date @@ -609,7 +609,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC execWithReactorAsync <| fun ctok -> cancellable { let! tcPrior = builder.GetCheckResultsBeforeFileInProject (ctok, filename) - let! tcInfo = tcPrior.GetTcInfo() |> Eventually.toCancellable + let! tcInfo = tcPrior.GetTcInfoWithOptionalExtras() |> Eventually.toCancellable return (tcPrior, tcInfo) } let! checkAnswer = bc.CheckOneFileImpl(parseResults, sourceText, filename, options, fileVersion, builder, tcPrior, tcInfo, tcInfoOptionalExtras, creationDiags) @@ -659,7 +659,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC execWithReactorAsync <| fun ctok -> cancellable { let! tcPrior = builder.GetCheckResultsBeforeFileInProject (ctok, filename) - let! tcInfo = tcPrior.GetTcInfoWithOptionalExtras(ctok) |> Eventually.toCancellable + let! tcInfo = tcPrior.GetTcInfoWithOptionalExtras() |> Eventually.toCancellable return (tcPrior, tcInfo) } From 2b3592cf4127558dfb2c04770f1013981cbcf771 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 26 Mar 2021 19:34:21 +0000 Subject: [PATCH 26/31] Don't deploy Full extension after build --- vsintegration/Vsix/VisualFSharpFull/VisualFSharpFull.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vsintegration/Vsix/VisualFSharpFull/VisualFSharpFull.csproj b/vsintegration/Vsix/VisualFSharpFull/VisualFSharpFull.csproj index c77244fede9..10c18b8530e 100644 --- a/vsintegration/Vsix/VisualFSharpFull/VisualFSharpFull.csproj +++ b/vsintegration/Vsix/VisualFSharpFull/VisualFSharpFull.csproj @@ -8,6 +8,8 @@ netcoreapp1.0 true net472 + + false From d924143d32e2009ecafb505b641bd64c664b3bcb Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 24 May 2021 23:00:22 +0100 Subject: [PATCH 27/31] update baselines --- .../SurfaceArea.netstandard.fs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index ed8145d1543..1f560fdd230 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1902,6 +1902,8 @@ FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryRe FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+ReduceMemoryFlag FSharp.Compiler.AbstractIL.ILBinaryReader: FSharp.Compiler.AbstractIL.ILBinaryReader+Shim FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext +FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext: Boolean EditorServicesRequested +FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext: Boolean get_EditorServicesRequested() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean RequiresAssemblyContents FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Boolean get_RequiresAssemblyContents() @@ -1915,15 +1917,14 @@ FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] FixableDiagnosticId FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: System.String[] get_FixableDiagnosticIds() FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Void .ctor(FSharp.Compiler.CodeAnalysis.FSharpAnalysisContext) FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults CheckerModel -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_CheckerModel() +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults[] CheckerModel +FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults[] get_CheckerModel() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken CancellationToken FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults CheckerModel FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults get_CheckerModel() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: System.Threading.CancellationToken CancellationToken FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer @@ -1974,8 +1975,10 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FShar FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpDisplayContext] GetDisplayContextForPos(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpImplementationFileContents] ImplementationFile FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpImplementationFileContents] get_ImplementationFile() -FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.ParsedInput] ParseTree -FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.ParsedInput] get_ParseTree() +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Syntax.ParsedInput ParseTree +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: FSharp.Compiler.Syntax.ParsedInput get_ParseTree() +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] SourceText +FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] get_SourceText() FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] GenerateSignature() FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpSymbolUse]] GetMethodsAsSymbols(Int32, Int32, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.String] GetF1Keyword(Int32, Int32, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String]) @@ -2024,8 +2027,8 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] GetBackgroundParseResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String]) -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] AnalyzeFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Text.TaggedText[][]] GetAdditionalAnalyzerToolTips(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Text.Position, Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic[]] AnalyzeFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.Text.TaggedText[][]] GetAdditionalAnalyzerToolTips(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Text.Position, Microsoft.FSharp.Core.FSharpOption`1[System.String]) 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]) @@ -2065,6 +2068,8 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_ImplicitlyStartBackgroundWo FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_MaxMemory(Int32) FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_PauseBeforeBackgroundWork(Int32) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults +FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] SourceText +FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] get_SourceText() FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position) FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPositionContainedInACurriedParameter(FSharp.Compiler.Text.Position) From 3ecf924249ca5efeda8484587c43be4c87e905a4 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 26 May 2021 20:44:56 +0100 Subject: [PATCH 28/31] fix baselines --- src/fsharp/utils/FileSystem.fs | 2 +- tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fsharp/utils/FileSystem.fs b/src/fsharp/utils/FileSystem.fs index 275d99d2c6f..7f4fe2a9587 100644 --- a/src/fsharp/utils/FileSystem.fs +++ b/src/fsharp/utils/FileSystem.fs @@ -780,7 +780,7 @@ type ByteStorage(getByteMemory: unit -> ReadOnlyByteMemory) = static member FromByteArrayAndCopy(bytes: byte [], useBackingMemoryMappedFile: bool) = ByteStorage.FromByteMemoryAndCopy(ByteMemory.FromArray(bytes).AsReadOnly(), useBackingMemoryMappedFile) -module SourceText = +module internal SourceText = let readFile fileName inputCodePage = let fileName = FileSystem.GetFullPathShim fileName use stream = FileSystem.OpenFileForReadShim(fileName).AsReadOnlyStream() diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 1f560fdd230..3df749f64ea 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -1919,7 +1919,6 @@ FSharp.Compiler.CodeAnalysis.FSharpAnalyzer: Void .ctor(FSharp.Compiler.CodeAnal FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults[] CheckerModel FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults[] get_CheckerModel() -FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: FSharp.Compiler.Text.ISourceText GetFileSource(System.String) FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken CancellationToken FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckFilesContext: System.Threading.CancellationToken get_CancellationToken() FSharp.Compiler.CodeAnalysis.FSharpAnalyzerCheckProjectContext From 0abfaee52cdefddbab305c66d11d7a9c04ac65ae Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 27 May 2021 13:12:24 +0100 Subject: [PATCH 29/31] update baselines --- tests/fsharpqa/Source/CompilerOptions/fsc/times/times01.fs | 1 - .../Source/CompilerOptions/fsi/exename/help40.437.1033.bsl | 1 + .../Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl | 1 + .../fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl | 1 + 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/times/times01.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/times/times01.fs index 63a3663ff4d..df8262c1d93 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/times/times01.fs +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/times/times01.fs @@ -18,7 +18,6 @@ namespace N2 //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Parse inputs\] //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Import non-system references\] //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Typecheck\] -//TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Typechecked\] //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Write XML docs\] //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[Encode Interface Data\] //TIME:.+Delta:.+Mem:.+G0:.+G1:.+G2:.+\[TAST -> IL\] diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl index b4c1b490400..8bbceacc4e6 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/exename/help40.437.1033.bsl @@ -97,6 +97,7 @@ Usage: fsharpi [script.fsx []] command line --gui[+|-] Execute interactions on a Windows Forms event loop (on by default) +--runanalyzers[+|-] Execute analyzers (off by default) --quiet Suppress fsi writing to stdout --readline[+|-] Support TAB completion in console (on by default) diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl index d95678648c7..8c566ea2ce0 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40-nologo.437.1033.bsl @@ -97,6 +97,7 @@ Usage: fsiAnyCpu [script.fsx []] command line --gui[+|-] Execute interactions on a Windows Forms event loop (on by default) +--runanalyzers[+|-] Execute analyzers (off by default) --quiet Suppress fsi writing to stdout --readline[+|-] Support TAB completion in console (on by default) diff --git a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl index cbedecea482..0abfaf49d82 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsi/help/help40.437.1033.bsl @@ -99,6 +99,7 @@ Usage: fsiAnyCpu [script.fsx []] command line --gui[+|-] Execute interactions on a Windows Forms event loop (on by default) +--runanalyzers[+|-] Execute analyzers (off by default) --quiet Suppress fsi writing to stdout --readline[+|-] Support TAB completion in console (on by default) From 7693168eb53b590df90dc4878ca311ba473e5d7b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 24 Jun 2021 20:58:59 +0100 Subject: [PATCH 30/31] simplify code --- src/fsharp/service/IncrementalBuild.fs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index e8f4698e435..cb58d3bedf7 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -418,14 +418,14 @@ type BoundModel private (tcConfig: TcConfig, member _.TryPeekTcInfo() = match tcInfoNode with | TcInfoNode(partialGraphNode, fullGraphNode) -> - match fullGraphNode.TryPeekValue() with - | ValueSome (tcInfo, _) -> Some tcInfo - | _ -> match partialGraphNode.TryPeekValue() with | ValueSome tcInfo -> Some tcInfo - | _ -> None + | _ -> + match fullGraphNode.TryPeekValue() with + | ValueSome (tcInfo, _) -> Some tcInfo + | _ -> None - member _.TryPeekTcInfoWithExtras() = + member _.TryPeekTcInfoExtras() = match tcInfoNode with | TcInfoNode(_, fullGraphNode) -> match fullGraphNode.TryPeekValue() with @@ -673,7 +673,7 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime) = member _.TryPeekTcInfo() = boundModel.TryPeekTcInfo() - member _.TryPeekTcInfoWithExtras() = boundModel.TryPeekTcInfoWithExtras() + member _.TryPeekTcInfoExtras() = boundModel.TryPeekTcInfoExtras() member _.GetOrComputeTcInfo() = boundModel.GetOrComputeTcInfo() From 355dbd708ffa2f0428c488b130f0658f33e554ab Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 24 Jun 2021 21:46:05 +0100 Subject: [PATCH 31/31] fix build --- src/fsharp/service/FSharpCheckerResults.fs | 24 +++++++++++----------- src/fsharp/service/IncrementalBuild.fs | 2 +- src/fsharp/service/IncrementalBuild.fsi | 2 +- src/fsharp/service/service.fs | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index 822c321fd05..386e34be11b 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -2230,12 +2230,12 @@ type FSharpCheckProjectResults member _.HasCriticalErrors = details.IsNone member _.AssemblySignature = - let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _symbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() FSharpAssemblySignature(tcGlobals, thisCcu, ccuSig, tcImports, topAttribs, ccuSig) member _.TypedImplementationFiles = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, _ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, tcImports, thisCcu, _ccuSig, _symbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2244,7 +2244,7 @@ type FSharpCheckProjectResults member info.AssemblyContents = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _symbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2253,7 +2253,7 @@ type FSharpCheckProjectResults member _.GetOptimizedAssemblyContents() = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, _symbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2272,12 +2272,12 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetUsesOfSymbol(symbol:FSharpSymbol, ?cancellationToken: CancellationToken) = - let (tcGlobals, _tcImports, _thisCcu, _ccuSig, builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, _tcImports, _thisCcu, _ccuSig, symbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let results = - match builderOrSymbolUses with - | Choice1Of2 builder -> - builder() + match symbolUses with + | Choice1Of2 getSymbolUses -> + getSymbolUses() |> Array.collect (fun uses -> uses.GetUsesOfSymbol symbol.Item) | Choice2Of2 tcSymbolUses -> tcSymbolUses.GetUsesOfSymbol symbol.Item @@ -2292,13 +2292,13 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetAllUsesOfAllSymbols(?cancellationToken: CancellationToken) = - let (tcGlobals, tcImports, thisCcu, ccuSig, builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() + let (tcGlobals, tcImports, thisCcu, ccuSig, symbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails() let cenv = SymbolEnv(tcGlobals, thisCcu, Some ccuSig, tcImports) let tcSymbolUses = - match builderOrSymbolUses with - | Choice1Of2 builder -> - builder() + match symbolUses with + | Choice1Of2 getSymbolUses -> + getSymbolUses() | Choice2Of2 tcSymbolUses -> [|tcSymbolUses|] diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index cb58d3bedf7..7608835f24a 100644 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -429,7 +429,7 @@ type BoundModel private (tcConfig: TcConfig, match tcInfoNode with | TcInfoNode(_, fullGraphNode) -> match fullGraphNode.TryPeekValue() with - | ValueSome(tcInfo, tcInfoExtras) -> Some(tcInfo, tcInfoExtras) + | ValueSome(_, tcInfoExtras) -> Some tcInfoExtras | _ -> None member _.GetOrComputeTcInfo() = diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi index 8444908eba2..6dcbcc2c461 100755 --- a/src/fsharp/service/IncrementalBuild.fsi +++ b/src/fsharp/service/IncrementalBuild.fsi @@ -111,7 +111,7 @@ type internal PartialCheckResults = /// Peek to see the results. /// For thread-safe access to pre-computed results /// If `enablePartialTypeChecking` is false then extras will be available - member TryPeekTcInfoWithExtras: unit -> (TcInfo * TcInfoExtras) option + member TryPeekTcInfoExtras: unit -> TcInfoExtras option /// Compute the "TcInfo" part of the results. If `enablePartialTypeChecking` is false then /// extras will also be available, otherwise they will be empty diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 7805a5511f7..63f6bb838be 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -879,8 +879,8 @@ type BackgroundCompiler( |> Array.map (fun x -> match builder.GetCheckResultsForFileInProjectEvenIfStale x with | Some partialCheckResults -> - match partialCheckResults.TryPeekTcInfoWithExtras() with - | Some(_, tcInfoExtras) -> + match partialCheckResults.TryPeekTcInfoExtras() with + | Some tcInfoExtras -> tcInfoExtras.TcSymbolUses | _ -> TcSymbolUses.Empty