Skip to content
This repository has been archived by the owner on Oct 31, 2021. It is now read-only.

Commit

Permalink
Merge pull request #891 from dungpa/unsupported-attributes
Browse files Browse the repository at this point in the history
Bypass unsupported attribute arguments
  • Loading branch information
vasily-kirichenko committed Dec 6, 2014
2 parents a0fe0f9 + 7a797bc commit b404159
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 44 deletions.
55 changes: 26 additions & 29 deletions src/FSharpVSPowerTools.Core/OpenDeclarationsGetter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -262,56 +262,53 @@ module OpenDeclarationGetter =
| _ -> []

let getEffectiveOpenDeclarationsAtLocation (pos: pos) (ast: ParsedInput) =
match ast with
| ParsedInput.ImplFile (ParsedImplFileInput(_, _, _, _, _, modules, _)) ->
let rec walkModuleOrNamespace acc (decls, moduleRange) =
let openStatements =
let openStatements =
match ast with
| ParsedInput.ImplFile (ParsedImplFileInput(_, _, _, _, _, modules, _)) ->
let rec walkModuleOrNamespace openStatements (decls, moduleRange) =
decls
|> List.fold (fun acc ->
function
| SynModuleDecl.NestedModule (_, nestedModuleDecls, _, nestedModuleRange) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespace acc (nestedModuleDecls, nestedModuleRange)
else []
else acc
| SynModuleDecl.Open (LongIdentWithDots(longIdent, _), openDeclRange) ->
let identArray = processOpenDeclaration longIdent
if openDeclRange.EndLine < pos.Line || (openDeclRange.EndLine = pos.Line && openDeclRange.EndColumn < pos.Column) then
String.Join(".", identArray) :: acc
else acc
| _ -> acc) []
openStatements @ acc
| _ -> acc) openStatements

