Skip to content

Commit

Permalink
Merge pull request #426 from dsyme/fix-423
Browse files Browse the repository at this point in the history
fix 423 (Events), fix 235 (XmlDocSig)
  • Loading branch information
dsyme committed Sep 30, 2015
2 parents 92c68a4 + 04b4d6f commit 1ae73fe
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 41 deletions.
64 changes: 53 additions & 11 deletions src/fsharp/vs/Symbols.fs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ module Impl =
System.Collections.ObjectModel.ReadOnlyCollection<_>(Seq.toArray arr) :> IList<_>
let makeXmlDoc (XmlDoc x) = makeReadOnlyCollection (x)

let rescopeEntity viewedCcu (entity : Entity) =
let rescopeEntity optViewedCcu (entity : Entity) =
match optViewedCcu with
| None -> mkLocalEntityRef entity
| Some viewedCcu ->
match tryRescopeEntity viewedCcu entity with
| None -> mkLocalEntityRef entity
| Some eref -> eref
Expand Down Expand Up @@ -1115,9 +1118,37 @@ and FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
| P m ->
let minfo = m.GetterMethod
FSharpMemberOrFunctionOrValue(cenv, M minfo, Item.MethodGroup (minfo.DisplayName,[minfo]))
| E _
| M _
| V _ -> invalidOp "the value or member doesn't have an associated getter method"
| E _ | M _ | V _ -> invalidOp "the value or member doesn't have an associated getter method"

member __.EventAddMethod =
checkIsResolved()
match d with
| E e ->
let minfo = e.GetAddMethod()
FSharpMemberOrFunctionOrValue(cenv, M minfo, Item.MethodGroup (minfo.DisplayName,[minfo]))
| P _ | M _ | V _ -> invalidOp "the value or member doesn't have an associated add method"

member __.EventRemoveMethod =
checkIsResolved()
match d with
| E e ->
let minfo = e.GetRemoveMethod()
FSharpMemberOrFunctionOrValue(cenv, M minfo, Item.MethodGroup (minfo.DisplayName,[minfo]))
| P _ | M _ | V _ -> invalidOp "the value or member doesn't have an associated remove method"

member __.EventDelegateType =
checkIsResolved()
match d with
| E e -> FSharpType(cenv, e.GetDelegateType(cenv.amap,range0))
| P _ | M _ | V _ -> invalidOp "the value or member doesn't have an associated event delegate type"

member __.EventIsStandard =
checkIsResolved()
match d with
| E e ->
let dty = e.GetDelegateType(cenv.amap,range0)
TryDestStandardDelegateTyp cenv.infoReader range0 AccessibleFromSomewhere dty |> isSome
| P _ | M _ | V _ -> invalidOp "the value or member is not an event"

member __.HasSetterMethod =
if isUnresolved() then false
Expand Down Expand Up @@ -1446,9 +1477,15 @@ and FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
| E e ->
// INCOMPLETENESS: Attribs is empty here, so we can't look at return attributes for .NET or F# methods
let retInfo : ArgReprInfo = { Name=None; Attribs= [] }
let rty = PropTypOfEventInfo cenv.infoReader range0 AccessibleFromSomewhere e
let _,rty, _cxs = PrettyTypes.PrettifyTypes1 cenv.g rty
let rty =
try PropTypOfEventInfo cenv.infoReader range0 AccessibleFromSomewhere e
with _ ->
// For non-standard events, just use the delegate type as the ReturnParameter type
e.GetDelegateType(cenv.amap,range0)

let _, rty, _cxs = PrettyTypes.PrettifyTypes1 cenv.g rty
FSharpParameter(cenv, rty, retInfo, x.DeclarationLocationOpt, isParamArrayArg=false, isOutArg=false, isOptionalArg=false)

