diff --git a/src/FSharpLint.Core/Application/Lint.fs b/src/FSharpLint.Core/Application/Lint.fs index c63694a91..da988cc96 100644 --- a/src/FSharpLint.Core/Application/Lint.fs +++ b/src/FSharpLint.Core/Application/Lint.fs @@ -476,7 +476,7 @@ module Lint = let parsedFiles = files |> List.filter (not << isIgnoredFile) - |> List.map (fun file -> ParseFile.parseFile file checker (Some projectOptions)) + |> List.map (fun file -> ParseFile.parseFile file checker (Some projectOptions) |> Async.RunSynchronously) let failedFiles = List.choose getFailedFiles parsedFiles @@ -585,19 +585,25 @@ module Lint = LintResult.Failure (RunTimeConfigError err) /// Lints F# source code. - let lintSource optionalParams source = - let checker = FSharpChecker.Create(keepAssemblyContents=true) + let asyncLintSource optionalParams source = + async { + let checker = FSharpChecker.Create(keepAssemblyContents=true) - match ParseFile.parseSource source checker with - | ParseFile.Success(parseFileInformation) -> - let parsedFileInfo = - { Source = parseFileInformation.Text - Ast = parseFileInformation.Ast - TypeCheckResults = parseFileInformation.TypeCheckResults } + match! ParseFile.parseSource source checker with + | ParseFile.Success(parseFileInformation) -> + let parsedFileInfo = + { Source = parseFileInformation.Text + Ast = parseFileInformation.Ast + TypeCheckResults = parseFileInformation.TypeCheckResults } - lintParsedSource optionalParams parsedFileInfo - | ParseFile.Failed failure -> LintResult.Failure(FailedToParseFile failure) + return lintParsedSource optionalParams parsedFileInfo + | ParseFile.Failed failure -> return LintResult.Failure(FailedToParseFile failure) + } + /// Lints F# source code. + let lintSource optionalParams source = + asyncLintSource optionalParams source |> Async.RunSynchronously + /// Lints an F# file that has already been parsed using `FSharp.Compiler.Services` in the calling application. let lintParsedFile (optionalParams:OptionalLintParameters) (parsedFileInfo:ParsedFileInformation) (filePath:string) = match getConfig optionalParams.Configuration with @@ -631,7 +637,7 @@ module Lint = if IO.File.Exists filePath then let checker = FSharpChecker.Create(keepAssemblyContents=true) - match ParseFile.parseFile filePath checker None with + match ParseFile.parseFile filePath checker None |> Async.RunSynchronously with | ParseFile.Success astFileParseInfo -> let parsedFileInfo = { Source = astFileParseInfo.Text @@ -654,7 +660,7 @@ module Lint = let lintSingleFile filePath = if IO.File.Exists filePath then - match ParseFile.parseFile filePath checker None with + match ParseFile.parseFile filePath checker None |> Async.RunSynchronously with | ParseFile.Success astFileParseInfo -> let parsedFileInfo = { Source = astFileParseInfo.Text diff --git a/src/FSharpLint.Core/Application/Lint.fsi b/src/FSharpLint.Core/Application/Lint.fsi index 6d7eb05ad..29ddd3332 100644 --- a/src/FSharpLint.Core/Application/Lint.fsi +++ b/src/FSharpLint.Core/Application/Lint.fsi @@ -156,6 +156,9 @@ module Lint = /// Lints F# source code. val lintSource : optionalParams:OptionalLintParameters -> source:string -> LintResult + /// Lints F# source code async. + val asyncLintSource : optionalParams:OptionalLintParameters -> source:string -> Async + /// Lints F# source code that has already been parsed using /// `FSharp.Compiler.Services` in the calling application. val lintParsedSource : optionalParams:OptionalLintParameters -> parsedFileInfo:ParsedFileInformation -> LintResult @@ -168,4 +171,4 @@ module Lint = /// Lints an F# file that has already been parsed using /// `FSharp.Compiler.Services` in the calling application. - val lintParsedFile : optionalParams:OptionalLintParameters -> parsedFileInfo:ParsedFileInformation -> filePath:string -> LintResult \ No newline at end of file + val lintParsedFile : optionalParams:OptionalLintParameters -> parsedFileInfo:ParsedFileInformation -> filePath:string -> LintResult diff --git a/src/FSharpLint.Core/Framework/ParseFile.fs b/src/FSharpLint.Core/Framework/ParseFile.fs index ac4208a36..6a5edcb56 100644 --- a/src/FSharpLint.Core/Framework/ParseFile.fs +++ b/src/FSharpLint.Core/Framework/ParseFile.fs @@ -1,4 +1,4 @@ -namespace FSharpLint.Framework +namespace FSharpLint.Framework /// Provides functionality to parse F# files using `FSharp.Compiler.Service`. module ParseFile = @@ -37,49 +37,51 @@ module ParseFile = | Failed of ParseFileFailure | Success of 'Content - let private parse file source (checker:FSharpChecker, options) = + let private parse file source (checker:FSharpChecker, options) = async { let sourceText = SourceText.ofString source - let (parseResults, checkFileAnswer) = + let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(file, 0, sourceText, options) - |> Async.RunSynchronously match checkFileAnswer with | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> - Success + return Success { Text = source Ast = parseResults.ParseTree TypeCheckResults = Some(typeCheckResults) File = file } - | FSharpCheckFileAnswer.Aborted -> Failed(AbortedTypeCheck) + | FSharpCheckFileAnswer.Aborted -> return Failed(AbortedTypeCheck) + } - let getProjectOptionsFromScript (checker:FSharpChecker) file (source:string) = + let getProjectOptionsFromScript (checker:FSharpChecker) file (source:string) = async { let sourceText = SourceText.ofString source let assumeDotNetFramework = false let otherOpts = [| "--targetprofile:netstandard" |] - let (options, _diagnostics) = + let! options, _diagnostics = checker.GetProjectOptionsFromScript(file, sourceText, assumeDotNetFramework = assumeDotNetFramework, useSdkRefs = not assumeDotNetFramework, otherFlags = otherOpts) - |> Async.RunSynchronously - options + return options + } /// Parses a file using `FSharp.Compiler.Service`. - let parseFile file (checker:FSharpChecker) projectOptions = + let parseFile file (checker:FSharpChecker) projectOptions = async { let source = File.ReadAllText(file) - let projectOptions = + let! projectOptions = match projectOptions with - | Some(existingOptions) -> existingOptions + | Some(existingOptions) -> async { return existingOptions } | None -> getProjectOptionsFromScript checker file source - parse file source (checker, projectOptions) + return! parse file source (checker, projectOptions) + } /// Parses source code using `FSharp.Compiler.Service`. - let parseSourceFile fileName source (checker:FSharpChecker) = - let options = getProjectOptionsFromScript checker fileName source + let parseSourceFile fileName source (checker:FSharpChecker) = async { + let! options = getProjectOptionsFromScript checker fileName source - parse fileName source (checker, options) + return! parse fileName source (checker, options) + } let parseSource source (checker:FSharpChecker) = let fileName = Path.ChangeExtension(Path.GetTempFileName(), "fsx") diff --git a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs index 44fa93e72..a1c99fe86 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestAstNodeRule.fs @@ -28,7 +28,7 @@ type TestAstNodeRuleBase (rule:Rule) = let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig - match parseResults with + match Async.RunSynchronously parseResults with | ParseFileResult.Success parseInfo -> let syntaxArray = AbstractSyntaxArray.astToArray parseInfo.Ast let checkResult = diff --git a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs index e81a14b06..1339649a8 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestHintMatcherBase.fs @@ -51,7 +51,7 @@ type TestHintMatcherBase () = let globalConfig = Option.defaultValue GlobalRuleConfig.Default globalConfig - match parseResults with + match Async.RunSynchronously parseResults with | ParseFileResult.Success parseInfo -> let syntaxArray = AbstractSyntaxArray.astToArray parseInfo.Ast let checkResult = diff --git a/tests/FSharpLint.Core.Tests/TestUtils.fs b/tests/FSharpLint.Core.Tests/TestUtils.fs index 1a26a61cf..cdcb8ae46 100644 --- a/tests/FSharpLint.Core.Tests/TestUtils.fs +++ b/tests/FSharpLint.Core.Tests/TestUtils.fs @@ -15,17 +15,22 @@ let private performanceTestSourceFile = basePath "TypeChecker.fs" - let generateAst source = - let checker = FSharpChecker.Create(keepAssemblyContents=true) - let sourceText = SourceText.ofString source + let asyncGenerateAst source = + async { + let checker = FSharpChecker.Create(keepAssemblyContents=true) + let sourceText = SourceText.ofString source + + let! options = + ParseFile.getProjectOptionsFromScript checker performanceTestSourceFile source - let options = ParseFile.getProjectOptionsFromScript checker performanceTestSourceFile source + let! parseResults = + checker.ParseFile(performanceTestSourceFile, sourceText, options |> checker.GetParsingOptionsFromProjectOptions |> fst) - let parseResults = - checker.ParseFile(performanceTestSourceFile, sourceText, options |> checker.GetParsingOptionsFromProjectOptions |> fst) - |> Async.RunSynchronously + return parseResults.ParseTree + } - parseResults.ParseTree + let generateAst source = + asyncGenerateAst source |> Async.RunSynchronously let getPerformanceTestInput = let memoizedResult = ref None