From 44792763c716a01f12fb8c3464b4ce822e0b1ef9 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 20 Sep 2023 16:22:08 +0200 Subject: [PATCH 1/9] - add a JsonSerializerOptions analyzer - refactor testing code - add tests for new analyzer --- src/FSharp.Analyzers/FSharp.Analyzers.fsproj | 1 + .../JsonSerializerOptionsAnalyzer.fs | 165 ++++++++++++++++ .../FSharp.Analyzers.Tests.fsproj | 2 + .../JsonSerializerOptionsAnalyzerTests.fs | 58 ++++++ .../StringAnalyzerTests.fs | 186 +++++++----------- tests/FSharp.Analyzers.Tests/Testing.fs | 46 +++++ .../Deserialize call with ctor.fs | 9 + .../Deserialize call with ctor.fs.expected | 3 + .../Deserialize calls with new ctor.fs | 9 + ...eserialize calls with new ctor.fs.expected | 3 + .../Serialize call with cached options.fs | 14 ++ ...alize call with cached options.fs.expected | 1 + .../Serialize call with ctor.fs | 12 ++ .../Serialize call with ctor.fs.expected | 6 + .../Serialize calls with new ctor.fs | 12 ++ .../Serialize calls with new ctor.fs.expected | 6 + 16 files changed, 423 insertions(+), 110 deletions(-) create mode 100644 src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs create mode 100644 tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs create mode 100644 tests/FSharp.Analyzers.Tests/Testing.fs create mode 100644 tests/data/jsonserializeroptions/Deserialize call with ctor.fs create mode 100644 tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected create mode 100644 tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs create mode 100644 tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected create mode 100644 tests/data/jsonserializeroptions/Serialize call with cached options.fs create mode 100644 tests/data/jsonserializeroptions/Serialize call with cached options.fs.expected create mode 100644 tests/data/jsonserializeroptions/Serialize call with ctor.fs create mode 100644 tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected create mode 100644 tests/data/jsonserializeroptions/Serialize calls with new ctor.fs create mode 100644 tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected diff --git a/src/FSharp.Analyzers/FSharp.Analyzers.fsproj b/src/FSharp.Analyzers/FSharp.Analyzers.fsproj index 60aeb4c..58810ab 100644 --- a/src/FSharp.Analyzers/FSharp.Analyzers.fsproj +++ b/src/FSharp.Analyzers/FSharp.Analyzers.fsproj @@ -11,6 +11,7 @@ + diff --git a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs new file mode 100644 index 0000000..25c30fe --- /dev/null +++ b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs @@ -0,0 +1,165 @@ +namespace ``G-Research``.FSharp.Analyzers + +open System +open FSharp.Analyzers.SDK +open FSharp.Compiler.Symbols +open FSharp.Compiler.Text +open FSharp.Compiler.Symbols.FSharpExprPatterns + +module JsonSerializerOptionsAnalyzer = + + [] + let Code = "GRA-002" + + let rec visitExpr memberCallHandler (e : FSharpExpr) = + match e with + | AddressOf (lvalueExpr) -> visitExpr memberCallHandler lvalueExpr + | AddressSet (lvalueExpr, rvalueExpr) -> + visitExpr memberCallHandler lvalueExpr + visitExpr memberCallHandler rvalueExpr + | Application (funcExpr, _typeArgs, argExprs) -> + visitExpr memberCallHandler funcExpr + visitExprs memberCallHandler argExprs + | Call (objExprOpt, memberOrFunc, _typeArgs1, _typeArgs2, argExprs) -> // memberOrFunc = Deserialize + memberCallHandler e.Range memberOrFunc argExprs + visitObjArg memberCallHandler objExprOpt + visitExprs memberCallHandler argExprs + | Coerce (_targetType, inpExpr) -> visitExpr memberCallHandler inpExpr + | FastIntegerForLoop (startExpr, limitExpr, consumeExpr, _isUp, _debugPointAtFor, _debugPointAtInOrTo) -> + visitExpr memberCallHandler startExpr + visitExpr memberCallHandler limitExpr + visitExpr memberCallHandler consumeExpr + | ILAsm (_asmCode, _typeArgs, argExprs) -> visitExprs memberCallHandler argExprs + | ILFieldGet (objExprOpt, _fieldType, _fieldName) -> visitObjArg memberCallHandler objExprOpt + | ILFieldSet (objExprOpt, _fieldType, _fieldName, _valueExpr) -> visitObjArg memberCallHandler objExprOpt + | IfThenElse (guardExpr, thenExpr, elseExpr) -> + visitExpr memberCallHandler guardExpr + visitExpr memberCallHandler thenExpr + visitExpr memberCallHandler elseExpr + | Lambda (_lambdaVar, bodyExpr) -> visitExpr memberCallHandler bodyExpr + | Let ((_bindingVar, bindingExpr, _debugPointAtBinding), bodyExpr) -> + visitExpr memberCallHandler bindingExpr + visitExpr memberCallHandler bodyExpr + | LetRec (recursiveBindings, bodyExpr) -> + let recursiveBindings' = + recursiveBindings |> List.map (fun (mfv, expr, _dp) -> (mfv, expr)) + + List.iter (snd >> visitExpr memberCallHandler) recursiveBindings' + visitExpr memberCallHandler bodyExpr + | NewArray (_arrayType, argExprs) -> visitExprs memberCallHandler argExprs + | NewDelegate (_delegateType, delegateBodyExpr) -> visitExpr memberCallHandler delegateBodyExpr + | NewObject (_objType, _typeArgs, argExprs) -> visitExprs memberCallHandler argExprs + | NewRecord (_recordType, argExprs) -> visitExprs memberCallHandler argExprs + | NewTuple (_tupleType, argExprs) -> visitExprs memberCallHandler argExprs + | NewUnionCase (_unionType, _unionCase, argExprs) -> visitExprs memberCallHandler argExprs + | Quote (quotedExpr) -> visitExpr memberCallHandler quotedExpr + | FSharpFieldGet (objExprOpt, _recordOrClassType, _fieldInfo) -> visitObjArg memberCallHandler objExprOpt + | FSharpFieldSet (objExprOpt, _recordOrClassType, _fieldInfo, argExpr) -> + visitObjArg memberCallHandler objExprOpt + visitExpr memberCallHandler argExpr + | Sequential (firstExpr, secondExpr) -> + visitExpr memberCallHandler firstExpr + visitExpr memberCallHandler secondExpr + | TryFinally (bodyExpr, finalizeExpr, _debugPointAtTry, _debugPointAtFinally) -> + visitExpr memberCallHandler bodyExpr + visitExpr memberCallHandler finalizeExpr + | TryWith (bodyExpr, _, _, _catchVar, catchExpr, _debugPointAtTry, _debugPointAtWith) -> + visitExpr memberCallHandler bodyExpr + visitExpr memberCallHandler catchExpr + | TupleGet (_tupleType, _tupleElemIndex, tupleExpr) -> visitExpr memberCallHandler tupleExpr + | DecisionTree (decisionExpr, decisionTargets) -> + visitExpr memberCallHandler decisionExpr + List.iter (snd >> visitExpr memberCallHandler) decisionTargets + | DecisionTreeSuccess (_decisionTargetIdx, decisionTargetExprs) -> + visitExprs memberCallHandler decisionTargetExprs + | TypeLambda (_genericParam, bodyExpr) -> visitExpr memberCallHandler bodyExpr + | TypeTest (_ty, inpExpr) -> visitExpr memberCallHandler inpExpr + | UnionCaseSet (unionExpr, _unionType, _unionCase, _unionCaseField, valueExpr) -> + visitExpr memberCallHandler unionExpr + visitExpr memberCallHandler valueExpr + | UnionCaseGet (unionExpr, _unionType, _unionCase, _unionCaseField) -> visitExpr memberCallHandler unionExpr + | UnionCaseTest (unionExpr, _unionType, _unionCase) -> visitExpr memberCallHandler unionExpr + | UnionCaseTag (unionExpr, _unionType) -> visitExpr memberCallHandler unionExpr + | ObjectExpr (_objType, baseCallExpr, overrides, interfaceImplementations) -> + visitExpr memberCallHandler baseCallExpr + List.iter (visitObjMember memberCallHandler) overrides + List.iter (snd >> List.iter (visitObjMember memberCallHandler)) interfaceImplementations + | TraitCall (_sourceTypes, _traitName, _typeArgs, _typeInstantiation, _argTypes, argExprs) -> + visitExprs memberCallHandler argExprs + | ValueSet (_valToSet, valueExpr) -> visitExpr memberCallHandler valueExpr + | WhileLoop (guardExpr, bodyExpr, _debugPointAtWhile) -> + visitExpr memberCallHandler guardExpr + visitExpr memberCallHandler bodyExpr + | BaseValue _baseType -> () + | DefaultValue _defaultType -> () + | ThisValue _thisType -> () + | Const (_constValueObj, _constType) -> () + | Value (_valueToGet) -> () + | _ -> () + + and visitExprs f exprs = List.iter (visitExpr f) exprs + + and visitObjArg f objOpt = Option.iter (visitExpr f) objOpt + + and visitObjMember f memb = visitExpr f memb.Body + + let rec visitDeclaration f d = + match d with + | FSharpImplementationFileDeclaration.Entity (_e, subDecls) -> + for subDecl in subDecls do + visitDeclaration f subDecl + | FSharpImplementationFileDeclaration.MemberOrFunctionOrValue (_v, _vs, e) -> visitExpr f e + | FSharpImplementationFileDeclaration.InitAction (e) -> visitExpr f e + + [] + let jsonSerializerOptionsAnalyzer : Analyzer = + fun ctx -> + async { + let state = ResizeArray () + + let namesToWarnAbount = + [| + "System.Text.Json.JsonSerializer.Deserialize" + "System.Text.Json.JsonSerializer.DeserializeAsync" + "System.Text.Json.JsonSerializer.DeserializeAsyncEnumerable" + "System.Text.Json.JsonSerializer.Serialize" + "System.Text.Json.JsonSerializer.SerializeAsync" + "System.Text.Json.JsonSerializer.SerializeToDocument" + "System.Text.Json.JsonSerializer.SerializeToElement" + "System.Text.Json.JsonSerializer.SerializeToNode" + "System.Text.Json.JsonSerializer.SerializeToUtf8Bytes" + |] + + let handler (range : range) (m : FSharpMemberOrFunctionOrValue) (args : FSharpExpr list) = + let name = String.Join (".", m.DeclaringEntity.Value.FullName, m.DisplayName) + + let containsSerOptsCtorCall = + args + |> List.exists ( + function + | NewObject (objType, _, _) when objType.FullName = "System.Text.Json.JsonSerializerOptions" -> + true + | _ -> false + ) + + if Array.contains name namesToWarnAbount && containsSerOptsCtorCall then + state.Add range + + match ctx.TypedTree with + | None -> () + | Some typedTree -> typedTree.Declarations |> List.iter (visitDeclaration handler) + + return + state + |> Seq.map (fun r -> + { + Type = "JsonSerializerOptions analyzer" + Message = "JsonSerializerOptions instances should be cached." + Code = Code + Severity = Warning + Range = r + Fixes = [] + } + ) + |> Seq.toList + } diff --git a/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj b/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj index 1aed30a..15d9737 100644 --- a/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj +++ b/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj @@ -10,7 +10,9 @@ + + diff --git a/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs new file mode 100644 index 0000000..24c41c6 --- /dev/null +++ b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs @@ -0,0 +1,58 @@ +namespace ``G-Research``.FSharp.Analyzers.Tests + +module JsonSerializerOptionsAnalyzerTests = + + open System.Collections + open System.IO + open NUnit.Framework + open FSharp.Compiler.CodeAnalysis + open FSharp.Analyzers.SDK.Testing + open ``G-Research``.FSharp.Analyzers + open Testing + + let mutable projectOptions : FSharpProjectOptions = FSharpProjectOptions.zero + + [] + let Setup () = + task { + let! options = + mkOptionsFromProject + "net7.0" + [ + { + Name = "System.Text.Json" + Version = "7.0.3" + } + ] + + projectOptions <- options + } + + type TestCases() = + static member DataFolder = Path.Combine (__SOURCE_DIRECTORY__, "..", "data") + + interface IEnumerable with + member _.GetEnumerator () : IEnumerator = + let jsonSerializerOptionsTests = + Path.Combine (TestCases.DataFolder, "jsonserializeroptions") + + Directory.EnumerateFiles (jsonSerializerOptionsTests, "*.fs") + |> Seq.map (fun f -> + let fileName = Path.GetRelativePath (TestCases.DataFolder, f) + [| fileName :> obj |] + ) + |> fun s -> s.GetEnumerator () + + [)>] + let JsonSerializerOptionsTests (fileName : string) = + task { + let dataFolder = TestCases.DataFolder + let fileName = Path.Combine (dataFolder, fileName) + + let! messages = + File.ReadAllText fileName + |> getContext projectOptions + |> JsonSerializerOptionsAnalyzer.jsonSerializerOptionsAnalyzer + + do! assertExpected fileName messages + } diff --git a/tests/FSharp.Analyzers.Tests/StringAnalyzerTests.fs b/tests/FSharp.Analyzers.Tests/StringAnalyzerTests.fs index 9106c9b..04302ff 100644 --- a/tests/FSharp.Analyzers.Tests/StringAnalyzerTests.fs +++ b/tests/FSharp.Analyzers.Tests/StringAnalyzerTests.fs @@ -1,110 +1,76 @@ -module ``G-Research``.FSharp.Analyzers.Tests - -open System.Collections -open System.IO -open System.Threading.Tasks -open FSharp.Compiler.CodeAnalysis -open NUnit.Framework -open FSharp.Analyzers.SDK -open FSharp.Analyzers.SDK.Testing - -let shouldUpdateBaseline () = - System.Environment.GetEnvironmentVariable "TEST_UPDATE_BSL" - |> Option.ofObj - |> Option.map (fun v -> v.Trim () = "1") - |> Option.defaultValue false - -let assertExpected sourceFile messages = - task { - let actualContents = - messages - |> List.map (fun (m : Message) -> - $"%s{m.Code} | %A{m.Severity} | (%i{m.Range.StartLine},%i{m.Range.StartColumn} - %i{m.Range.EndLine},%i{m.Range.EndColumn}) | %s{m.Message}" - ) - |> String.concat "\n" - |> fun contents -> System.String.Concat (contents, "\n") - - let expectedFile = $"%s{sourceFile}.expected" - let actualFile = $"%s{sourceFile}.actual" - - let! expectedContents = - if File.Exists expectedFile then - File.ReadAllTextAsync expectedFile - else - Task.FromResult "No baseline was found" - - let areEqual = expectedContents = actualContents - - if shouldUpdateBaseline () then - do! File.WriteAllTextAsync (expectedFile, actualContents) - elif not areEqual then - do! File.WriteAllTextAsync (actualFile, actualContents) - elif File.Exists actualFile then - File.Delete actualFile - - Assert.AreEqual (expectedContents, actualContents) - } - -let mutable projectOptions : FSharpProjectOptions = FSharpProjectOptions.zero - -[] -let Setup () = - task { - let! options = mkOptionsFromProject "net6.0" [] - projectOptions <- options - } - -type TestCases() = - static member DataFolder = Path.Combine (__SOURCE_DIRECTORY__, "..", "data") - - interface IEnumerable with - member _.GetEnumerator () : IEnumerator = - let endsWithTests = Path.Combine (TestCases.DataFolder, "string", "endswith") - - Directory.EnumerateFiles (endsWithTests, "*.fs") - |> Seq.map (fun f -> - let fileName = Path.GetRelativePath (TestCases.DataFolder, f) - [| fileName :> obj |] - ) - |> fun s -> s.GetEnumerator () - -[)>] -let EndsWithTests (fileName : string) = - task { - let dataFolder = TestCases.DataFolder - let fileName = Path.Combine (dataFolder, fileName) - - let! messages = - File.ReadAllText fileName - |> getContext projectOptions - |> StringAnalyzers.endsWithAnalyzer - - do! assertExpected fileName messages - } - -type NegativeTestCases() = - - interface IEnumerable with - member _.GetEnumerator () : IEnumerator = - let endsWithTests = - Path.Combine (TestCases.DataFolder, "string", "endswith", "negative") - - Directory.EnumerateFiles (endsWithTests, "*.fs") - |> Seq.map (fun f -> - let fileName = Path.GetRelativePath (TestCases.DataFolder, f) - [| fileName :> obj |] - ) - |> fun s -> s.GetEnumerator () - -[)>] -let NegativeEndsWithTests (fileName : string) = - task { - let fileName = Path.Combine (TestCases.DataFolder, fileName) - - let! messages = - File.ReadAllText fileName - |> getContext projectOptions - |> StringAnalyzers.endsWithAnalyzer - - Assert.IsEmpty messages - } +namespace ``G-Research``.FSharp.Analyzers.Tests + +module StringAnalyzerTests = + + open System.Collections + open System.IO + open FSharp.Compiler.CodeAnalysis + open NUnit.Framework + open FSharp.Analyzers.SDK + open FSharp.Analyzers.SDK.Testing + open ``G-Research``.FSharp.Analyzers + open Testing + + let mutable projectOptions : FSharpProjectOptions = FSharpProjectOptions.zero + + [] + let Setup () = + task { + let! options = mkOptionsFromProject "net6.0" [] + projectOptions <- options + } + + type TestCases() = + static member DataFolder = Path.Combine (__SOURCE_DIRECTORY__, "..", "data") + + interface IEnumerable with + member _.GetEnumerator () : IEnumerator = + let endsWithTests = Path.Combine (TestCases.DataFolder, "string", "endswith") + + Directory.EnumerateFiles (endsWithTests, "*.fs") + |> Seq.map (fun f -> + let fileName = Path.GetRelativePath (TestCases.DataFolder, f) + [| fileName :> obj |] + ) + |> fun s -> s.GetEnumerator () + + [)>] + let EndsWithTests (fileName : string) = + task { + let dataFolder = TestCases.DataFolder + let fileName = Path.Combine (dataFolder, fileName) + + let! messages = + File.ReadAllText fileName + |> getContext projectOptions + |> StringAnalyzers.endsWithAnalyzer + + do! assertExpected fileName messages + } + + type NegativeTestCases() = + + interface IEnumerable with + member _.GetEnumerator () : IEnumerator = + let endsWithTests = + Path.Combine (TestCases.DataFolder, "string", "endswith", "negative") + + Directory.EnumerateFiles (endsWithTests, "*.fs") + |> Seq.map (fun f -> + let fileName = Path.GetRelativePath (TestCases.DataFolder, f) + [| fileName :> obj |] + ) + |> fun s -> s.GetEnumerator () + + [)>] + let NegativeEndsWithTests (fileName : string) = + task { + let fileName = Path.Combine (TestCases.DataFolder, fileName) + + let! messages = + File.ReadAllText fileName + |> getContext projectOptions + |> StringAnalyzers.endsWithAnalyzer + + Assert.IsEmpty messages + } diff --git a/tests/FSharp.Analyzers.Tests/Testing.fs b/tests/FSharp.Analyzers.Tests/Testing.fs new file mode 100644 index 0000000..242bae5 --- /dev/null +++ b/tests/FSharp.Analyzers.Tests/Testing.fs @@ -0,0 +1,46 @@ +namespace ``G-Research``.FSharp.Analyzers.Tests + +module Testing = + + open System.IO + open System.Threading.Tasks + open NUnit.Framework + open FSharp.Analyzers.SDK + open FSharp.Analyzers.SDK.Testing + + let shouldUpdateBaseline () = + System.Environment.GetEnvironmentVariable "TEST_UPDATE_BSL" + |> Option.ofObj + |> Option.map (fun v -> v.Trim () = "1") + |> Option.defaultValue false + + let assertExpected sourceFile messages = + task { + let actualContents = + messages + |> List.map (fun (m : Message) -> + $"%s{m.Code} | %A{m.Severity} | (%i{m.Range.StartLine},%i{m.Range.StartColumn} - %i{m.Range.EndLine},%i{m.Range.EndColumn}) | %s{m.Message}" + ) + |> String.concat "\n" + |> fun contents -> System.String.Concat (contents, "\n") + + let expectedFile = $"%s{sourceFile}.expected" + let actualFile = $"%s{sourceFile}.actual" + + let! expectedContents = + if File.Exists expectedFile then + File.ReadAllTextAsync expectedFile + else + Task.FromResult "No baseline was found" + + let areEqual = expectedContents = actualContents + + if shouldUpdateBaseline () then + do! File.WriteAllTextAsync (expectedFile, actualContents) + elif not areEqual then + do! File.WriteAllTextAsync (actualFile, actualContents) + elif File.Exists actualFile then + File.Delete actualFile + + Assert.AreEqual (expectedContents, actualContents) + } diff --git a/tests/data/jsonserializeroptions/Deserialize call with ctor.fs b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs new file mode 100644 index 0000000..b5a9d23 --- /dev/null +++ b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs @@ -0,0 +1,9 @@ +module M + +open System.Text.Json + +let f (json: string) (jsonStream: System.IO.Stream) = + let _ = JsonSerializer.Deserialize(json, JsonSerializerOptions ()) + let _ = JsonSerializer.DeserializeAsync(jsonStream, JsonSerializerOptions ()) + let _ = JsonSerializer.DeserializeAsyncEnumerable(jsonStream, JsonSerializerOptions ()) + () diff --git a/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected new file mode 100644 index 0000000..df7d611 --- /dev/null +++ b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected @@ -0,0 +1,3 @@ +GRA-002 | Warning | (6,12 - 6,78) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (7,12 - 7,89) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (8,12 - 8,99) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs new file mode 100644 index 0000000..60e5ab8 --- /dev/null +++ b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs @@ -0,0 +1,9 @@ +module M + +open System.Text.Json + +let f (json: string) (jsonStream: System.IO.Stream) = + let _ = JsonSerializer.Deserialize(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.DeserializeAsync(jsonStream, new JsonSerializerOptions ()) + let _ = JsonSerializer.DeserializeAsyncEnumerable(jsonStream, new JsonSerializerOptions ()) + () \ No newline at end of file diff --git a/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected new file mode 100644 index 0000000..b551075 --- /dev/null +++ b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected @@ -0,0 +1,3 @@ +GRA-002 | Warning | (6,12 - 6,82) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (7,12 - 7,93) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (8,12 - 8,103) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Serialize call with cached options.fs b/tests/data/jsonserializeroptions/Serialize call with cached options.fs new file mode 100644 index 0000000..8b08320 --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize call with cached options.fs @@ -0,0 +1,14 @@ +module M + +open System.Text.Json + +let cachedOptions = new JsonSerializerOptions () + +let f (json: string) (jsonStream: System.IO.Stream) = + let _ = JsonSerializer.Serialize(json, cachedOptions) + let _ = JsonSerializer.SerializeAsync(jsonStream, json, cachedOptions) + let _ = JsonSerializer.SerializeToDocument(json, cachedOptions) + let _ = JsonSerializer.SerializeToElement(json, cachedOptions) + let _ = JsonSerializer.SerializeToNode(json, cachedOptions) + let _ = JsonSerializer.SerializeToUtf8Bytes(json, cachedOptions) + () diff --git a/tests/data/jsonserializeroptions/Serialize call with cached options.fs.expected b/tests/data/jsonserializeroptions/Serialize call with cached options.fs.expected new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize call with cached options.fs.expected @@ -0,0 +1 @@ + diff --git a/tests/data/jsonserializeroptions/Serialize call with ctor.fs b/tests/data/jsonserializeroptions/Serialize call with ctor.fs new file mode 100644 index 0000000..3047f2f --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize call with ctor.fs @@ -0,0 +1,12 @@ +module M + +open System.Text.Json + +let f (json: string) (jsonStream: System.IO.Stream) = + let _ = JsonSerializer.Serialize(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeAsync(jsonStream, json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToDocument(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToElement(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToNode(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToUtf8Bytes(json, new JsonSerializerOptions ()) + () diff --git a/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected b/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected new file mode 100644 index 0000000..6108800 --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected @@ -0,0 +1,6 @@ +GRA-002 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs new file mode 100644 index 0000000..3047f2f --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs @@ -0,0 +1,12 @@ +module M + +open System.Text.Json + +let f (json: string) (jsonStream: System.IO.Stream) = + let _ = JsonSerializer.Serialize(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeAsync(jsonStream, json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToDocument(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToElement(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToNode(json, new JsonSerializerOptions ()) + let _ = JsonSerializer.SerializeToUtf8Bytes(json, new JsonSerializerOptions ()) + () diff --git a/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected new file mode 100644 index 0000000..6108800 --- /dev/null +++ b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected @@ -0,0 +1,6 @@ +GRA-002 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. +GRA-002 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached. From b4cab32fe175382e177f0e99bc3d2fd34726071b Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 20 Sep 2023 17:44:09 +0200 Subject: [PATCH 2/9] use net6.0 --- .../JsonSerializerOptionsAnalyzerTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs index 24c41c6..a798569 100644 --- a/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs +++ b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs @@ -17,11 +17,11 @@ module JsonSerializerOptionsAnalyzerTests = task { let! options = mkOptionsFromProject - "net7.0" + "net6.0" [ { Name = "System.Text.Json" - Version = "7.0.3" + Version = "6.0.8" } ] From 88781a456d28d0f804476a9c4f7727cd0d7374f2 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 20 Sep 2023 18:20:26 +0200 Subject: [PATCH 3/9] update package.lock.json files --- src/FSharp.Analyzers/packages.lock.json | 290 ------------------ .../FSharp.Analyzers.Tests/packages.lock.json | 287 +---------------- 2 files changed, 1 insertion(+), 576 deletions(-) diff --git a/src/FSharp.Analyzers/packages.lock.json b/src/FSharp.Analyzers/packages.lock.json index 5db4729..c46b369 100644 --- a/src/FSharp.Analyzers/packages.lock.json +++ b/src/FSharp.Analyzers/packages.lock.json @@ -36,11 +36,6 @@ "resolved": "0.1.8", "contentHash": "hHUZIVz9BlF++B5w183c5HwbqSIXUtJU+lxhKz3ebQ5X8INBIWV7dS/FK8uSqSMUTYavuKkRRTZvJlbYXPUykg==" }, - "CliWrap": { - "type": "Transitive", - "resolved": "3.6.4", - "contentHash": "KVGVZlR0GWgN3Xr88oZMSzYu38TXIogwLz588e6wku3mIfg6lPchxpYWtZSZfurpTY63ANF61xWp8EZF3jkN4g==" - }, "McMaster.NETCore.Plugins": { "type": "Transitive", "resolved": "1.4.0", @@ -50,33 +45,11 @@ "Microsoft.Extensions.DependencyModel": "5.0.0" } }, - "Microsoft.Build.Framework": { - "type": "Transitive", - "resolved": "16.10.0", - "contentHash": "uD2GUw3AYlFSpU42c/80DouuJL6w1Kb06q4FEjQhW/9wjhBwukgx13T5MPIpSvQ8ssahKINanHfMUL89EVQHgQ==", - "dependencies": { - "System.Security.Permissions": "4.7.0" - } - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "1.1.1", "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" }, - "Microsoft.Build.Utilities.Core": { - "type": "Transitive", - "resolved": "16.10.0", - "contentHash": "R8eATgdaGCfdepd67LMe1qhJz6iQOTuI9gVoOqXrHwhc77sBDqG0XD9zKvrgOqfS6NJ03KKTAhbbXnLgD5fKCA==", - "dependencies": { - "Microsoft.Build.Framework": "16.10.0", - "Microsoft.NET.StringTools": "1.0.0", - "Microsoft.Win32.Registry": "4.3.0", - "System.Collections.Immutable": "5.0.0", - "System.Configuration.ConfigurationManager": "4.7.0", - "System.Security.Permissions": "4.7.0", - "System.Text.Encoding.CodePages": "4.0.1" - } - }, "Microsoft.DotNet.PlatformAbstractions": { "type": "Transitive", "resolved": "3.1.6", @@ -87,25 +60,6 @@ "resolved": "5.0.0", "contentHash": "umBECCoMC+sOUgm083yFr8SxTobUOcPFH4AXigdO2xJiszCHAnmeDl4qPphJt+oaJ/XIfV1wOjIts2nRnki61Q==" }, - "Microsoft.NET.StringTools": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "ZYVcoDM0LnSyT5nWoRGfShYdOecCw2sOXWwP6j1Z0u48Xq3+BVvZ+EiPCX9/8Gz439giW+O1H1kWF9Eb/w6rVg==", - "dependencies": { - "System.Memory": "4.5.4", - "System.Runtime.CompilerServices.Unsafe": "5.0.0" - } - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "3.1.0", - "contentHash": "z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" - }, "Microsoft.SourceLink.AzureRepos.Git": { "type": "Transitive", "resolved": "1.1.1", @@ -147,53 +101,11 @@ "Microsoft.SourceLink.Common": "1.1.1" } }, - "Microsoft.Win32.Registry": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0" - } - }, - "Microsoft.Win32.SystemEvents": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0" - } - }, - "MSBuild.StructuredLogger": { - "type": "Transitive", - "resolved": "2.1.815", - "contentHash": "5UfWYgsWBGI3w0npjYLeXPv8TUcNmGB/QBhoYLDeYTosuvmG6pz6HPb+xPg/Boi1bmw2Bgnjo+XopcwzCbZAqg==", - "dependencies": { - "Microsoft.Build.Framework": "16.10.0", - "Microsoft.Build.Utilities.Core": "16.10.0" - } - }, "System.Buffers": { "type": "Transitive", "resolved": "4.5.1", "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" }, - "System.Collections": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, "System.Collections.Immutable": { "type": "Transitive", "resolved": "7.0.0", @@ -202,15 +114,6 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, - "System.Configuration.ConfigurationManager": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "/anOTeSZCNNI2zDilogWrZ8pNqCmYbzGNexUnNhjW8k0sHqEZ2nHJBp147jBV3hGYswu5lINpNg1vxR7bnqvVA==", - "dependencies": { - "System.Security.Cryptography.ProtectedData": "4.7.0", - "System.Security.Permissions": "4.7.0" - } - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "7.0.2", @@ -219,54 +122,11 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, - "System.Drawing.Common": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "Microsoft.Win32.SystemEvents": "4.7.0" - } - }, - "System.Globalization": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.IO": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, "System.Reflection.Emit": { "type": "Transitive", "resolved": "4.7.0", @@ -280,166 +140,16 @@ "System.Collections.Immutable": "7.0.0" } }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Security.AccessControl": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "System.Security.Principal.Windows": "4.7.0" - } - }, - "System.Security.Cryptography.ProtectedData": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ehYW0m9ptxpGWvE4zgqongBVWpSDU/JCFD4K7krxkQwSz/sFQjEXCUqpvencjy6DYDbn7Ig09R8GFffu8TtneQ==" - }, - "System.Security.Permissions": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==", - "dependencies": { - "System.Security.AccessControl": "4.7.0", - "System.Windows.Extensions": "4.7.0" - } - }, - "System.Security.Principal.Windows": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "h4z6rrA/hxWf4655D18IIZ0eaLRa3tQC/j+e26W+VinIHY0l07iEXaAvO0YSYq3MvCjMYy8Zs5AdC1sxNQOB7Q==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "System.Collections": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Handles": "4.0.1", - "System.Runtime.InteropServices": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Threading": "4.0.11" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==", - "dependencies": { - "System.Runtime": "4.1.0", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Windows.Extensions": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==", - "dependencies": { - "System.Drawing.Common": "4.7.0" - } - }, "fsharp.analyzers.sdk": { "type": "Project", "dependencies": { - "CliWrap": "[3.6.4, )", "FSharp.Compiler.Service": "[43.7.400, )", "FSharp.Core": "[7.0.400, )", - "MSBuild.StructuredLogger": "[2.1.815, )", "McMaster.NETCore.Plugins": "[1.4.0, )" } }, diff --git a/tests/FSharp.Analyzers.Tests/packages.lock.json b/tests/FSharp.Analyzers.Tests/packages.lock.json index 776299f..ea7a324 100644 --- a/tests/FSharp.Analyzers.Tests/packages.lock.json +++ b/tests/FSharp.Analyzers.Tests/packages.lock.json @@ -39,11 +39,6 @@ "resolved": "4.5.0", "contentHash": "s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==" }, - "CliWrap": { - "type": "Transitive", - "resolved": "3.6.4", - "contentHash": "KVGVZlR0GWgN3Xr88oZMSzYu38TXIogwLz588e6wku3mIfg6lPchxpYWtZSZfurpTY63ANF61xWp8EZF3jkN4g==" - }, "McMaster.NETCore.Plugins": { "type": "Transitive", "resolved": "1.4.0", @@ -53,28 +48,6 @@ "Microsoft.Extensions.DependencyModel": "5.0.0" } }, - "Microsoft.Build.Framework": { - "type": "Transitive", - "resolved": "16.10.0", - "contentHash": "uD2GUw3AYlFSpU42c/80DouuJL6w1Kb06q4FEjQhW/9wjhBwukgx13T5MPIpSvQ8ssahKINanHfMUL89EVQHgQ==", - "dependencies": { - "System.Security.Permissions": "4.7.0" - } - }, - "Microsoft.Build.Utilities.Core": { - "type": "Transitive", - "resolved": "16.10.0", - "contentHash": "R8eATgdaGCfdepd67LMe1qhJz6iQOTuI9gVoOqXrHwhc77sBDqG0XD9zKvrgOqfS6NJ03KKTAhbbXnLgD5fKCA==", - "dependencies": { - "Microsoft.Build.Framework": "16.10.0", - "Microsoft.NET.StringTools": "1.0.0", - "Microsoft.Win32.Registry": "4.3.0", - "System.Collections.Immutable": "5.0.0", - "System.Configuration.ConfigurationManager": "4.7.0", - "System.Security.Permissions": "4.7.0", - "System.Text.Encoding.CodePages": "4.0.1" - } - }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "17.7.2", @@ -90,24 +63,10 @@ "resolved": "5.0.0", "contentHash": "umBECCoMC+sOUgm083yFr8SxTobUOcPFH4AXigdO2xJiszCHAnmeDl4qPphJt+oaJ/XIfV1wOjIts2nRnki61Q==" }, - "Microsoft.NET.StringTools": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "ZYVcoDM0LnSyT5nWoRGfShYdOecCw2sOXWwP6j1Z0u48Xq3+BVvZ+EiPCX9/8Gz439giW+O1H1kWF9Eb/w6rVg==", - "dependencies": { - "System.Memory": "4.5.4", - "System.Runtime.CompilerServices.Unsafe": "5.0.0" - } - }, "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "3.1.0", - "contentHash": "z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==" - }, - "Microsoft.NETCore.Targets": { "type": "Transitive", "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", @@ -127,38 +86,6 @@ "Newtonsoft.Json": "13.0.1" } }, - "Microsoft.Win32.Registry": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0" - } - }, - "Microsoft.Win32.SystemEvents": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0" - } - }, - "MSBuild.StructuredLogger": { - "type": "Transitive", - "resolved": "2.1.815", - "contentHash": "5UfWYgsWBGI3w0npjYLeXPv8TUcNmGB/QBhoYLDeYTosuvmG6pz6HPb+xPg/Boi1bmw2Bgnjo+XopcwzCbZAqg==", - "dependencies": { - "Microsoft.Build.Framework": "16.10.0", - "Microsoft.Build.Utilities.Core": "16.10.0" - } - }, "NETStandard.Library": { "type": "Transitive", "resolved": "2.0.0", @@ -182,16 +109,6 @@ "resolved": "4.5.1", "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" }, - "System.Collections": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, "System.Collections.Immutable": { "type": "Transitive", "resolved": "7.0.0", @@ -200,15 +117,6 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, - "System.Configuration.ConfigurationManager": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "/anOTeSZCNNI2zDilogWrZ8pNqCmYbzGNexUnNhjW8k0sHqEZ2nHJBp147jBV3hGYswu5lINpNg1vxR7bnqvVA==", - "dependencies": { - "System.Security.Cryptography.ProtectedData": "4.7.0", - "System.Security.Permissions": "4.7.0" - } - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "7.0.2", @@ -217,54 +125,11 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, - "System.Drawing.Common": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "Microsoft.Win32.SystemEvents": "4.7.0" - } - }, - "System.Globalization": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.IO": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, "System.Reflection.Emit": { "type": "Transitive", "resolved": "4.7.0", @@ -278,166 +143,16 @@ "System.Collections.Immutable": "7.0.0" } }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Security.AccessControl": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "System.Security.Principal.Windows": "4.7.0" - } - }, - "System.Security.Cryptography.ProtectedData": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ehYW0m9ptxpGWvE4zgqongBVWpSDU/JCFD4K7krxkQwSz/sFQjEXCUqpvencjy6DYDbn7Ig09R8GFffu8TtneQ==" - }, - "System.Security.Permissions": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==", - "dependencies": { - "System.Security.AccessControl": "4.7.0", - "System.Windows.Extensions": "4.7.0" - } - }, - "System.Security.Principal.Windows": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "h4z6rrA/hxWf4655D18IIZ0eaLRa3tQC/j+e26W+VinIHY0l07iEXaAvO0YSYq3MvCjMYy8Zs5AdC1sxNQOB7Q==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "System.Collections": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Handles": "4.0.1", - "System.Runtime.InteropServices": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Threading": "4.0.11" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==", - "dependencies": { - "System.Runtime": "4.1.0", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Windows.Extensions": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==", - "dependencies": { - "System.Drawing.Common": "4.7.0" - } - }, "fsharp.analyzers.sdk": { "type": "Project", "dependencies": { - "CliWrap": "[3.6.4, )", "FSharp.Compiler.Service": "[43.7.400, )", "FSharp.Core": "[7.0.400, )", - "MSBuild.StructuredLogger": "[2.1.815, )", "McMaster.NETCore.Plugins": "[1.4.0, )" } }, From fec4a4130077162ba4f557719954bd5ceb12ff80 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 20 Sep 2023 18:20:49 +0200 Subject: [PATCH 4/9] Revert "use net6.0" This reverts commit b4cab32fe175382e177f0e99bc3d2fd34726071b. --- .../JsonSerializerOptionsAnalyzerTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs index a798569..24c41c6 100644 --- a/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs +++ b/tests/FSharp.Analyzers.Tests/JsonSerializerOptionsAnalyzerTests.fs @@ -17,11 +17,11 @@ module JsonSerializerOptionsAnalyzerTests = task { let! options = mkOptionsFromProject - "net6.0" + "net7.0" [ { Name = "System.Text.Json" - Version = "6.0.8" + Version = "7.0.3" } ] From 957a81ca7766d900ed5ccf7b1bd47c829303fe50 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 20 Sep 2023 18:35:05 +0200 Subject: [PATCH 5/9] Add proj reference after split in SDK --- .../FSharp.Analyzers.Tests.fsproj | 1 + .../FSharp.Analyzers.Tests/packages.lock.json | 294 +++++++++++++++++- 2 files changed, 294 insertions(+), 1 deletion(-) diff --git a/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj b/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj index 15d9737..31541d9 100644 --- a/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj +++ b/tests/FSharp.Analyzers.Tests/FSharp.Analyzers.Tests.fsproj @@ -26,6 +26,7 @@ + diff --git a/tests/FSharp.Analyzers.Tests/packages.lock.json b/tests/FSharp.Analyzers.Tests/packages.lock.json index ea7a324..2388b1d 100644 --- a/tests/FSharp.Analyzers.Tests/packages.lock.json +++ b/tests/FSharp.Analyzers.Tests/packages.lock.json @@ -39,6 +39,11 @@ "resolved": "4.5.0", "contentHash": "s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==" }, + "CliWrap": { + "type": "Transitive", + "resolved": "3.6.4", + "contentHash": "KVGVZlR0GWgN3Xr88oZMSzYu38TXIogwLz588e6wku3mIfg6lPchxpYWtZSZfurpTY63ANF61xWp8EZF3jkN4g==" + }, "McMaster.NETCore.Plugins": { "type": "Transitive", "resolved": "1.4.0", @@ -48,6 +53,28 @@ "Microsoft.Extensions.DependencyModel": "5.0.0" } }, + "Microsoft.Build.Framework": { + "type": "Transitive", + "resolved": "16.10.0", + "contentHash": "uD2GUw3AYlFSpU42c/80DouuJL6w1Kb06q4FEjQhW/9wjhBwukgx13T5MPIpSvQ8ssahKINanHfMUL89EVQHgQ==", + "dependencies": { + "System.Security.Permissions": "4.7.0" + } + }, + "Microsoft.Build.Utilities.Core": { + "type": "Transitive", + "resolved": "16.10.0", + "contentHash": "R8eATgdaGCfdepd67LMe1qhJz6iQOTuI9gVoOqXrHwhc77sBDqG0XD9zKvrgOqfS6NJ03KKTAhbbXnLgD5fKCA==", + "dependencies": { + "Microsoft.Build.Framework": "16.10.0", + "Microsoft.NET.StringTools": "1.0.0", + "Microsoft.Win32.Registry": "4.3.0", + "System.Collections.Immutable": "5.0.0", + "System.Configuration.ConfigurationManager": "4.7.0", + "System.Security.Permissions": "4.7.0", + "System.Text.Encoding.CodePages": "4.0.1" + } + }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "17.7.2", @@ -63,10 +90,24 @@ "resolved": "5.0.0", "contentHash": "umBECCoMC+sOUgm083yFr8SxTobUOcPFH4AXigdO2xJiszCHAnmeDl4qPphJt+oaJ/XIfV1wOjIts2nRnki61Q==" }, + "Microsoft.NET.StringTools": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "ZYVcoDM0LnSyT5nWoRGfShYdOecCw2sOXWwP6j1Z0u48Xq3+BVvZ+EiPCX9/8Gz439giW+O1H1kWF9Eb/w6rVg==", + "dependencies": { + "System.Memory": "4.5.4", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + } + }, "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==" + }, + "Microsoft.NETCore.Targets": { "type": "Transitive", "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", @@ -86,6 +127,38 @@ "Newtonsoft.Json": "13.0.1" } }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0" + } + }, + "MSBuild.StructuredLogger": { + "type": "Transitive", + "resolved": "2.1.815", + "contentHash": "5UfWYgsWBGI3w0npjYLeXPv8TUcNmGB/QBhoYLDeYTosuvmG6pz6HPb+xPg/Boi1bmw2Bgnjo+XopcwzCbZAqg==", + "dependencies": { + "Microsoft.Build.Framework": "16.10.0", + "Microsoft.Build.Utilities.Core": "16.10.0" + } + }, "NETStandard.Library": { "type": "Transitive", "resolved": "2.0.0", @@ -109,6 +182,16 @@ "resolved": "4.5.1", "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, "System.Collections.Immutable": { "type": "Transitive", "resolved": "7.0.0", @@ -117,6 +200,15 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "/anOTeSZCNNI2zDilogWrZ8pNqCmYbzGNexUnNhjW8k0sHqEZ2nHJBp147jBV3hGYswu5lINpNg1vxR7bnqvVA==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "4.7.0", + "System.Security.Permissions": "4.7.0" + } + }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "7.0.2", @@ -125,11 +217,54 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.Win32.SystemEvents": "4.7.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, "System.Reflection.Emit": { "type": "Transitive", "resolved": "4.7.0", @@ -143,11 +278,159 @@ "System.Collections.Immutable": "7.0.0" } }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "ehYW0m9ptxpGWvE4zgqongBVWpSDU/JCFD4K7krxkQwSz/sFQjEXCUqpvencjy6DYDbn7Ig09R8GFffu8TtneQ==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==", + "dependencies": { + "System.Security.AccessControl": "4.7.0", + "System.Windows.Extensions": "4.7.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.CodePages": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "h4z6rrA/hxWf4655D18IIZ0eaLRa3tQC/j+e26W+VinIHY0l07iEXaAvO0YSYq3MvCjMYy8Zs5AdC1sxNQOB7Q==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.Collections": "4.0.11", + "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.Reflection": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Runtime.Handles": "4.0.1", + "System.Runtime.InteropServices": "4.1.0", + "System.Text.Encoding": "4.0.11", + "System.Threading": "4.0.11" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.0.11", + "contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==", + "dependencies": { + "System.Runtime": "4.1.0", + "System.Threading.Tasks": "4.0.11" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==", + "dependencies": { + "System.Drawing.Common": "4.7.0" + } + }, "fsharp.analyzers.sdk": { "type": "Project", "dependencies": { @@ -156,6 +439,15 @@ "McMaster.NETCore.Plugins": "[1.4.0, )" } }, + "fsharp.analyzers.sdk.testing": { + "type": "Project", + "dependencies": { + "CliWrap": "[3.6.4, )", + "FSharp.Analyzers.SDK": "[1.0.0, )", + "FSharp.Compiler.Service": "[43.7.400, )", + "MSBuild.StructuredLogger": "[2.1.815, )" + } + }, "G-Research.FSharp.Analyzers": { "type": "Project", "dependencies": { From 1213f17df6787f1d72b52f1b527f8a5ce0fdaf30 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 21 Sep 2023 10:01:56 +0200 Subject: [PATCH 6/9] Check the Assembly of the called mfv and also of the called ctor --- src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs index 25c30fe..a1efdcc 100644 --- a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs +++ b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs @@ -137,12 +137,19 @@ module JsonSerializerOptionsAnalyzer = args |> List.exists ( function - | NewObject (objType, _, _) when objType.FullName = "System.Text.Json.JsonSerializerOptions" -> + | NewObject (objType, _, _) when + objType.FullName = "System.Text.Json.JsonSerializerOptions" + && objType.Assembly.SimpleName = "System.Text.Json" + -> true | _ -> false ) - if Array.contains name namesToWarnAbount && containsSerOptsCtorCall then + if + m.Assembly.SimpleName = "System.Text.Json" + && Array.contains name namesToWarnAbount + && containsSerOptsCtorCall + then state.Add range match ctx.TypedTree with From 98563c15182aef1bb4ef12b7ad8952a9fb216996 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 21 Sep 2023 14:29:24 +0200 Subject: [PATCH 7/9] Move TAST handling to it's own module and start the ground work to have different handlers for the various parts of the TAST an analyzer might want to handle. --- src/FSharp.Analyzers/FSharp.Analyzers.fsproj | 1 + .../JsonSerializerOptionsAnalyzer.fs | 147 ++++-------------- src/FSharp.Analyzers/TASTCollection.fs | 110 +++++++++++++ 3 files changed, 137 insertions(+), 121 deletions(-) create mode 100644 src/FSharp.Analyzers/TASTCollection.fs diff --git a/src/FSharp.Analyzers/FSharp.Analyzers.fsproj b/src/FSharp.Analyzers/FSharp.Analyzers.fsproj index 58810ab..029508c 100644 --- a/src/FSharp.Analyzers/FSharp.Analyzers.fsproj +++ b/src/FSharp.Analyzers/FSharp.Analyzers.fsproj @@ -10,6 +10,7 @@ + diff --git a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs index a1efdcc..8e05ad1 100644 --- a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs +++ b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs @@ -5,112 +5,13 @@ open FSharp.Analyzers.SDK open FSharp.Compiler.Symbols open FSharp.Compiler.Text open FSharp.Compiler.Symbols.FSharpExprPatterns +open TASTCollection module JsonSerializerOptionsAnalyzer = [] let Code = "GRA-002" - let rec visitExpr memberCallHandler (e : FSharpExpr) = - match e with - | AddressOf (lvalueExpr) -> visitExpr memberCallHandler lvalueExpr - | AddressSet (lvalueExpr, rvalueExpr) -> - visitExpr memberCallHandler lvalueExpr - visitExpr memberCallHandler rvalueExpr - | Application (funcExpr, _typeArgs, argExprs) -> - visitExpr memberCallHandler funcExpr - visitExprs memberCallHandler argExprs - | Call (objExprOpt, memberOrFunc, _typeArgs1, _typeArgs2, argExprs) -> // memberOrFunc = Deserialize - memberCallHandler e.Range memberOrFunc argExprs - visitObjArg memberCallHandler objExprOpt - visitExprs memberCallHandler argExprs - | Coerce (_targetType, inpExpr) -> visitExpr memberCallHandler inpExpr - | FastIntegerForLoop (startExpr, limitExpr, consumeExpr, _isUp, _debugPointAtFor, _debugPointAtInOrTo) -> - visitExpr memberCallHandler startExpr - visitExpr memberCallHandler limitExpr - visitExpr memberCallHandler consumeExpr - | ILAsm (_asmCode, _typeArgs, argExprs) -> visitExprs memberCallHandler argExprs - | ILFieldGet (objExprOpt, _fieldType, _fieldName) -> visitObjArg memberCallHandler objExprOpt - | ILFieldSet (objExprOpt, _fieldType, _fieldName, _valueExpr) -> visitObjArg memberCallHandler objExprOpt - | IfThenElse (guardExpr, thenExpr, elseExpr) -> - visitExpr memberCallHandler guardExpr - visitExpr memberCallHandler thenExpr - visitExpr memberCallHandler elseExpr - | Lambda (_lambdaVar, bodyExpr) -> visitExpr memberCallHandler bodyExpr - | Let ((_bindingVar, bindingExpr, _debugPointAtBinding), bodyExpr) -> - visitExpr memberCallHandler bindingExpr - visitExpr memberCallHandler bodyExpr - | LetRec (recursiveBindings, bodyExpr) -> - let recursiveBindings' = - recursiveBindings |> List.map (fun (mfv, expr, _dp) -> (mfv, expr)) - - List.iter (snd >> visitExpr memberCallHandler) recursiveBindings' - visitExpr memberCallHandler bodyExpr - | NewArray (_arrayType, argExprs) -> visitExprs memberCallHandler argExprs - | NewDelegate (_delegateType, delegateBodyExpr) -> visitExpr memberCallHandler delegateBodyExpr - | NewObject (_objType, _typeArgs, argExprs) -> visitExprs memberCallHandler argExprs - | NewRecord (_recordType, argExprs) -> visitExprs memberCallHandler argExprs - | NewTuple (_tupleType, argExprs) -> visitExprs memberCallHandler argExprs - | NewUnionCase (_unionType, _unionCase, argExprs) -> visitExprs memberCallHandler argExprs - | Quote (quotedExpr) -> visitExpr memberCallHandler quotedExpr - | FSharpFieldGet (objExprOpt, _recordOrClassType, _fieldInfo) -> visitObjArg memberCallHandler objExprOpt - | FSharpFieldSet (objExprOpt, _recordOrClassType, _fieldInfo, argExpr) -> - visitObjArg memberCallHandler objExprOpt - visitExpr memberCallHandler argExpr - | Sequential (firstExpr, secondExpr) -> - visitExpr memberCallHandler firstExpr - visitExpr memberCallHandler secondExpr - | TryFinally (bodyExpr, finalizeExpr, _debugPointAtTry, _debugPointAtFinally) -> - visitExpr memberCallHandler bodyExpr - visitExpr memberCallHandler finalizeExpr - | TryWith (bodyExpr, _, _, _catchVar, catchExpr, _debugPointAtTry, _debugPointAtWith) -> - visitExpr memberCallHandler bodyExpr - visitExpr memberCallHandler catchExpr - | TupleGet (_tupleType, _tupleElemIndex, tupleExpr) -> visitExpr memberCallHandler tupleExpr - | DecisionTree (decisionExpr, decisionTargets) -> - visitExpr memberCallHandler decisionExpr - List.iter (snd >> visitExpr memberCallHandler) decisionTargets - | DecisionTreeSuccess (_decisionTargetIdx, decisionTargetExprs) -> - visitExprs memberCallHandler decisionTargetExprs - | TypeLambda (_genericParam, bodyExpr) -> visitExpr memberCallHandler bodyExpr - | TypeTest (_ty, inpExpr) -> visitExpr memberCallHandler inpExpr - | UnionCaseSet (unionExpr, _unionType, _unionCase, _unionCaseField, valueExpr) -> - visitExpr memberCallHandler unionExpr - visitExpr memberCallHandler valueExpr - | UnionCaseGet (unionExpr, _unionType, _unionCase, _unionCaseField) -> visitExpr memberCallHandler unionExpr - | UnionCaseTest (unionExpr, _unionType, _unionCase) -> visitExpr memberCallHandler unionExpr - | UnionCaseTag (unionExpr, _unionType) -> visitExpr memberCallHandler unionExpr - | ObjectExpr (_objType, baseCallExpr, overrides, interfaceImplementations) -> - visitExpr memberCallHandler baseCallExpr - List.iter (visitObjMember memberCallHandler) overrides - List.iter (snd >> List.iter (visitObjMember memberCallHandler)) interfaceImplementations - | TraitCall (_sourceTypes, _traitName, _typeArgs, _typeInstantiation, _argTypes, argExprs) -> - visitExprs memberCallHandler argExprs - | ValueSet (_valToSet, valueExpr) -> visitExpr memberCallHandler valueExpr - | WhileLoop (guardExpr, bodyExpr, _debugPointAtWhile) -> - visitExpr memberCallHandler guardExpr - visitExpr memberCallHandler bodyExpr - | BaseValue _baseType -> () - | DefaultValue _defaultType -> () - | ThisValue _thisType -> () - | Const (_constValueObj, _constType) -> () - | Value (_valueToGet) -> () - | _ -> () - - and visitExprs f exprs = List.iter (visitExpr f) exprs - - and visitObjArg f objOpt = Option.iter (visitExpr f) objOpt - - and visitObjMember f memb = visitExpr f memb.Body - - let rec visitDeclaration f d = - match d with - | FSharpImplementationFileDeclaration.Entity (_e, subDecls) -> - for subDecl in subDecls do - visitDeclaration f subDecl - | FSharpImplementationFileDeclaration.MemberOrFunctionOrValue (_v, _vs, e) -> visitExpr f e - | FSharpImplementationFileDeclaration.InitAction (e) -> visitExpr f e - [] let jsonSerializerOptionsAnalyzer : Analyzer = fun ctx -> @@ -130,27 +31,31 @@ module JsonSerializerOptionsAnalyzer = "System.Text.Json.JsonSerializer.SerializeToUtf8Bytes" |] - let handler (range : range) (m : FSharpMemberOrFunctionOrValue) (args : FSharpExpr list) = - let name = String.Join (".", m.DeclaringEntity.Value.FullName, m.DisplayName) - - let containsSerOptsCtorCall = - args - |> List.exists ( - function - | NewObject (objType, _, _) when - objType.FullName = "System.Text.Json.JsonSerializerOptions" - && objType.Assembly.SimpleName = "System.Text.Json" - -> - true - | _ -> false - ) - - if - m.Assembly.SimpleName = "System.Text.Json" - && Array.contains name namesToWarnAbount - && containsSerOptsCtorCall - then - state.Add range + let handler : Handler = + let callHandler (range : range) (m : FSharpMemberOrFunctionOrValue) (args : FSharpExpr list) = + let name = String.Join (".", m.DeclaringEntity.Value.FullName, m.DisplayName) + let assemblyName = "System.Text.Json" + + let containsSerOptsCtorCall = + args + |> List.exists ( + function + | NewObject (objType, _, _) when + objType.FullName = "System.Text.Json.JsonSerializerOptions" + && objType.Assembly.SimpleName = assemblyName + -> + true + | _ -> false + ) + + if + m.Assembly.SimpleName = assemblyName + && Array.contains name namesToWarnAbount + && containsSerOptsCtorCall + then + state.Add range + + Handler.CallHandler callHandler match ctx.TypedTree with | None -> () diff --git a/src/FSharp.Analyzers/TASTCollection.fs b/src/FSharp.Analyzers/TASTCollection.fs new file mode 100644 index 0000000..637f063 --- /dev/null +++ b/src/FSharp.Analyzers/TASTCollection.fs @@ -0,0 +1,110 @@ +namespace ``G-Research``.FSharp.Analyzers + +module TASTCollection = + + open FSharp.Compiler.Symbols + open FSharp.Compiler.Text + open FSharp.Compiler.Symbols.FSharpExprPatterns + + type Handler = | CallHandler of (range -> FSharpMemberOrFunctionOrValue -> FSharpExpr list -> unit) + + let rec visitExpr (handler : Handler) (e : FSharpExpr) = + match e with + | AddressOf lvalueExpr -> visitExpr handler lvalueExpr + | AddressSet (lvalueExpr, rvalueExpr) -> + visitExpr handler lvalueExpr + visitExpr handler rvalueExpr + | Application (funcExpr, _typeArgs, argExprs) -> + visitExpr handler funcExpr + visitExprs handler argExprs + | Call (objExprOpt, memberOrFunc, _typeArgs1, _typeArgs2, argExprs) -> + match handler with + | CallHandler f -> f e.Range memberOrFunc argExprs + + visitObjArg handler objExprOpt + visitExprs handler argExprs + | Coerce (_targetType, inpExpr) -> visitExpr handler inpExpr + | FastIntegerForLoop (startExpr, limitExpr, consumeExpr, _isUp, _debugPointAtFor, _debugPointAtInOrTo) -> + visitExpr handler startExpr + visitExpr handler limitExpr + visitExpr handler consumeExpr + | ILAsm (_asmCode, _typeArgs, argExprs) -> visitExprs handler argExprs + | ILFieldGet (objExprOpt, _fieldType, _fieldName) -> visitObjArg handler objExprOpt + | ILFieldSet (objExprOpt, _fieldType, _fieldName, _valueExpr) -> visitObjArg handler objExprOpt + | IfThenElse (guardExpr, thenExpr, elseExpr) -> + visitExpr handler guardExpr + visitExpr handler thenExpr + visitExpr handler elseExpr + | Lambda (_lambdaVar, bodyExpr) -> visitExpr handler bodyExpr + | Let ((_bindingVar, bindingExpr, _debugPointAtBinding), bodyExpr) -> + visitExpr handler bindingExpr + visitExpr handler bodyExpr + | LetRec (recursiveBindings, bodyExpr) -> + let recursiveBindings' = + recursiveBindings |> List.map (fun (mfv, expr, _dp) -> (mfv, expr)) + + List.iter (snd >> visitExpr handler) recursiveBindings' + visitExpr handler bodyExpr + | NewArray (_arrayType, argExprs) -> visitExprs handler argExprs + | NewDelegate (_delegateType, delegateBodyExpr) -> visitExpr handler delegateBodyExpr + | NewObject (_objType, _typeArgs, argExprs) -> visitExprs handler argExprs + | NewRecord (_recordType, argExprs) -> visitExprs handler argExprs + | NewTuple (_tupleType, argExprs) -> visitExprs handler argExprs + | NewUnionCase (_unionType, _unionCase, argExprs) -> visitExprs handler argExprs + | Quote quotedExpr -> visitExpr handler quotedExpr + | FSharpFieldGet (objExprOpt, _recordOrClassType, _fieldInfo) -> visitObjArg handler objExprOpt + | FSharpFieldSet (objExprOpt, _recordOrClassType, _fieldInfo, argExpr) -> + visitObjArg handler objExprOpt + visitExpr handler argExpr + | Sequential (firstExpr, secondExpr) -> + visitExpr handler firstExpr + visitExpr handler secondExpr + | TryFinally (bodyExpr, finalizeExpr, _debugPointAtTry, _debugPointAtFinally) -> + visitExpr handler bodyExpr + visitExpr handler finalizeExpr + | TryWith (bodyExpr, _, _, _catchVar, catchExpr, _debugPointAtTry, _debugPointAtWith) -> + visitExpr handler bodyExpr + visitExpr handler catchExpr + | TupleGet (_tupleType, _tupleElemIndex, tupleExpr) -> visitExpr handler tupleExpr + | DecisionTree (decisionExpr, decisionTargets) -> + visitExpr handler decisionExpr + List.iter (snd >> visitExpr handler) decisionTargets + | DecisionTreeSuccess (_decisionTargetIdx, decisionTargetExprs) -> visitExprs handler decisionTargetExprs + | TypeLambda (_genericParam, bodyExpr) -> visitExpr handler bodyExpr + | TypeTest (_ty, inpExpr) -> visitExpr handler inpExpr + | UnionCaseSet (unionExpr, _unionType, _unionCase, _unionCaseField, valueExpr) -> + visitExpr handler unionExpr + visitExpr handler valueExpr + | UnionCaseGet (unionExpr, _unionType, _unionCase, _unionCaseField) -> visitExpr handler unionExpr + | UnionCaseTest (unionExpr, _unionType, _unionCase) -> visitExpr handler unionExpr + | UnionCaseTag (unionExpr, _unionType) -> visitExpr handler unionExpr + | ObjectExpr (_objType, baseCallExpr, overrides, interfaceImplementations) -> + visitExpr handler baseCallExpr + List.iter (visitObjMember handler) overrides + List.iter (snd >> List.iter (visitObjMember handler)) interfaceImplementations + | TraitCall (_sourceTypes, _traitName, _typeArgs, _typeInstantiation, _argTypes, argExprs) -> + visitExprs handler argExprs + | ValueSet (_valToSet, valueExpr) -> visitExpr handler valueExpr + | WhileLoop (guardExpr, bodyExpr, _debugPointAtWhile) -> + visitExpr handler guardExpr + visitExpr handler bodyExpr + | BaseValue _baseType -> () + | DefaultValue _defaultType -> () + | ThisValue _thisType -> () + | Const (_constValueObj, _constType) -> () + | Value _valueToGet -> () + | _ -> () + + and visitExprs f exprs = List.iter (visitExpr f) exprs + + and visitObjArg f objOpt = Option.iter (visitExpr f) objOpt + + and visitObjMember f memb = visitExpr f memb.Body + + let rec visitDeclaration f d = + match d with + | FSharpImplementationFileDeclaration.Entity (_e, subDecls) -> + for subDecl in subDecls do + visitDeclaration f subDecl + | FSharpImplementationFileDeclaration.MemberOrFunctionOrValue (_v, _vs, e) -> visitExpr f e + | FSharpImplementationFileDeclaration.InitAction e -> visitExpr f e From 6443a36b42bc876ef401352dff9a6d02c17c1171 Mon Sep 17 00:00:00 2001 From: dawe Date: Mon, 25 Sep 2023 15:05:23 +0200 Subject: [PATCH 8/9] use the set datatype for method names --- .../JsonSerializerOptionsAnalyzer.fs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs index 8e05ad1..63892af 100644 --- a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs +++ b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs @@ -19,17 +19,18 @@ module JsonSerializerOptionsAnalyzer = let state = ResizeArray () let namesToWarnAbount = - [| - "System.Text.Json.JsonSerializer.Deserialize" - "System.Text.Json.JsonSerializer.DeserializeAsync" - "System.Text.Json.JsonSerializer.DeserializeAsyncEnumerable" - "System.Text.Json.JsonSerializer.Serialize" - "System.Text.Json.JsonSerializer.SerializeAsync" - "System.Text.Json.JsonSerializer.SerializeToDocument" - "System.Text.Json.JsonSerializer.SerializeToElement" - "System.Text.Json.JsonSerializer.SerializeToNode" - "System.Text.Json.JsonSerializer.SerializeToUtf8Bytes" - |] + set + [ + "System.Text.Json.JsonSerializer.Deserialize" + "System.Text.Json.JsonSerializer.DeserializeAsync" + "System.Text.Json.JsonSerializer.DeserializeAsyncEnumerable" + "System.Text.Json.JsonSerializer.Serialize" + "System.Text.Json.JsonSerializer.SerializeAsync" + "System.Text.Json.JsonSerializer.SerializeToDocument" + "System.Text.Json.JsonSerializer.SerializeToElement" + "System.Text.Json.JsonSerializer.SerializeToNode" + "System.Text.Json.JsonSerializer.SerializeToUtf8Bytes" + ] let handler : Handler = let callHandler (range : range) (m : FSharpMemberOrFunctionOrValue) (args : FSharpExpr list) = @@ -50,7 +51,7 @@ module JsonSerializerOptionsAnalyzer = if m.Assembly.SimpleName = assemblyName - && Array.contains name namesToWarnAbount + && Set.contains name namesToWarnAbount && containsSerOptsCtorCall then state.Add range From e4e9434b76524b6928dd7bb233065d69820167ea Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 27 Sep 2023 10:58:06 +0200 Subject: [PATCH 9/9] use code with analyzer-specific namespace --- .../JsonSerializerOptionsAnalyzer.fs | 2 +- .../Deserialize call with ctor.fs.expected | 6 +++--- .../Deserialize calls with new ctor.fs.expected | 6 +++--- .../Serialize call with ctor.fs.expected | 12 ++++++------ .../Serialize calls with new ctor.fs.expected | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs index 63892af..2583da4 100644 --- a/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs +++ b/src/FSharp.Analyzers/JsonSerializerOptionsAnalyzer.fs @@ -10,7 +10,7 @@ open TASTCollection module JsonSerializerOptionsAnalyzer = [] - let Code = "GRA-002" + let Code = "GRA-JSONOPTS-001" [] let jsonSerializerOptionsAnalyzer : Analyzer = diff --git a/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected index df7d611..ec7df68 100644 --- a/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected +++ b/tests/data/jsonserializeroptions/Deserialize call with ctor.fs.expected @@ -1,3 +1,3 @@ -GRA-002 | Warning | (6,12 - 6,78) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (7,12 - 7,89) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (8,12 - 8,99) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (6,12 - 6,78) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (7,12 - 7,89) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (8,12 - 8,99) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected index b551075..ac9f895 100644 --- a/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected +++ b/tests/data/jsonserializeroptions/Deserialize calls with new ctor.fs.expected @@ -1,3 +1,3 @@ -GRA-002 | Warning | (6,12 - 6,82) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (7,12 - 7,93) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (8,12 - 8,103) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (6,12 - 6,82) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (7,12 - 7,93) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (8,12 - 8,103) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected b/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected index 6108800..1c9ae73 100644 --- a/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected +++ b/tests/data/jsonserializeroptions/Serialize call with ctor.fs.expected @@ -1,6 +1,6 @@ -GRA-002 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached. diff --git a/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected index 6108800..1c9ae73 100644 --- a/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected +++ b/tests/data/jsonserializeroptions/Serialize calls with new ctor.fs.expected @@ -1,6 +1,6 @@ -GRA-002 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. -GRA-002 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (6,12 - 6,80) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (7,12 - 7,97) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (8,12 - 8,90) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (9,12 - 9,89) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (10,12 - 10,86) | JsonSerializerOptions instances should be cached. +GRA-JSONOPTS-001 | Warning | (11,12 - 11,91) | JsonSerializerOptions instances should be cached.