Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/fsharp/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ module private TastDefinitionPrinting =

let nameL = eventTag |> wordL
let typL = layoutType denv (e.GetDelegateType(amap, m))
staticL ^^ WordL.keywordEvent ^^ nameL ^^ WordL.colon ^^ typL
staticL ^^ WordL.keywordMember ^^ nameL ^^ WordL.colon ^^ typL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find


let private layoutPropInfo denv amap m (p: PropInfo) =
match p.ArbitraryValRef with
Expand Down Expand Up @@ -1783,6 +1783,17 @@ module private TastDefinitionPrinting =
let xs = List.map (layoutTycon denv infoReader ad m false (wordL (tagKeyword "and"))) t
aboveListL (x :: xs)

let layoutEntity (denv: DisplayEnv) (infoReader: InfoReader) ad m (entity: Entity) =
if entity.IsModule then
// TODO: Implementation of layoutTycon isn't correct for module.
layoutTycon denv infoReader ad m false (wordL (tagKeyword "module")) entity
elif entity.IsNamespace then
emptyL
elif entity.IsExceptionDecl then
layoutExnDefn denv entity
else
layoutTycon denv infoReader ad m true WordL.keywordType entity

//--------------------------------------------------------------------------

module private InferredSigPrinting =
Expand Down Expand Up @@ -1976,6 +1987,8 @@ let stringOfTyparConstraints denv x = x |> PrintTypes.layoutConstraintsWithInfo

let layoutTycon denv infoReader ad m (* width *) x = TastDefinitionPrinting.layoutTycon denv infoReader ad m true WordL.keywordType x (* |> Display.squashTo width *)

let layoutEntity denv infoReader ad m x = TastDefinitionPrinting.layoutEntity denv infoReader ad m x

let layoutUnionCases denv x = x |> TastDefinitionPrinting.layoutUnionCaseFields denv true

/// Pass negative number as pos in case of single cased discriminated unions
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/NicePrint.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ val stringOfTyparConstraints: denv:DisplayEnv -> x:(Typar * TyparConstraint) lis

val layoutTycon: denv:DisplayEnv -> infoReader:InfoReader -> ad:AccessorDomain -> m:range -> x:Tycon -> Layout

val layoutEntity: denv:DisplayEnv -> infoReader:InfoReader -> ad:AccessorDomain -> m:range -> x:Entity -> Layout

val layoutUnionCases: denv:DisplayEnv -> x:RecdField list -> Layout

val isGeneratedUnionCaseField: pos:int -> f:RecdField -> bool
Expand Down
104 changes: 104 additions & 0 deletions src/fsharp/symbols/Symbols.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.Syntax.PrettyNaming
open FSharp.Compiler.AbstractIL

type FSharpAccessibility(a:Accessibility, ?isProtected) =
let isProtected = defaultArg isProtected false
Expand Down Expand Up @@ -806,6 +808,108 @@ type FSharpEntity(cenv: SymbolEnv, entity:EntityRef) =
member x.TryGetMembersFunctionsAndValues() =
try x.MembersFunctionsAndValues with _ -> [||] :> _

member this.TryGetMetadataText() =
match entity.TryDeref with
| ValueSome entity ->
if entity.IsNamespace then None
else

let denv = DisplayEnv.Empty cenv.g
let denv =
{ denv with
showImperativeTyparAnnotations=true
showHiddenMembers=true
showObsoleteMembers=true
showAttributes=true
shrinkOverloads=false
printVerboseSignatures=false }

let extraOpenPath =
match entity.CompilationPathOpt with
| Some cpath ->
let rec getOpenPath accessPath acc =
match accessPath with
| [] -> acc
| (name, ModuleOrNamespaceKind.ModuleOrType) :: accessPath ->
getOpenPath accessPath (name :: acc)
| (name, ModuleOrNamespaceKind.Namespace) :: accessPath ->
getOpenPath accessPath (name :: acc)
| (name, ModuleOrNamespaceKind.FSharpModuleWithSuffix) :: accessPath ->
getOpenPath accessPath (name :: acc)

getOpenPath cpath.AccessPath []
| _ ->
[]
|> List.rev

let needOpenType =
match entity.CompilationPathOpt with
| Some cpath ->
match cpath.AccessPath with
| (_, ModuleOrNamespaceKind.ModuleOrType) :: _ ->
match this.DeclaringEntity with
| Some (declaringEntity: FSharpEntity) -> not declaringEntity.IsFSharpModule
| _ -> false
| _ -> false
| _ ->
false

let denv =
denv.SetOpenPaths
([ FSharpLib.RootPath
FSharpLib.CorePath
FSharpLib.CollectionsPath
FSharpLib.ControlPath
(IL.splitNamespace FSharpLib.ExtraTopLevelOperatorsName)
extraOpenPath
])

let infoReader = cenv.infoReader

let openPathL =
extraOpenPath
|> List.map (fun x -> Layout.wordL (TaggedText.tagUnknownEntity x))

let pathL =
if List.isEmpty extraOpenPath then
Layout.emptyL
else
Layout.sepListL (Layout.sepL TaggedText.dot) openPathL

