diff --git a/src/fsharp/vs/Symbols.fs b/src/fsharp/vs/Symbols.fs index 62f83181c9..7faffa1537 100644 --- a/src/fsharp/vs/Symbols.fs +++ b/src/fsharp/vs/Symbols.fs @@ -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 @@ -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 @@ -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= [] } @@ -1813,9 +1850,13 @@ and FSharpParameter(cenv, typ:TType, topArgInfo:ArgReprInfo, mOpt, isParamArrayA override x.ToString() = "parameter " + (match x.Name with None -> " 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 = @@ -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 @@ -1839,7 +1881,7 @@ 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 @@ -1847,7 +1889,7 @@ and FSharpAssembly internal (cenv, ccu: CcuThunk) = 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 diff --git a/src/fsharp/vs/Symbols.fsi b/src/fsharp/vs/Symbols.fsi index 5a6f98e162..5de5229c08 100644 --- a/src/fsharp/vs/Symbols.fsi +++ b/src/fsharp/vs/Symbols.fsi @@ -80,7 +80,7 @@ type [] FSharpSymbol = /// Represents an assembly as seen by the F# language and [] 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 @@ -623,18 +623,32 @@ and [] 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 diff --git a/src/fsharp/vs/service.fs b/src/fsharp/vs/service.fs index 0b7662e442..9e21b8ab8b 100755 --- a/src/fsharp/vs/service.fs +++ b/src/fsharp/vs/service.fs @@ -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() = @@ -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 = diff --git a/tests/service/CSharpProjectAnalysis.fs b/tests/service/CSharpProjectAnalysis.fs index 5bb775a8f3..9f7671dee7 100644 --- a/tests/service/CSharpProjectAnalysis.fs +++ b/tests/service/CSharpProjectAnalysis.fs @@ -65,33 +65,35 @@ let ``Test that csharp references are recognized as such`` () = let csharpAssembly = typeof.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" [] let ``Test that symbols of csharp inner classes/enums are reported`` () =