| P p ->
// INCOMPLETENESS: Attribs is empty here, so we can't look at return attributes for .NET or F# methods
let retInfo : ArgReprInfo = { Name=None; Attribs= [] }
Expand Down Expand Up @@ -1813,9 +1850,13 @@ and FSharpParameter(cenv, typ:TType, topArgInfo:ArgReprInfo, mOpt, isParamArrayA
override x.ToString() =
"parameter " + (match x.Name with None -> "<unnamed" | Some s -> s)

and FSharpAssemblySignature internal (cenv, topAttribs: TypeChecker.TopAttribs option, mtyp: ModuleOrNamespaceType) =
and FSharpAssemblySignature private (cenv, topAttribs: TypeChecker.TopAttribs option, optViewedCcu: CcuThunk option, mtyp: ModuleOrNamespaceType) =

new (g, thisCcu, tcImports, topAttribs, mtyp) = FSharpAssemblySignature(cenv(g,thisCcu,tcImports), topAttribs, mtyp)
// Assembly signature for a referenced/linked assembly
new (cenv, ccu: CcuThunk) = FSharpAssemblySignature((if ccu.IsUnresolvedReference then cenv else (new cenv(cenv.g, ccu, cenv.tcImports))), None, Some ccu, ccu.Contents.ModuleOrNamespaceType)

// Assembly signature for an assembly produced via type-checking.
new (g, thisCcu, tcImports, topAttribs, mtyp) = FSharpAssemblySignature(cenv(g, thisCcu, tcImports), topAttribs, None, mtyp)

member __.Entities =

Expand All @@ -1824,7 +1865,8 @@ and FSharpAssemblySignature internal (cenv, topAttribs: TypeChecker.TopAttribs o
if entity.IsNamespace then
yield! loop entity.ModuleOrNamespaceType
else
yield FSharpEntity(cenv, mkLocalEntityRef entity) |]
let entityRef = rescopeEntity optViewedCcu entity
yield FSharpEntity(cenv, entityRef) |]

loop mtyp |> makeReadOnlyCollection

Expand All @@ -1839,15 +1881,15 @@ and FSharpAssemblySignature internal (cenv, topAttribs: TypeChecker.TopAttribs o

and FSharpAssembly internal (cenv, ccu: CcuThunk) =

new (g, thisCcu, tcImports, ccu) = FSharpAssembly(cenv(g,thisCcu,tcImports), ccu)
new (g, tcImports, ccu) = FSharpAssembly(cenv(g, ccu, tcImports), ccu)

member __.RawCcuThunk = ccu
member __.QualifiedName = match ccu.QualifiedName with None -> "" | Some s -> s
member __.CodeLocation = ccu.SourceCodeDirectory
member __.FileName = ccu.FileName
member __.SimpleName = ccu.AssemblyName
member __.IsProviderGenerated = ccu.IsProviderGenerated
member __.Contents = FSharpAssemblySignature((if ccu.IsUnresolvedReference then cenv else (new cenv(cenv.g, ccu, cenv.tcImports))), None, ccu.Contents.ModuleOrNamespaceType)
member __.Contents = FSharpAssemblySignature(cenv, ccu)

override x.ToString() = x.QualifiedName

Expand Down
20 changes: 17 additions & 3 deletions src/fsharp/vs/Symbols.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type [<Class>] FSharpSymbol =
/// Represents an assembly as seen by the F# language
and [<Class>] FSharpAssembly =

internal new : tcGlobals: TcGlobals * thisCcu: CcuThunk * tcImports: TcImports * ccu: CcuThunk -> FSharpAssembly
internal new : tcGlobals: TcGlobals * tcImports: TcImports * ccu: CcuThunk -> FSharpAssembly

/// The qualified name of the assembly
member QualifiedName: string
Expand Down Expand Up @@ -623,18 +623,32 @@ and [<Class>] FSharpMemberOrFunctionOrValue =
/// Indicates if this is a property member
member IsProperty : bool

/// Indicates if this is a property then there exists an associated getter method
/// Indicates if this is a property and there exists an associated getter method
member HasGetterMethod : bool

/// Get an associated getter method of the property
member GetterMethod : FSharpMemberOrFunctionOrValue

/// Indicates if this is a property then there exists an associated setter method
/// Indicates if this is a property and there exists an associated setter method
member HasSetterMethod : bool

/// Get an associated setter method of the property
member SetterMethod : FSharpMemberOrFunctionOrValue

/// Get an associated add method of an event
member EventAddMethod : FSharpMemberOrFunctionOrValue

/// Get an associated remove method of an event
member EventRemoveMethod : FSharpMemberOrFunctionOrValue

/// Get an associated delegate type of an event
member EventDelegateType : FSharpType

/// Indicate if an event can be considered to be a property for the F# type system of type IEvent or IDelegateEvent.
/// In this case ReturnParameter will have a type corresponding to the property type. For
/// non-standard events, ReturnParameter will have a type corresponding to the delegate type.
member EventIsStandard: bool

/// Indicates if this is an event member
member IsEvent : bool

Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/vs/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ type TypeCheckInfo

member scope.GetReferencedAssemblies() =
[ for x in tcImports.GetImportedAssemblies() do
yield FSharpAssembly(g, thisCcu, tcImports, x.FSharpViewOfMetadata) ]
yield FSharpAssembly(g, tcImports, x.FSharpViewOfMetadata) ]