let headerL =
if List.isEmpty extraOpenPath then
Layout.emptyL
else
Layout.(^^)
(Layout.wordL (TaggedText.tagKeyword "namespace"))
pathL

let openL =
if List.isEmpty openPathL then Layout.emptyL
else
let openKeywordL =
if needOpenType then
Layout.(^^)
(Layout.wordL (TaggedText.tagKeyword "open"))
(Layout.wordL TaggedText.keywordType)
else
Layout.wordL (TaggedText.tagKeyword "open")
Layout.(^^)
openKeywordL
pathL

Layout.aboveListL
[
(Layout.(^^) headerL (Layout.sepL TaggedText.lineBreak))
(Layout.(^^) openL (Layout.sepL TaggedText.lineBreak))
(NicePrint.layoutEntity denv infoReader AccessibleFromSomewhere range0 entity)
]
|> LayoutRender.showL
|> SourceText.ofString
|> Some
| _ ->
None

override x.Equals(other: obj) =
box x === other ||
match other with
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/symbols/Symbols.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ type FSharpEntity =
/// Safe version of `GetMembersFunctionsAndValues`.
member TryGetMembersFunctionsAndValues: unit -> IList<FSharpMemberOrFunctionOrValue>

/// Get the source text of the entity's signature to be used as metadata.
member TryGetMetadataText: unit -> ISourceText option

