Skip to content

Commit

Permalink
Update F# analyzers
Browse files Browse the repository at this point in the history
  • Loading branch information
nojaf committed Nov 23, 2023
1 parent eaabd18 commit 6c76456
Show file tree
Hide file tree
Showing 25 changed files with 221 additions and 189 deletions.
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Ionide.KeepAChangelog.Tasks" Version="0.1.8" />
<PackageVersion Include="FSharp.Analyzers.Build" Version="0.2.0" />
<PackageVersion Include="G-Research.FSharp.Analyzers" Version="0.3.1" />
<PackageVersion Include="Ionide.Analyzers" Version="0.4.0" />
<PackageVersion Include="G-Research.FSharp.Analyzers" Version="0.4.0" />
<PackageVersion Include="Ionide.Analyzers" Version="0.5.0" />
</ItemGroup>
</Project>
33 changes: 18 additions & 15 deletions src/FSharp.Formatting.ApiDocs/GenerateHtml.fs
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,10 @@ type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
h5 [ Class "fsdocs-example-header" ] [ !! "Example" ]

p [
Class "fsdocs-example"
if e.Id.IsSome then
Id e.Id.Value
yield Class "fsdocs-example"
match e.Id with
| None -> ()
| Some id -> yield Id id
] [ embed e ]
//if m.IsObsolete then
// obsoleteMessage m.ObsoleteMessage
Expand Down Expand Up @@ -610,13 +611,19 @@ type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
| _ -> () ]

let listOfNamespacesNav otherDocs (nsOpt: ApiDocNamespace option) =
let isTemplatingAvailable =
match menuTemplateFolder with
| None -> false
| Some input -> Menu.isTemplatingAvailable input
let noTemplatingFallback () =
listOfNamespacesNavAux otherDocs nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"

match menuTemplateFolder with
| None -> noTemplatingFallback ()
| Some menuTemplateFolder ->
let isTemplatingAvailable = Menu.isTemplatingAvailable menuTemplateFolder

if isTemplatingAvailable then
if otherDocs && model.Collection.CollectionName <> "FSharp.Core" then
if not isTemplatingAvailable then
noTemplatingFallback ()
else if otherDocs && model.Collection.CollectionName <> "FSharp.Core" then
let menuItems =
let title = "All Namespaces"
let link = model.IndexFileUrl(root, collectionName, qualify, model.FileExtensions.InUrl)
Expand All @@ -625,7 +632,7 @@ type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
Menu.MenuItem.Content = title
Menu.MenuItem.IsActive = true } ]

Menu.createMenu menuTemplateFolder.Value false "API Reference" menuItems
Menu.createMenu menuTemplateFolder false "API Reference" menuItems

else
let categorise = Categorise.model model
Expand All @@ -643,11 +650,7 @@ type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
Menu.MenuItem.Content = name
Menu.MenuItem.IsActive = false })

Menu.createMenu menuTemplateFolder.Value false "Namespaces" menuItems
else
listOfNamespacesNavAux otherDocs nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"
Menu.createMenu menuTemplateFolder false "Namespaces" menuItems

/// Get the substitutions relevant to all
member _.GlobalSubstitutions: Substitutions =
Expand Down
26 changes: 14 additions & 12 deletions src/FSharp.Formatting.ApiDocs/GenerateMarkdown.fs
Original file line number Diff line number Diff line change
Expand Up @@ -355,13 +355,19 @@ type MarkdownRender(model: ApiDocModel, ?menuTemplateFolder: string) =
| _ -> () ]

let listOfNamespaces otherDocs nav (nsOpt: ApiDocNamespace option) =
let isTemplatingAvailable =
match menuTemplateFolder with
| None -> false
| Some input -> Menu.isTemplatingAvailable input
let noTemplatingFallback () =
listOfNamespacesAux otherDocs nav nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"

match menuTemplateFolder with
| None -> noTemplatingFallback ()
| Some menuTemplateFolder ->
let isTemplatingAvailable = Menu.isTemplatingAvailable menuTemplateFolder

if isTemplatingAvailable then
if otherDocs && nav && model.Collection.CollectionName <> "FSharp.Core" then
if not isTemplatingAvailable then
noTemplatingFallback ()
else if otherDocs && nav && model.Collection.CollectionName <> "FSharp.Core" then
let menuItems =
let title = "All Namespaces"
let link = model.IndexFileUrl(root, collectionName, qualify, model.FileExtensions.InUrl)
Expand All @@ -370,7 +376,7 @@ type MarkdownRender(model: ApiDocModel, ?menuTemplateFolder: string) =
Menu.MenuItem.Content = title
Menu.MenuItem.IsActive = false } ]

