Skip to content

Commit 192beb8

Browse files
committed
Merge pull request #375 from alfonsogarciacaro/master
Implements FSharpMemberOrFunctionOrValue.IsConstructorThisValue, IsMemberThisValue & LiteralValue
2 parents 6684fe1 + 55d8e33 commit 192beb8

File tree

3 files changed

+137
-39
lines changed

3 files changed

+137
-39
lines changed

src/fsharp/vs/Symbols.fs

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,28 @@ module Impl =
118118
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
119119
entity.Accessibility
120120

121-
121+
let getLiteralValue = function
122+
| Some lv ->
123+
match lv with
124+
| Const.Bool v -> Some(box v)
125+
| Const.SByte v -> Some(box v)
126+
| Const.Byte v -> Some(box v)
127+
| Const.Int16 v -> Some(box v)
128+
| Const.UInt16 v -> Some(box v)
129+
| Const.Int32 v -> Some(box v)
130+
| Const.UInt32 v -> Some(box v)
131+
| Const.Int64 v -> Some(box v)
132+
| Const.UInt64 v -> Some(box v)
133+
| Const.IntPtr v -> Some(box v)
134+
| Const.UIntPtr v -> Some(box v)
135+
| Const.Single v -> Some(box v)
136+
| Const.Double v -> Some(box v)
137+
| Const.Char v -> Some(box v)
138+
| Const.String v -> Some(box v)
139+
| Const.Decimal v -> Some(box v)
140+
| Const.Unit
141+
| Const.Zero -> None
142+
| None -> None
122143

123144

124145
type cenv(g:TcGlobals, thisCcu: CcuThunk , tcImports: TcImports) =
@@ -638,29 +659,9 @@ and FSharpField(cenv, d: FSharpFieldData) =
638659
d.RecdField.LiteralValue.IsSome
639660

640661
member __.LiteralValue =
641-
if isUnresolved() then None else
642-
match d.RecdField.LiteralValue with
643-
| Some lv ->
644-
match lv with
645-
| Const.Bool v -> Some(box v)
646-
| Const.SByte v -> Some(box v)
647-
| Const.Byte v -> Some(box v)
648-
| Const.Int16 v -> Some(box v)
649-
| Const.UInt16 v -> Some(box v)
650-
| Const.Int32 v -> Some(box v)
651-
| Const.UInt32 v -> Some(box v)
652-
| Const.Int64 v -> Some(box v)
653-
| Const.UInt64 v -> Some(box v)
654-
| Const.IntPtr v -> Some(box v)
655-
| Const.UIntPtr v -> Some(box v)
656-
| Const.Single v -> Some(box v)
657-
| Const.Double v -> Some(box v)
658-
| Const.Char v -> Some(box v)
659-
| Const.String v -> Some(box v)
660-
| Const.Decimal v -> Some(box v)
661-
| Const.Unit
662-
| Const.Zero -> None
663-
| None -> None
662+
if isUnresolved()
663+
then None
664+
else getLiteralValue d.RecdField.LiteralValue
664665

665666
member __.IsVolatile =
666667
if isUnresolved() then false else
@@ -1489,20 +1490,33 @@ and FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
14891490
v.Attribs |> List.map (fun a -> FSharpAttribute(cenv, AttribInfo.FSAttribInfo(cenv.g, a)))
14901491
|> makeReadOnlyCollection
14911492