/// Represents a delegate signature in an F# symbol
[<Class>]
type FSharpDelegateSignature =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1494,11 +1494,11 @@ FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: FSharp.Compiler.Syntax.Pars
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: FSharp.Compiler.Syntax.ParsedInput get_ParseTree()
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.ParameterLocations] FindParameterLocations(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfExprInYieldOrReturn(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfExpressionBeingDereferencedContainingPos(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfFunctionOrMethodBeingApplied(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfNameOfNearestOuterBindingContainingPos(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfRecordExpressionContainingPos(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfRefCellDereferenceContainingPos(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] TryRangeOfExpressionBeingDereferencedContainingPos(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] ValidateBreakpointLocation(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.Range]] GetAllArgumentsForFunctionApplicationAtPostion(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[FSharp.Compiler.Syntax.Ident,System.Int32]] TryIdentOfPipelineContainingPosAndNumArgsApplied(FSharp.Compiler.Text.Position)
Expand Down Expand Up @@ -3821,6 +3821,7 @@ FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[FShar
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpEntity] get_DeclaringEntity()
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpType] BaseType
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Symbols.FSharpType] get_BaseType()
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.ISourceText] TryGetMetadataText()
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[System.String] Namespace
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[System.String] TryFullName
FSharp.Compiler.Symbols.FSharpEntity: Microsoft.FSharp.Core.FSharpOption`1[System.String] TryGetFullCompiledName()
Expand Down
4 changes: 4 additions & 0 deletions vsintegration/src/FSharp.Editor/Common/Constants.fs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ module internal FSharpConstants =
/// "F# Miscellaneous Files"
let FSharpMiscellaneousFilesName = "F# Miscellaneous Files"

[<Literal>]
/// "F# Metadata"
let FSharpMetadataName = "F# Metadata"

[<RequireQualifiedAccess>]
module internal FSharpProviderConstants =

Expand Down
10 changes: 10 additions & 0 deletions vsintegration/src/FSharp.Editor/Common/Extensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ open FSharp.Compiler.EditorServices
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text

open Microsoft.VisualStudio.FSharp.Editor

type private FSharpGlyph = FSharp.Compiler.EditorServices.FSharpGlyph
type private FSharpRoslynGlyph = Microsoft.CodeAnalysis.ExternalAccess.FSharp.FSharpGlyph

Expand All @@ -36,6 +38,11 @@ type ProjectId with
member this.ToFSharpProjectIdString() =
this.Id.ToString("D").ToLowerInvariant()

type Project with
member this.IsFSharpMiscellaneous = this.Name = FSharpConstants.FSharpMiscellaneousFilesName
member this.IsFSharpMetadata = this.Name.StartsWith(FSharpConstants.FSharpMetadataName)
member this.IsFSharpMiscellaneousOrMetadata = this.IsFSharpMiscellaneous || this.IsFSharpMetadata

type Document with
member this.TryGetLanguageService<'T when 'T :> ILanguageService>() =
match this.Project with
Expand All @@ -47,6 +54,9 @@ type Document with
languageServices.GetService<'T>()
|> Some

member this.IsFSharpScript =
isScriptFile this.FilePath

module private SourceText =

open System.Runtime.CompilerServices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ type internal FSharpDocumentDiagnosticAnalyzer
interface IFSharpDocumentDiagnosticAnalyzer with

member this.AnalyzeSyntaxAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
if document.Project.IsFSharpMetadata then Task.FromResult(ImmutableArray.Empty)
else

asyncMaybe {
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
return!
Expand All @@ -125,14 +128,14 @@ type internal FSharpDocumentDiagnosticAnalyzer
|> RoslynHelpers.StartAsyncAsTask cancellationToken

member this.AnalyzeSemanticsAsync(document: Document, cancellationToken: CancellationToken): Task<ImmutableArray<Diagnostic>> =
if document.Project.IsFSharpMiscellaneousOrMetadata && not document.IsFSharpScript then Task.FromResult(ImmutableArray.Empty)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically here we would move this into the computation expression and say

do! (not document.Project.IsFSharpMiscellaneousOrMetadata || document.IsFSharpScript)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asyncMaybe doesn't support a bind operation for just bool, though we could add it.

I would also find it confusing for it to be used in that way. A simple if/then is very clear comparatively.

asyncMaybe itself is a good abstraction so you don't have to constantly keep handling the None case, but that's all that it should do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, it's do! Option.guard expr where expr is a bool-returning thing. This is the canonical way that invariants are held in this layer of the tools. I'll submit a separate PR for this, since we should be consistent

else

asyncMaybe {
let! parsingOptions, _, projectOptions = projectInfoManager.TryGetOptionsForDocumentOrProject(document, cancellationToken, userOpName)
if document.Project.Name <> FSharpConstants.FSharpMiscellaneousFilesName || isScriptFile document.FilePath then
return!
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic)
|> liftAsync
else
return ImmutableArray<Diagnostic>.Empty
return!
FSharpDocumentDiagnosticAnalyzer.GetDiagnostics(checkerProvider.Checker, document, parsingOptions, projectOptions, DiagnosticsType.Semantic)
|> liftAsync
}
|> Async.map (Option.defaultValue ImmutableArray<Diagnostic>.Empty)
|> RoslynHelpers.StartAsyncAsTask cancellationToken
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type internal SimplifyNameDiagnosticAnalyzer
interface IFSharpSimplifyNameDiagnosticAnalyzer with

member _.AnalyzeSemanticsAsync(descriptor, document: Document, cancellationToken: CancellationToken) =
if document.Project.IsFSharpMiscellaneousOrMetadata && not document.IsFSharpScript then Tasks.Task.FromResult(ImmutableArray.Empty)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically here we would move this into the computation expression and say

do! (not document.Project.IsFSharpMiscellaneousOrMetadata || document.IsFSharpScript)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, this should be Option.guard (...)

else

asyncMaybe {
do! Option.guard document.FSharpOptions.CodeFixes.SimplifyName
do Trace.TraceInformation("{0:n3} (start) SimplifyName", DateTime.Now.TimeOfDay.TotalSeconds)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type internal UnusedDeclarationsAnalyzer
interface IFSharpUnusedDeclarationsDiagnosticAnalyzer with

member _.AnalyzeSemanticsAsync(descriptor, document, cancellationToken) =
if document.Project.IsFSharpMiscellaneousOrMetadata && not document.IsFSharpScript then Threading.Tasks.Task.FromResult(ImmutableArray.Empty)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically here we would move this into the computation expression and say

do! (not document.Project.IsFSharpMiscellaneousOrMetadata || document.IsFSharpScript)

else

asyncMaybe {
do! Option.guard document.FSharpOptions.CodeFixes.UnusedDeclarations

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type internal UnusedOpensDiagnosticAnalyzer
interface IFSharpUnusedOpensDiagnosticAnalyzer with

member _.AnalyzeSemanticsAsync(descriptor, document: Document, cancellationToken: CancellationToken) =
if document.Project.IsFSharpMiscellaneousOrMetadata && not document.IsFSharpScript then Tasks.Task.FromResult(ImmutableArray.Empty)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically here we would move this into the computation expression and say

do! (not document.Project.IsFSharpMiscellaneousOrMetadata || document.IsFSharpScript)

else

asyncMaybe {
do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds)
let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
Expand Down
2 changes: 1 addition & 1 deletion vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
<Compile Include="Common\Logger.fsi" />
<Compile Include="Common\Logger.fs" />
<Compile Include="Common\Pervasive.fs" />
<Compile Include="Common\Extensions.fs" />
<Compile Include="Common\Constants.fs" />
<Compile Include="Common\Extensions.fs" />
<Compile Include="Common\Error.fs" />
<Compile Include="Common\Logging.fs" />
<Compile Include="Common\RoslynHelpers.fs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ open Microsoft.CodeAnalysis
open Microsoft.VisualStudio
open Microsoft.VisualStudio.FSharp.Editor
open Microsoft.VisualStudio.LanguageServices
open Microsoft.VisualStudio.LanguageServices.ProjectSystem
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics

#nowarn "9" // NativePtr.toNativeInt
Expand All @@ -23,10 +24,11 @@ type internal FSharpCheckerProvider
(
analyzerService: IFSharpDiagnosticAnalyzerService,
[<Import(typeof<VisualStudioWorkspace>)>] workspace: VisualStudioWorkspace,
projectContextFactory: IWorkspaceProjectContextFactory,
settings: EditorOptions
) =

let metadataAsSource = FSharpMetadataAsSourceService()
let metadataAsSource = FSharpMetadataAsSourceService(projectContextFactory)

let tryGetMetadataSnapshot (path, timeStamp) =
try
Expand Down
Loading