Menu.createMenu menuTemplateFolder.Value false "API Reference" menuItems
Menu.createMenu menuTemplateFolder false "API Reference" menuItems

else
let categorise = Categorise.model model
Expand All @@ -388,11 +394,7 @@ type MarkdownRender(model: ApiDocModel, ?menuTemplateFolder: string) =
Menu.MenuItem.Content = name
Menu.MenuItem.IsActive = false })

Menu.createMenu menuTemplateFolder.Value false "Namespaces" menuItems
else
listOfNamespacesAux otherDocs nav nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"
Menu.createMenu menuTemplateFolder false "Namespaces" menuItems

/// Get the substitutions relevant to all
member _.GlobalSubstitutions: Substitutions =
Expand Down
77 changes: 46 additions & 31 deletions src/FSharp.Formatting.ApiDocs/GenerateModel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,10 @@ type ApiDocAttribute(name, fullName, constructorArguments, namedConstructorArgum
member x.ObsoleteMessage =
let tryFindObsoleteMessage =
x.ConstructorArguments
|> List.tryFind (fun x -> x :? string)
|> Option.map string
|> List.tryPick (fun x ->
match x with
| :? string as s -> Some s
| _ -> None)
|> Option.defaultValue ""

if x.IsObsoleteAttribute then tryFindObsoleteMessage else ""
Expand All @@ -186,8 +188,10 @@ type ApiDocAttribute(name, fullName, constructorArguments, namedConstructorArgum
member x.CustomOperationName =
let tryFindCustomOperation =
x.ConstructorArguments
|> List.tryFind (fun x -> x :? string)
|> Option.map string
|> List.tryPick (fun x ->
match x with
| :? string as s -> Some s
| _ -> None)
|> Option.defaultValue ""

if x.IsCustomOperationAttribute then
Expand Down Expand Up @@ -215,9 +219,9 @@ type ApiDocAttribute(name, fullName, constructorArguments, namedConstructorArgum
let rec formatValue (v: obj) =
match v with
| :? string as s -> sprintf "\"%s\"" s
| :? array<obj> as a -> a |> Seq.map formatValue |> join "; " |> sprintf "[|%s|]"
| :? (obj array) as a -> a |> Seq.map formatValue |> join "; " |> sprintf "[|%s|]"
| :? bool as b -> if b then "true" else "false"
| _ -> string v
| _ -> string<obj> v

let formatedConstructorArguments = x.ConstructorArguments |> Seq.map formatValue |> join ", "

Expand All @@ -239,7 +243,7 @@ type ApiDocAttribute(name, fullName, constructorArguments, namedConstructorArgum
|> append formatedNamedConstructorArguments
|> appendIfTrue needsBraces ")"
|> append ">]"
|> string
|> string<StringBuilder>

/// Formats the attribute using the Name. Removes the "Attribute"-suffix. E.g Obsolete
member x.Format() = x.Format(x.Name, true)
Expand All @@ -254,14 +258,14 @@ type ApiDocAttribute(name, fullName, constructorArguments, namedConstructorArgum
member x.FormatFullNameLongForm() = x.Format(x.FullName, false)

/// Tries to find the System.ObsoleteAttribute and return its obsolete message
static member internal TryGetObsoleteMessage(attributes: seq<ApiDocAttribute>) =
static member internal TryGetObsoleteMessage(attributes: ApiDocAttribute seq) =
attributes
|> Seq.tryFind (fun a -> a.IsObsoleteAttribute)
|> Option.map (fun a -> a.ObsoleteMessage)
|> Option.defaultValue ""

/// Tries to find the CustomOperationAttribute and return its obsolete message
static member internal TryGetCustomOperationName(attributes: seq<ApiDocAttribute>) =
static member internal TryGetCustomOperationName(attributes: ApiDocAttribute seq) =
attributes
|> Seq.tryFind (fun a -> a.IsCustomOperationAttribute)
|> Option.map (fun a -> a.CustomOperationName)
Expand Down Expand Up @@ -715,8 +719,11 @@ module internal CrossReferences =
let name = memb.CompiledName.Replace(".ctor", "#ctor")

let typeGenericParameters =
memb.DeclaringEntity.Value.GenericParameters
|> Seq.mapi (fun num par -> par.Name, sprintf "`%d" num)
match memb.DeclaringEntity with
| None -> Seq.empty
| Some declaringEntity ->
declaringEntity.GenericParameters
|> Seq.mapi (fun num par -> par.Name, sprintf "`%d" num)

let methodGenericParameters =
memb.GenericParameters |> Seq.mapi (fun num par -> par.Name, sprintf "``%d" num)
Expand Down Expand Up @@ -758,9 +765,12 @@ module internal CrossReferences =
Log.verbf "Full Exception details of previous message: %O" exn
memb.CompiledName

match (memb.DeclaringEntity.Value.TryFullName) with
match
memb.DeclaringEntity
|> Option.bind (fun declaringEntity -> declaringEntity.TryFullName)
with
| None -> ""
| Some(n) -> sprintf "%s:%s.%s" (getMemberXmlDocsSigPrefix memb) n memberName
| Some fullName -> sprintf "%s:%s.%s" (getMemberXmlDocsSigPrefix memb) fullName memberName

type internal CrefReference =
{ IsInternal: bool
Expand Down Expand Up @@ -1004,11 +1014,14 @@ type internal CrossReferenceResolver(root, collectionName, qualify, extensions)
externalDocsLink false simple typeName typeName

let mfvToCref (mfv: FSharpMemberOrFunctionOrValue) =
let entityUrlBaseName = getUrlBaseNameForRegisteredEntity mfv.DeclaringEntity.Value
match mfv.DeclaringEntity with
| None -> failwith $"%s{mfv.DisplayName} does not have a DeclaringEntity"
| Some declaringEntity ->
let entityUrlBaseName = getUrlBaseNameForRegisteredEntity declaringEntity

{ IsInternal = true
ReferenceLink = internalCrossReferenceForMember entityUrlBaseName mfv
NiceName = mfv.DeclaringEntity.Value.DisplayName + "." + mfv.DisplayName }
{ IsInternal = true
ReferenceLink = internalCrossReferenceForMember entityUrlBaseName mfv
NiceName = declaringEntity.DisplayName + "." + mfv.DisplayName }

let tryResolveCrossReferenceForMemberByXmlSig (memberXmlSig: string) =
assert
Expand Down Expand Up @@ -1225,7 +1238,7 @@ module internal TypeFormatter =
let formatArgNameAndTypePair i (argName, argType) =
let argName =
match argName with
| None -> if isUnitType argType then "()" else "arg" + string i
| None -> if isUnitType argType then "()" else "arg" + string<int> i
| Some nm -> nm

argName, argType
Expand Down Expand Up @@ -1356,7 +1369,7 @@ module internal SymbolReader =

ApiDocAttribute(name, fullName, constructorArguments, namedArguments)

let readAttributes (attributes: seq<FSharpAttribute>) =
let readAttributes (attributes: FSharpAttribute seq) =
attributes |> Seq.map readAttribute |> Seq.toList

let readMemberOrVal (ctx: ReadingContext) (v: FSharpMemberOrFunctionOrValue) =
Expand All @@ -1374,8 +1387,10 @@ module internal SymbolReader =
| Some v ->
v.ConstructorArguments
|> Seq.map snd
|> Seq.tryFind (fun x -> x :? string)
|> Option.map string
|> Seq.tryPick (fun x ->
match x with
| :? string as s -> Some s
| _ -> None)

// This module doesn't have RequireQualifiedAccessAttribute and anyway we want the name to show
// usage of its members as Array.Parallel.map
Expand Down Expand Up @@ -1963,7 +1978,7 @@ module internal SymbolReader =
let html = new StringBuilder()

for (id, e) in List.indexed summaries do
let n = if id = 0 then "summary" else "summary-" + string id
let n = if id = 0 then "summary" else "summary-" + string<int> id

rawData.[n] <- e.Value
readXmlElementAsHtml true urlMap cmds html e
Expand Down Expand Up @@ -2004,7 +2019,7 @@ module internal SymbolReader =
let html = new StringBuilder()

for (id, e) in List.indexed remarkNodes do
let n = if id = 0 then "remarks" else "remarks-" + string id
let n = if id = 0 then "remarks" else "remarks-" + string<int> id

rawData.[n] <- e.Value
readXmlElementAsHtml true urlMap cmds html e
Expand All @@ -2020,7 +2035,7 @@ module internal SymbolReader =

if returnNodes.Length > 0 then
for (id, e) in List.indexed returnNodes do
let n = if id = 0 then "returns" else "returns-" + string id
let n = if id = 0 then "returns" else "returns-" + string<int> id

rawData.[n] <- e.Value
readXmlElementAsHtml true urlMap cmds html e
Expand Down Expand Up @@ -2069,7 +2084,7 @@ module internal SymbolReader =

let exampleId =
match e.TryAttr "id" with
| None -> if id = 0 then "example" else "example-" + string id
| None -> if id = 0 then "example" else "example-" + string<int> id
| Some attrId -> attrId

rawData.[exampleId] <- e.Value
Expand All @@ -2082,7 +2097,7 @@ module internal SymbolReader =
[ for (id, e) in List.indexed noteNodes do
let html = new StringBuilder()

let n = if id = 0 then "note" else "note-" + string id
let n = if id = 0 then "note" else "note-" + string<int> id

rawData.[n] <- e.Value
readXmlElementAsHtml true urlMap cmds html e
Expand All @@ -2106,7 +2121,7 @@ module internal SymbolReader =

match lst with
| [ x ] -> rawData.[n] <- x.Value
| lst -> lst |> List.iteri (fun id el -> rawData.[n + "-" + string id] <- el.Value))
| lst -> lst |> List.iteri (fun id el -> rawData.[n + "-" + string<int> id] <- el.Value))

let rawData = rawData |> Seq.toList

Expand Down Expand Up @@ -2400,7 +2415,7 @@ module internal SymbolReader =
|> function
| (results, nspDocs) -> (results, combineNamespaceDocs nspDocs)

let readChildren ctx (entities: seq<FSharpEntity>) reader cond =
let readChildren ctx (entities: FSharpEntity seq) reader cond =
entities
|> Seq.filter (fun v -> checkAccess ctx v.Accessibility)
|> Seq.filter cond
Expand All @@ -2427,7 +2442,7 @@ module internal SymbolReader =
ctx.WarnOnMissingDocs
))

let readAllMembers ctx entityUrl kind (members: seq<FSharpMemberOrFunctionOrValue>) =
let readAllMembers ctx entityUrl kind (members: FSharpMemberOrFunctionOrValue seq) =
members
|> Seq.filter (fun v -> checkAccess ctx v.Accessibility)
|> Seq.filter (fun v ->
Expand Down Expand Up @@ -2755,7 +2770,7 @@ module internal SymbolReader =
ctx.Substitutions
))

and readEntities ctx (entities: seq<_>) =
and readEntities ctx (entities: _ seq) =
let modifiers, nsdocs1 = readChildren ctx entities readModule (fun x -> x.IsFSharpModule)

let typs, nsdocs2 = readChildren ctx entities readType (fun x -> not x.IsFSharpModule)
Expand All @@ -2774,7 +2789,7 @@ module internal SymbolReader =
else
str

let readNamespace ctx (ns, entities: seq<FSharpEntity>) =
let readNamespace ctx (ns, entities: FSharpEntity seq) =
let entities, nsdocs = readEntities ctx entities
ApiDocNamespace(stripMicrosoft ns, entities, ctx.Substitutions, nsdocs)

Expand Down
2 changes: 1 addition & 1 deletion src/FSharp.Formatting.CodeFormat/Pervasive.fs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type AsyncMaybeBuilder() =
x.Zero()

[<DebuggerStepThrough>]
member x.For(sequence: seq<_>, body: 'T -> Async<unit option>) : Async<_ option> =
member x.For(sequence: _ seq, body: 'T -> Async<unit option>) : Async<_ option> =
x.Using(sequence.GetEnumerator(), (fun enum -> x.While(enum.MoveNext, x.Delay(fun () -> body enum.Current))))

[<DebuggerStepThrough>]
Expand Down
2 changes: 1 addition & 1 deletion src/FSharp.Formatting.CodeFormat/SourceCode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ open FSharp.Formatting.CodeFormat.Constants
// --------------------------------------------------------------------------------------

/// A tool tip consists of a list of items reported from the compiler
type ToolTipSpans = list<ToolTipSpan>
type ToolTipSpans = ToolTipSpan list

/// A tool tip span can be emphasized text, plain text Literal or a line brak
type ToolTipSpan =
Expand Down
4 changes: 2 additions & 2 deletions src/FSharp.Formatting.CodeFormat/ToolTipReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ let linesFromTaggedText (tags: TaggedText array) =

for tag in tags do
if tag.Tag = TextTag.Space && tag.Text.Contains "\n" then
yield string content
yield string<StringBuilder> content
content.Clear() |> ignore
else
content.Append tag.Text |> ignore
// yield any remaining text
if content.Length <> 0 then
yield string content
yield string<StringBuilder> content
}

/// Turn string into a sequence of lines interleaved with line breaks
Expand Down
Loading

0 comments on commit 6c76456

Please sign in to comment.