1492-
(*
14931493
/// Is this "base" in "base.M(...)"
1494-
member __.IsBaseValue : bool
1494+
member __.IsBaseValue =
1495+
if isUnresolved() then false else
1496+
match d with
1497+
| M _ | P _ | E _ -> false
1498+
| V v -> v.BaseOrThisInfo = BaseVal
14951499

14961500
/// Is this the "x" in "type C() as x = ..."
1497-
member __.IsConstructorThisValue : bool
1498-
1499-
/// Is this the "x" in "member __.M = ..."
1500-
member __.IsMemberThisValue : bool
1501+
member __.IsConstructorThisValue =
1502+
if isUnresolved() then false else
1503+
match d with
1504+
| M _ | P _ | E _ -> false
1505+
| V v -> v.BaseOrThisInfo = CtorThisVal
15011506

1502-
/// Is this a [<Literal>] value, and if so what value?
1503-
member __.LiteralValue : obj // may be null
1507+
/// Is this the "x" in "member x.M = ..."
1508+
member __.IsMemberThisValue =
1509+
if isUnresolved() then false else
1510+
match d with
1511+
| M _ | P _ | E _ -> false
1512+
| V v -> v.BaseOrThisInfo = MemberThisVal
15041513

1505-
*)
1514+
/// Is this a [<Literal>] value, and if so what value? (may be null)
1515+
member __.LiteralValue =
1516+
if isUnresolved() then None else
1517+
match d with
1518+
| M _ | P _ | E _ -> None
1519+
| V v -> getLiteralValue v.LiteralValue
15061520

15071521
/// How visible is this?
15081522
member this.Accessibility : FSharpAccessibility =

src/fsharp/vs/Symbols.fsi

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -698,8 +698,6 @@ and [<Class>] FSharpMemberOrFunctionOrValue =
698698
/// XML documentation signature for the value, used for .xml file lookup for compiled code
699699
member XmlDocSig: string
700700

701-
702-
#if TODO
703701
/// Indicates if this is "base" in "base.M(...)"
704702
member IsBaseValue : bool
705703

@@ -709,10 +707,8 @@ and [<Class>] FSharpMemberOrFunctionOrValue =
709707
/// Indicates if this is the "x" in "member x.M = ..."
710708
member IsMemberThisValue : bool
711709

712-
/// Indicates if this is a [<Literal>] value, and if so what value?
713-
member LiteralValue : obj // may be null
714-
715-
#endif
710+
/// Indicates if this is a [<Literal>] value, and if so what value? (may be null)
711+
member LiteralValue : obj option
716712

717713
/// Get the accessibility information for the member, function or value
718714
member Accessibility : FSharpAccessibility

tests/service/ProjectAnalysisTests.fs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ let attribsOfSymbol (s:FSharpSymbol) =
8888
if v.IsMutable then yield "mutable"
8989
if v.IsOverrideOrExplicitInterfaceImplementation then yield "overridemem"
9090
if v.IsExplicitInterfaceImplementation then yield "intfmem"
91+
// if v.IsConstructorThisValue then yield "ctorthis"
92+
// if v.IsMemberThisValue then yield "this"
93+
// if v.LiteralValue.IsSome then yield "literal"
9194
| _ -> () ]
9295

9396
module Project1 =
@@ -4408,3 +4411,88 @@ let ``Test project35 CurriedParameterGroups should be available for nested funct
44084411

44094412
| _ -> failwith "Unexpected symbol type"
44104413