// Not, this does not have to be a SyncOp, it can be called from any thread
member scope.GetFormatSpecifierLocations() =
Expand Down Expand Up @@ -1928,7 +1928,7 @@ type FSharpCheckProjectResults(keepAssemblyContents, errors: FSharpErrorInfo[],
let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, ad, _tcAssemblyExpr) = getDetails()
let assemblies =
[ for x in tcImports.GetImportedAssemblies() do
yield FSharpAssembly(tcGlobals, thisCcu, tcImports, x.FSharpViewOfMetadata) ]
yield FSharpAssembly(tcGlobals, tcImports, x.FSharpViewOfMetadata) ]
FSharpProjectContext(thisCcu, assemblies, ad)

member info.RawFSharpAssemblyData =
Expand Down
52 changes: 27 additions & 25 deletions tests/service/CSharpProjectAnalysis.fs
Original file line number Diff line number Diff line change
Expand Up @@ -65,33 +65,35 @@ let ``Test that csharp references are recognized as such`` () =
let csharpAssembly = typeof<CSharpClass>.Assembly.Location
let _, table = getProjectReferences("""module M""", [csharpAssembly], None, None)
let ass = table.["CSharp_Analysis"]
match ass.Contents.Entities |> Seq.tryFind (fun e -> e.DisplayName = "CSharpClass") with
| Some found ->
// this is no F# thing
found.IsFSharp |> shouldEqual false
let search = ass.Contents.Entities |> Seq.tryFind (fun e -> e.DisplayName = "CSharpClass")
Assert.True search.IsSome
let found = search.Value
// this is no F# thing
found.IsFSharp |> shouldEqual false

// Check that we have members
let members = found.MembersFunctionsAndValues |> Seq.map (fun e -> e.CompiledName, e) |> dict
members.ContainsKey ".ctor" |> shouldEqual true
members.ContainsKey "Method" |> shouldEqual true
members.ContainsKey "Property" |> shouldEqual true
members.ContainsKey "Event" |> shouldEqual true
members.ContainsKey "InterfaceMethod" |> shouldEqual true
members.ContainsKey "InterfaceProperty" |> shouldEqual true
members.ContainsKey "InterfaceEvent" |> shouldEqual true
// Check that we have members
let members = found.MembersFunctionsAndValues |> Seq.map (fun e -> e.CompiledName, e) |> dict
members.ContainsKey ".ctor" |> shouldEqual true
members.ContainsKey "Method" |> shouldEqual true
members.ContainsKey "Property" |> shouldEqual true
members.ContainsKey "Event" |> shouldEqual true
members.ContainsKey "InterfaceMethod" |> shouldEqual true
members.ContainsKey "InterfaceProperty" |> shouldEqual true
members.ContainsKey "InterfaceEvent" |> shouldEqual true
members.["Event"].IsEvent |> shouldEqual true
members.["Event"].EventIsStandard |> shouldEqual true
members.["Event"].EventAddMethod.DisplayName |> shouldEqual "add_Event"
members.["Event"].EventRemoveMethod.DisplayName |> shouldEqual "remove_Event"
members.["Event"].EventDelegateType.ToString() |> shouldEqual "type System.EventHandler"

//// Check that we get xml docs
//String.IsNullOrWhiteSpace(members.[".ctor"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["Method"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["Property"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["Event"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["InterfaceMethod"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["InterfaceProperty"].XmlDocSig) |> shouldEqual false
//String.IsNullOrWhiteSpace(members.["InterfaceEvent"].XmlDocSig) |> shouldEqual false

()
| None ->
Assert.Fail ("CSharpClass was not found in CSharp_Analysis assembly!")
//// Check that we get xml docs
members.[".ctor"].XmlDocSig |> shouldEqual "M:FSharp.Compiler.Service.Tests.CSharpClass.#ctor(System.Int32,System.String)"
members.["Method"].XmlDocSig |> shouldEqual "M:FSharp.Compiler.Service.Tests.CSharpClass.Method(System.String)"
members.["Property"].XmlDocSig |> shouldEqual "P:FSharp.Compiler.Service.Tests.CSharpClass.Property"
members.["Event"].XmlDocSig |> shouldEqual "E:FSharp.Compiler.Service.Tests.CSharpClass.Event"
members.["InterfaceMethod"].XmlDocSig |> shouldEqual "M:FSharp.Compiler.Service.Tests.CSharpClass.InterfaceMethod(System.String)"
members.["InterfaceProperty"].XmlDocSig |> shouldEqual "P:FSharp.Compiler.Service.Tests.CSharpClass.InterfaceProperty"
members.["InterfaceEvent"].XmlDocSig |> shouldEqual "E:FSharp.Compiler.Service.Tests.CSharpClass.InterfaceEvent"

[<Test>]
let ``Test that symbols of csharp inner classes/enums are reported`` () =
Expand Down

0 comments on commit 1ae73fe

Please sign in to comment.