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
2 changes: 1 addition & 1 deletion VisualFSharp.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26009.0
VisualStudioVersion = 15.0.26014.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler", "src\fsharp\FSharp.Compiler\FSharp.Compiler.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}"
EndProject
Expand Down
42 changes: 21 additions & 21 deletions src/fsharp/vs/ServiceAssemblyContent.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ open Microsoft.FSharp.Compiler.Range

type internal ShortIdent = string
type Idents = ShortIdent[]
type MaybeUnresolvedIdent = { Ident: ShortIdent; Resolved: bool }
type MaybeUnresolvedIdents = MaybeUnresolvedIdent[]
type IsAutoOpen = bool

[<AutoOpen>]
Expand Down Expand Up @@ -458,15 +460,18 @@ module internal Entity =
| _ -> candidateNs.Length
candidateNs.[0..nsCount - 1]

let tryCreate (targetNamespace: Idents option, targetScope: Idents, partiallyQualifiedName: Idents,
requiresQualifiedAccessParent: Idents option, autoOpenParent: Idents option,
candidateNamespace: Idents option, candidate: Idents) =
let tryCreate (targetNamespace: Idents option, targetScope: Idents, partiallyQualifiedName: MaybeUnresolvedIdents,
requiresQualifiedAccessParent: Idents option, autoOpenParent: Idents option, candidateNamespace: Idents option, candidate: Idents) =
match candidate with
| [||] -> [||]
| _ ->
partiallyQualifiedName
|> Array.heads
|> Array.choose (fun parts ->
// the last part must be unresolved, otherwise we show false positive suggestions like
// "open System" for `let _ = System.DateTime.Naaaw`. Here only "Naaw" is unresolved.
|> Array.filter (fun x -> not (x.[x.Length - 1].Resolved))
|> Array.choose (fun parts ->
let parts = parts |> Array.map (fun x -> x.Ident)
if not (candidate |> Array.endsWith parts) then None
else
let identCount = parts.Length
Expand Down Expand Up @@ -547,29 +552,25 @@ module internal ParsedInput =
| SynConstructorArgs.Pats ps -> ps
| SynConstructorArgs.NamePatPairs(xs, _) -> List.map snd xs

let internal longIdentToArray (longIdent: LongIdent): Idents =
longIdent |> Seq.map string |> Seq.toArray

/// Returns all Idents and LongIdents found in an untyped AST.
let internal getLongIdents (input: ParsedInput option) : IDictionary<Range.pos, Idents> =
let identsByEndPos = Dictionary<Range.pos, Idents>()
/// Returns all `Ident`s and `LongIdent`s found in an untyped AST.
let internal getLongIdents (input: ParsedInput option) : IDictionary<Range.pos, LongIdent> =
let identsByEndPos = Dictionary<Range.pos, LongIdent>()

let addLongIdent (longIdent: LongIdent) =
let idents = longIdentToArray longIdent
for ident in longIdent do
identsByEndPos.[ident.idRange.End] <- idents
identsByEndPos.[ident.idRange.End] <- longIdent

let addLongIdentWithDots (LongIdentWithDots (longIdent, lids) as value) =
match longIdentToArray longIdent with
| [||] -> ()
| [|_|] as idents -> identsByEndPos.[value.Range.End] <- idents
match longIdent with
| [] -> ()
| [_] as idents -> identsByEndPos.[value.Range.End] <- idents
| idents ->
for dotRange in lids do
identsByEndPos.[Range.mkPos dotRange.EndLine (dotRange.EndColumn - 1)] <- idents
identsByEndPos.[value.Range.End] <- idents

let addIdent (ident: Ident) =
identsByEndPos.[ident.idRange.End] <- [|ident.idText|]
identsByEndPos.[ident.idRange.End] <- [ident]

let rec walkImplFileInput (ParsedImplFileInput(_, _, _, _, _, moduleOrNamespaceList, _)) =
List.iter walkSynModuleOrNamespace moduleOrNamespaceList
Expand Down Expand Up @@ -886,7 +887,7 @@ module internal ParsedInput =
walkImplFileInput input
| _ -> ()
//debug "%A" idents
identsByEndPos :> _
upcast identsByEndPos

let getLongIdentAt ast pos =
let idents = getLongIdents (Some ast)
Expand Down Expand Up @@ -1003,13 +1004,12 @@ module internal ParsedInput =
|> Seq.sortBy (fun (m, _, _) -> -m.Length)
|> Seq.toList

fun (partiallyQualifiedName: Idents) (requiresQualifiedAccessParent: Idents option, autoOpenParent: Idents option,
entityNamespace: Idents option, entity: Idents) ->
fun (partiallyQualifiedName: MaybeUnresolvedIdents)
(requiresQualifiedAccessParent: Idents option, autoOpenParent: Idents option, entityNamespace: Idents option, entity: Idents) ->
match res with
| None -> [||]
| Some (scope, ns, pos) ->
Entity.tryCreate(ns, scope.Idents, partiallyQualifiedName, requiresQualifiedAccessParent,
autoOpenParent, entityNamespace, entity)
Entity.tryCreate(ns, scope.Idents, partiallyQualifiedName, requiresQualifiedAccessParent, autoOpenParent, entityNamespace, entity)
|> Array.map (fun e ->
e,
match modules |> List.filter (fun (m, _, _) -> entity |> Array.startsWith m ) with
Expand Down
66 changes: 38 additions & 28 deletions vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -178,34 +178,44 @@ type internal FSharpAddOpenCodeFixProvider
| None, _
| _, FSharpCheckFileAnswer.Aborted -> ()
| Some parsedInput, FSharpCheckFileAnswer.Succeeded checkFileResults ->
let textLinePos = sourceText.Lines.GetLinePosition context.Span.Start
let defines = CompilerEnvironment.GetCompilationDefinesForEditing(context.Document.FilePath, options.OtherOptions |> Seq.toList)
let symbol = CommonHelpers.getSymbolAtPosition(context.Document.Id, sourceText, context.Span.Start, context.Document.FilePath, defines, SymbolLookupKind.Fuzzy)
match symbol with
| Some symbol ->
let pos = Pos.fromZ textLinePos.Line textLinePos.Character
let isAttribute = UntypedParseImpl.GetEntityKind(pos, parsedInput) = Some EntityKind.Attribute
let entities =
assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies checkFileResults
|> List.map (fun e ->
[ yield e.TopRequireQualifiedAccessParent, e.AutoOpenParent, e.Namespace, e.CleanedIdents
if isAttribute then
let lastIdent = e.CleanedIdents.[e.CleanedIdents.Length - 1]
if lastIdent.EndsWith "Attribute" && e.Kind LookupType.Precise = EntityKind.Attribute then
yield
e.TopRequireQualifiedAccessParent,
e.AutoOpenParent,
e.Namespace,
e.CleanedIdents
|> Array.replace (e.CleanedIdents.Length - 1) (lastIdent.Substring(0, lastIdent.Length - 9)) ])
|> List.concat

let idents = ParsedInput.getLongIdentAt parsedInput (Range.mkPos pos.Line symbol.RightColumn)
match idents with
| Some idents ->
let createEntity = ParsedInput.tryFindInsertionContext pos.Line parsedInput idents
return entities |> Seq.map createEntity |> Seq.concat |> Seq.toList |> getSuggestions context
| None -> ()
let unresolvedIdentRange =
let startLinePos = sourceText.Lines.GetLinePosition context.Span.Start
let startPos = Pos.fromZ startLinePos.Line startLinePos.Character
let endLinePos = sourceText.Lines.GetLinePosition context.Span.End
let endPos = Pos.fromZ endLinePos.Line endLinePos.Character
Range.mkRange context.Document.FilePath startPos endPos

let isAttribute = UntypedParseImpl.GetEntityKind(unresolvedIdentRange.Start, parsedInput) = Some EntityKind.Attribute

let entities =
assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies checkFileResults
|> List.collect (fun e ->
[ yield e.TopRequireQualifiedAccessParent, e.AutoOpenParent, e.Namespace, e.CleanedIdents
if isAttribute then
let lastIdent = e.CleanedIdents.[e.CleanedIdents.Length - 1]
if lastIdent.EndsWith "Attribute" && e.Kind LookupType.Precise = EntityKind.Attribute then
yield
e.TopRequireQualifiedAccessParent,
e.AutoOpenParent,
e.Namespace,
e.CleanedIdents
|> Array.replace (e.CleanedIdents.Length - 1) (lastIdent.Substring(0, lastIdent.Length - 9)) ])

let longIdent = ParsedInput.getLongIdentAt parsedInput unresolvedIdentRange.End

let maybeUnresolvedIdents =
longIdent
|> Option.map (fun longIdent ->
longIdent
|> List.map (fun ident ->
{ Ident = ident.idText
Resolved = not (ident.idRange = unresolvedIdentRange) })
|> List.toArray)

match maybeUnresolvedIdents with
| Some maybeUnresolvedIdents ->
let createEntity = ParsedInput.tryFindInsertionContext unresolvedIdentRange.StartLine parsedInput maybeUnresolvedIdents
return entities |> Seq.map createEntity |> Seq.concat |> Seq.toList |> getSuggestions context
| None -> ()
| None -> ()
} |> CommonRoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
Expand Down