modules
|> List.fold (fun acc (SynModuleOrNamespace(_, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespace acc (decls, moduleRange) @ acc
else acc) []
|> Seq.distinct
|> Seq.toList
|> List.rev
| ParsedInput.SigFile(ParsedSigFileInput(_, _, _, _, modules)) ->
let rec walkModuleOrNamespaceSig acc (decls, moduleRange) =
let openStatements =
modules
|> List.fold (fun acc (SynModuleOrNamespace(_, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespace acc (decls, moduleRange) @ acc
else acc) []
| ParsedInput.SigFile(ParsedSigFileInput(_, _, _, _, modules)) ->
let rec walkModuleOrNamespaceSig openStatements (decls, moduleRange) =
decls
|> List.fold (fun acc ->
function
| SynModuleSigDecl.NestedModule (_, nestedModuleDecls, nestedModuleRange) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespaceSig acc (nestedModuleDecls, nestedModuleRange)
else []
else acc
| SynModuleSigDecl.Open (longIdent, openDeclRange) ->
let identArray = processOpenDeclaration longIdent
if openDeclRange.EndLine < pos.Line || (openDeclRange.EndLine = pos.Line && openDeclRange.EndColumn < pos.Column) then
String.Join(".", identArray) :: acc
else acc
| _ -> acc) []
openStatements @ acc
| _ -> acc) openStatements

modules
|> List.fold (fun acc (SynModuleOrNamespaceSig(_, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespaceSig acc (decls, moduleRange) @ acc
else acc) []
|> Seq.distinct
|> Seq.toList
|> List.rev
modules
|> List.fold (fun acc (SynModuleOrNamespaceSig(_, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespaceSig acc (decls, moduleRange) @ acc
else acc) []
seq {
yield! List.rev openStatements
yield getModuleOrNamespacePath pos ast
}
|> Seq.distinct
|> Seq.toList
12 changes: 9 additions & 3 deletions src/FSharpVSPowerTools.Core/SignatureGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -658,11 +658,17 @@ and internal formatAttribute ctx (attribute: FSharpAttribute) =
and internal writeAttributes ctx writer (typ: option<FSharpEntity>) (attributes: IList<FSharpAttribute>) =
let typeDefSyntaxDelimOpt = Option.bind tryGetNeededTypeDefSyntaxDelimiter typ
let bypassAttribute (attrib: FSharpAttribute) =
typeDefSyntaxDelimOpt = Some "struct" && isAttribute<StructAttribute> attrib
not attrib.AttributeType.Accessibility.IsPublic
|| isAttribute<AttributeUsageAttribute> attrib
|| (typeDefSyntaxDelimOpt = Some "struct" && isAttribute<StructAttribute> attrib)

for (attr: FSharpAttribute) in attributes do
for attr in attributes do
if not (bypassAttribute attr) then
writer.WriteLine(formatAttribute ctx attr)
let attrText = formatAttribute ctx attr
// Bypass unsupported attribute arguments
// TODO: this should be fixed in FCS, albeit not easy.
if not (attrText.Contains "(* unsupported attribute argument *)") then
writer.WriteLine(attrText)

and internal writeField hasNewLine ctx (field: FSharpField) =
writeDocs ctx.Writer field.XmlDoc (fun _ -> field.XmlDocSig) ctx.GetXmlDocBySignature
Expand Down
45 changes: 45 additions & 0 deletions src/FSharpVSPowerTools.Core/UntypedAstUtils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
open Microsoft.FSharp.Compiler.Ast
open System.Collections.Generic
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.Range

type internal ShortIdent = string
type internal Idents = ShortIdent[]
Expand Down Expand Up @@ -708,3 +709,47 @@ let internal getStringLiterals ast : Range.range list =
| _ -> ())

List.ofSeq result

/// Get path to containing module/namespace of a given position
let getModuleOrNamespacePath (pos: pos) (ast: ParsedInput) =
let idents =
match ast with
| ParsedInput.ImplFile (ParsedImplFileInput(_, _, _, _, _, modules, _)) ->
let rec walkModuleOrNamespace idents (decls, moduleRange) =
decls
|> List.fold (fun acc ->
function
| SynModuleDecl.NestedModule (componentInfo, nestedModuleDecls, _, nestedModuleRange) ->
if rangeContainsPos moduleRange pos then
let (ComponentInfo(_,_,_,longIdent,_,_,_,_)) = componentInfo
walkModuleOrNamespace (longIdent::acc) (nestedModuleDecls, nestedModuleRange)
else acc
| _ -> acc) idents

modules
|> List.fold (fun acc (SynModuleOrNamespace(longIdent, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespace (longIdent::acc) (decls, moduleRange) @ acc
else acc) []
| ParsedInput.SigFile(ParsedSigFileInput(_, _, _, _, modules)) ->
let rec walkModuleOrNamespaceSig idents (decls, moduleRange) =
decls
|> List.fold (fun acc ->
function
| SynModuleSigDecl.NestedModule (componentInfo, nestedModuleDecls, nestedModuleRange) ->
if rangeContainsPos moduleRange pos then
let (ComponentInfo(_,_,_,longIdent,_,_,_,_)) = componentInfo
walkModuleOrNamespaceSig (longIdent::acc) (nestedModuleDecls, nestedModuleRange)
else acc
| _ -> acc) idents

modules
|> List.fold (fun acc (SynModuleOrNamespaceSig(longIdent, _, decls, _, _, _, moduleRange)) ->
if rangeContainsPos moduleRange pos then
walkModuleOrNamespaceSig (longIdent::acc) (decls, moduleRange) @ acc
else acc) []
idents
|> List.rev
|> Seq.concat
|> Seq.map (fun ident -> ident.idText)
|> String.concat "."
52 changes: 48 additions & 4 deletions tests/FSharpVSPowerTools.Core.Tests/GoToDefinitionTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ type T2 =
|> generateDefinitionFromPosNoValidation (Pos.fromZ 4 5)
|> assertSrcAreEqual """module File
open File
type T2 =
interface
inherit T
Expand Down Expand Up @@ -670,6 +672,8 @@ type MyClass() =
|> generateDefinitionFromPosNoValidation (Pos.fromZ 5 5)
|> assertSrcAreEqual """module File
open File
type MyClass =
inherit MyBaseClass
new : unit -> MyClass
Expand Down Expand Up @@ -1434,10 +1438,49 @@ let ``type abbreviations for basic types`` () =
type ResizeArray<'T> = System.Collections.Generic.List<'T>
"""

[<Test>]
let ``support compiled name attribute`` () =
"""open System
[<CompiledName("C")>]
type C() = class end"""
|> generateDefinitionFromPos (Pos.fromZ 1 8)
|> assertSrcAreEqual """namespace Microsoft.FSharp.Core
/// Adding this attribute to a value or function definition in an F# module changes the name used
/// for the value in compiled CLI code.
[<Sealed>]
type CompiledNameAttribute =
inherit System.Attribute
/// Creates an instance of the attribute
new : compiledName:string -> CompiledNameAttribute
/// The name of the value as it appears in compiled code
member CompiledName : string
"""

[<Test>]
let ``set up transitive open declarations correctly`` () =
"""namespace System
[<System.Runtime.InteropServices.ComVisible(true)>]
type T() = class end"""
|> generateDefinitionFromPos (Pos.fromZ 1 35)
|> assertSrcAreEqual """namespace System.Runtime.InteropServices
open System
/// Controls accessibility of an individual managed type or member, or of all types within an assembly, to COM.
[<Runtime.InteropServices.ComVisible(true)>]
type ComVisibleAttribute =
inherit System.Attribute
/// Initializes a new instance of the ComVisibleAttribute class.
new : visibility:bool -> ComVisibleAttribute
/// Gets a value that indicates whether the COM type is visible.
member Value : bool
"""

[<Test>]
let ``handle operators as compiled members`` () =
"""let x: System.DateTime = failwith "" """
|> generateDefinitionFromPosNoValidation (Pos.fromZ 0 20)
|> generateDefinitionFromPos (Pos.fromZ 0 20)
|> fun str -> str.Contains("static member op_GreaterThanOrEqual : t1:System.DateTime * t2:System.DateTime -> bool")
|> assertEqual true

Expand All @@ -1451,15 +1494,15 @@ let ``handle uninstantiated type parameters`` () =

let ``handle generic definitions`` () =
"""open System
let x: Collections.Generic.List<'T> = failwith "" """
let x: Collections.Generic.List<string> = failwith "" """
|> generateDefinitionFromPos (Pos.fromZ 1 30)
|> fun str -> str.Contains("member GetEnumerator : unit -> System.Collections.Generic.List<'T>.Enumerator")
|> assertEqual true

[<Test>]
let ``handle generic definitions 2`` () =
"""open System
let x: Collections.Generic.Dictionary<'K, 'V> = failwith "" """
let x: Collections.Generic.Dictionary<string, int> = failwith "" """
|> generateDefinitionFromPosNoValidation (Pos.fromZ 1 30)
|> fun str -> str.Contains("member Values : System.Collections.Generic.Dictionary<'TKey,'TValue>.ValueCollection")
|> assertEqual true
Expand All @@ -1468,7 +1511,7 @@ let x: Collections.Generic.Dictionary<'K, 'V> = failwith "" """
let ``handle active patterns as parts of module declarations`` () =
"""open Microsoft.FSharp.Quotations
let f = Patterns.(|AddressOf|_|)"""
|> generateDefinitionFromPosNoValidation (Pos.fromZ 1 13)
|> generateDefinitionFromPos (Pos.fromZ 1 13)
|> fun str -> str.Contains("val (|AddressSet|_|) : input:Expr -> (Expr * Expr) option")
|> assertEqual true

Expand Down Expand Up @@ -1514,6 +1557,7 @@ let _ = Async.AwaitTask"""
|> generateFileNameForSymbol (Pos.fromZ 1 16)
|> assertSrcAreEqual "Microsoft.FSharp.Control.FSharpAsync.fsi"


// Tests to add:
// TODO: buffer should have the same behavior as C#'s generated metadata ([from metadata] instead of [read-only] header, preview buffer and not permanent buffer)
// TODO: set cursor on method/... when symbol is a method/union case/enum value/record field
29 changes: 21 additions & 8 deletions tests/FSharpVSPowerTools.Core.Tests/OpenDeclarationsGetterTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,23 @@ let ``open declarations from nested modules``() =
open System
open System.IO
module M =
open InternalModuleWithSuffix
let x = 0
module N =
open InternalModuleWithSuffix
let x = 0
""", false)
|-> (pos 7 13, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M.N"])

[<Test>]
let ``open declarations from namespaces``() =
("""
namespace M
open System
open System.IO
module N =
open InternalModuleWithSuffix
let x = 0
""", false)
|-> (pos 6 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 7 13, ["System"; "System.IO"; "InternalModuleWithSuffix"; "M.N"])

[<Test>]
let ``open declarations with duplication``() =
Expand All @@ -315,7 +328,7 @@ module M =
open System.Collections.Generic
open System.Collections.Generic
""", false)
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M"])

[<Test>]
let ``open declarations with global prefix``() =
Expand All @@ -328,7 +341,7 @@ module M =
open System
let x = 0
""", false)
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M"])

[<Test>]
let ``open declarations from nested modules in signatures``() =
Expand All @@ -339,7 +352,7 @@ module M =
open InternalModuleWithSuffix
val x: int
""", true)
|-> (pos 6 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 6 9, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M"])

[<Test>]
let ``open declarations with duplication in signatures``() =
Expand All @@ -354,7 +367,7 @@ module M =
open System.Collections.Generic
open System.Collections.Generic
""", true)
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M"])

[<Test>]
let ``open declarations with global prefix in signatures``() =
Expand All @@ -367,4 +380,4 @@ module M =
open System
val x: int
""", true)
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"])
|-> (pos 8 9, ["System"; "System.IO"; "InternalModuleWithSuffix"; "OpenDeclarationsGetterTests.M"])

0 comments on commit b404159

Please sign in to comment.