4414+
module Project36 =
4415+
open System.IO
4416+
4417+
let fileName1 = Path.ChangeExtension(Path.GetTempFileName(), ".fs")
4418+
let base2 = Path.GetTempFileName()
4419+
let dllName = Path.ChangeExtension(base2, ".dll")
4420+
let projFileName = Path.ChangeExtension(base2, ".fsproj")
4421+
let fileSource1 = """
4422+
type A(i:int) =
4423+
member x.Value = i
4424+
4425+
type B(i:int) as b =
4426+
inherit A(i*2)
4427+
let a = b.Overload(i)
4428+
member x.Overload() = a
4429+
member x.Overload(y: int) = y + y
4430+
member x.BaseValue = base.Value
4431+
4432+
let [<Literal>] lit = 1.0
4433+
let notLit = 1.0
4434+
let callToOverload = B(5).Overload(4)
4435+
"""
4436+
File.WriteAllText(fileName1, fileSource1)
4437+
let cleanFileName a = if a = fileName1 then "file1" else "??"
4438+
4439+
let fileNames = [fileName1]
4440+
let args = mkProjectCommandLineArgs (dllName, fileNames)
4441+
let keepAssemblyContentsChecker = FSharpChecker.Create(keepAssemblyContents=true)
4442+
let options = keepAssemblyContentsChecker.GetProjectOptionsFromCommandLineArgs (projFileName, args)
4443+
let wholeProjectResults =
4444+
keepAssemblyContentsChecker.ParseAndCheckProject(options)
4445+
|> Async.RunSynchronously
4446+
let declarations =
4447+
let checkedFile = wholeProjectResults.AssemblyContents.ImplementationFiles.[0]
4448+
match checkedFile.Declarations.[0] with
4449+
| FSharpImplementationFileDeclaration.Entity (_, subDecls) -> subDecls
4450+
| _ -> failwith "unexpected declaration"
4451+
let getExpr exprIndex =
4452+
match declarations.[exprIndex] with
4453+
| FSharpImplementationFileDeclaration.MemberOrFunctionOrValue(_,_,e) -> e
4454+
| FSharpImplementationFileDeclaration.InitAction e -> e
4455+
| _ -> failwith "unexpected declaration"
4456+
4457+
[<Test>]
4458+
let ``Test project36 FSharpMemberOrFunctionOrValue.IsBaseValue`` () =
4459+
Project36.wholeProjectResults.GetAllUsesOfAllSymbols()
4460+
|> Async.RunSynchronously
4461+
|> Array.pick (fun (su:FSharpSymbolUse) ->
4462+
if su.Symbol.DisplayName = "base"
4463+
then Some (su.Symbol :?> FSharpMemberOrFunctionOrValue)
4464+
else None)
4465+
|> fun baseSymbol -> shouldEqual true baseSymbol.IsBaseValue
4466+
4467+
[<Test>]
4468+
let ``Test project36 FSharpMemberOrFunctionOrValue.IsConstructorThisValue & IsMemberThisValue`` () =
4469+
// Instead of checking the symbol uses directly, walk the typed tree to check
4470+
// the correct values are also visible from there. Also note you cannot use
4471+
// BasicPatterns.ThisValue in these cases, this is only used when the symbol
4472+
// is implicit in the constructor
4473+
match Project36.getExpr 4 with
4474+
| BasicPatterns.Let((b,_),_) ->
4475+
b.IsConstructorThisValue && not b.IsMemberThisValue
4476+
| _ -> failwith "unexpected expression"
4477+
|> shouldEqual true
4478+
4479+
match Project36.getExpr 5 with
4480+
| BasicPatterns.FSharpFieldGet(Some(BasicPatterns.Value x),_,_) ->
4481+
x.IsMemberThisValue && not x.IsConstructorThisValue
4482+
| _ -> failwith "unexpected expression"
4483+
|> shouldEqual true
4484+
4485+
match Project36.getExpr 6 with
4486+
| BasicPatterns.Call(_,_,_,_,[BasicPatterns.Value s;_]) ->
4487+
not s.IsMemberThisValue && not s.IsConstructorThisValue
4488+
| _ -> failwith "unexpected expression"
4489+
|> shouldEqual true
4490+
4491+
[<Test>]
4492+
let ``Test project36 FSharpMemberOrFunctionOrValue.LiteralValue`` () =
4493+
let project36Module = Project36.wholeProjectResults.AssemblySignature.Entities.[0]
4494+
let lit = project36Module.MembersFunctionsAndValues.[0]
4495+
shouldEqual true (lit.LiteralValue.Value |> unbox |> (=) 1.)
4496+
4497+
let notLit = project36Module.MembersFunctionsAndValues.[1]
4498+
shouldEqual true notLit.LiteralValue.IsNone

0 commit comments

Comments
 (0)