[Pkg-cli-apps-commits] [fsharp] 37/60: Fix for #121: Unify build action conversion logic used by BuildActionConverter and BuildActionTypeConverter

Christopher Halse Rogers raof-guest at moszumanska.debian.org
Sun Sep 14 08:13:40 UTC 2014


This is an automated email from the git hooks/post-receive script.

raof-guest pushed a commit to branch master
in repository fsharp.

commit ed47354dda34d56d9468e94acc3b5e4d2741db2c
Author: latkin <latkin at microsoft.com>
Date:   Tue Aug 12 15:38:42 2014 -0700

    Fix for #121: Unify build action conversion logic used by BuildActionConverter and BuildActionTypeConverter
    
    Details, from Kevin:
    The issue was caused by interactions between BuildActionTypeConverter and BuildActionConverter.
    
    BuildActionConverter is used to map strings to BuildAction for use in the FSharp project system.
    BuildActionTypeConverter is used to map strings to VSLangProj.prjBuildAction for use by the VS infrastructure. BuildActionType converter knows nothing about BuildActions registered by the F# project system.
    
    The fix is to have the BuildActionTypeConverter delegate to BuildActionConverter to translate  VSLangProj.prjBuildAction to BuildActionsRegistered by the F# project system.
    
    Longer term, we should consider a cleanup activity to make the FSharpProjectSystem use VSLangProj.prjBuildAction rather than BuildAction (changeset 1316292)
---
 .../unittests/Tests.ProjectSystem.Miscellaneous.fs |  56 ++++++++-
 .../Common.Source.CSharp/Project/NodeProperties.cs | 136 +++++++++++++++------
 .../Common.Source.CSharp/Project/ProjectFactory.cs |   2 +-
 .../Common.Source.CSharp/Project/TypeConverters.cs |   9 ++
 4 files changed, 163 insertions(+), 40 deletions(-)

diff --git a/vsintegration/src/unittests/Tests.ProjectSystem.Miscellaneous.fs b/vsintegration/src/unittests/Tests.ProjectSystem.Miscellaneous.fs
index f6902cf..3383941 100644
--- a/vsintegration/src/unittests/Tests.ProjectSystem.Miscellaneous.fs
+++ b/vsintegration/src/unittests/Tests.ProjectSystem.Miscellaneous.fs
@@ -528,7 +528,9 @@ type Miscellaneous() =
             use project = project
             let values = project.BuildActionConverter.GetStandardValues()
             let list = values |> Seq.cast |> Seq.map (fun (ba : BuildAction)-> ba.Name) |> Seq.toList
-            let expected = ["Compile"; "Content"; "EmbeddedResource"; "None"; "MyBuildAction"; "MyBuildAction3"]
+            // expected list of build actions is union of standard actions, custom actions, and "extended" standard actions (populated from, e.g., WPF or Fakes)
+            // this is not exhaustive (exhaustive list is not static), but covers the main equivalence classes
+            let expected = ["Compile"; "Content"; "EmbeddedResource"; "None"; "MyBuildAction"; "MyBuildAction3"; "Resource"; "SplashScreen"; "Fakes"]
             if expected |> List.forall (fun i -> List.exists ((=)i) list) |> not then                
                 let s0 = sprintf "%A" expected
                 let s1 = sprintf "%A" list
@@ -537,6 +539,58 @@ type Miscellaneous() =
         )
 
     [<Test>]
+    member public this.TestBuildActionConversions () =
+
+        let replace (pattern:string) (replacement:string) (input:string) = Regex.Replace(input, pattern, replacement)
+
+        let getBuildableNodeProps project caption = 
+            let node = TheTests.FindNodeWithCaption (project, caption)
+            let props = node.CreatePropertiesObject()
+            props :?> BuildableNodeProperties
+
+        let checkNotStandardBuildAction buildAction = 
+            Assert.IsFalse(VSLangProj.prjBuildAction.prjBuildActionNone = buildAction, "Unexpected None match")
+            Assert.IsFalse(VSLangProj.prjBuildAction.prjBuildActionCompile = buildAction, "Unexpected Compile match")
+            Assert.IsFalse(VSLangProj.prjBuildAction.prjBuildActionContent = buildAction, "Unexpected Content match")
+            Assert.IsFalse(VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource = buildAction, "Unexpected EmbeddedResource match")
+
+        DoWithTempFile "Test.fsproj" (fun file ->
+            let text =
+                TheTests.FsprojTextWithProjectReferences(["Compile.fs"; "None.fs"; "Resource.fs"; "SplashSceen.fs"; "Dude.fs"],[],[],"")
+                |> replace "Compile\s+Include='([a-zA-Z]+)\.fs'" "$1 Include='$1.fs'"            
+            File.AppendAllText(file, text)
+            let sp, cnn = VsMocks.MakeMockServiceProviderAndConfigChangeNotifier()
+            let project = TheTests.CreateProject(file, "false", cnn, sp)
+            use project = project
+
+            // test proper behavior from project file
+            let node = getBuildableNodeProps project "Compile.fs"
+            Assert.IsTrue(node.BuildAction = VSLangProj.prjBuildAction.prjBuildActionCompile, "Compile build action failed")
+            Assert.IsTrue(node.ItemType = "Compile", "Compile item type failed")
+
+            let node = getBuildableNodeProps project "None.fs"
+            Assert.IsTrue(node.BuildAction = VSLangProj.prjBuildAction.prjBuildActionNone, "None build action failed")
+            Assert.IsTrue(node.ItemType = "None", "None item type failed")
+
+            let node = getBuildableNodeProps project "Resource.fs"
+            checkNotStandardBuildAction node.BuildAction
+            Assert.IsTrue(node.ItemType = "Resource", "Resource item type failed")
+
+            let node = getBuildableNodeProps project "Dude.fs"
+            checkNotStandardBuildAction node.BuildAction
+            Assert.IsTrue(node.ItemType = "Dude", "Dude item type failed")
+
+            // test handling of bogus values
+            node.BuildAction <- enum 100
+            Assert.IsTrue(node.BuildAction = VSLangProj.prjBuildAction.prjBuildActionNone, "Bogus build action not mapped to None")
+
+            node.ItemType <- "Wibble"
+            Assert.IsTrue(node.ItemType = "None", "Bogus item type not mapped to None")
+
+            ()
+        )
+
+    [<Test>]
     member this.``WildcardsInProjectFile.ThrowingCase`` () =
         DoWithTempFile "Test.fsproj"(fun file ->
             let text = TheTests.FsprojTextWithProjectReferences(["*.fs"],[],[],"")
diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/NodeProperties.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/NodeProperties.cs
index 338805f..47567cc 100644
--- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/NodeProperties.cs
+++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/NodeProperties.cs
@@ -6,10 +6,12 @@ using Microsoft.VisualStudio.Shell.Interop;
 using Microsoft.VisualStudio.Designer.Interfaces;
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
 using System.Globalization;
 using System.IO;
+using System.Linq;
 using System.Runtime.InteropServices;
 using System.Windows.Forms;
 using System.Xml;
@@ -464,7 +466,7 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
         {
             get
             {
-                var res = BuildActionTypeConverter.Instance.ConvertFromString(this.Node.ItemNode.ItemName);
+                var res = BuildActionTypeConverter.Instance.ConvertFromString(this.Node.ProjectMgr.BuildActionConverter, this.Node.ItemNode.ItemName);
                 if (res is VSLangProj.prjBuildAction)
                 {
                     return (VSLangProj.prjBuildAction)res;
@@ -473,7 +475,7 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
             }
             set
             {
-                this.Node.ItemNode.ItemName = BuildActionTypeConverter.Instance.ConvertToString(value);
+                this.Node.ItemNode.ItemName = BuildActionTypeConverter.Instance.ConvertToString(this.Node.ProjectMgr.BuildActionConverter, value);
             }
         }
 
@@ -483,11 +485,11 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
         {
             get 
             {
-                return BuildActionTypeConverter.Instance.ConvertToString(this.BuildAction);
+                return BuildActionTypeConverter.Instance.ConvertToString(this.Node.ProjectMgr.BuildActionConverter, this.BuildAction);
             }
             set
             {
-                var res = BuildActionTypeConverter.Instance.ConvertFromString(value);
+                var res = BuildActionTypeConverter.Instance.ConvertFromString(this.Node.ProjectMgr.BuildActionConverter, value);
                 if (res is VSLangProj.prjBuildAction)
                 {
                     this.BuildAction = (VSLangProj.prjBuildAction)res;
@@ -527,65 +529,123 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
 
         public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
         {
-            if (sourceType == typeof(string))
-            {
-                return true;
-            }
-            return base.CanConvertFrom(context, sourceType);
+            return (sourceType == typeof(string)) ? true : base.CanConvertFrom(context, sourceType);
         }
 
         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
         {
-            return base.CanConvertTo(context, destinationType);
+            return (destinationType == typeof(string)) ? true : base.CanConvertTo(context, destinationType);
         }
 
         public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
         {
             if (destinationType == typeof(string))
             {
-                switch ((VSLangProj.prjBuildAction)value)
-                {
-                    case VSLangProj.prjBuildAction.prjBuildActionCompile:
-                        return "Compile";
-                    case VSLangProj.prjBuildAction.prjBuildActionContent:
-                        return "Content";
-                    case VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource:
-                        return "EmbeddedResource";
-                    case VSLangProj.prjBuildAction.prjBuildActionNone:
-                        return "None";
-                }
+                var reply = ConvertToString(GetBuildActionConverter(context), value);
+                if (reply != null) return reply;
             }
             return base.ConvertTo(context, culture, value, destinationType);
         }
 
-        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+        public string ConvertToString(BuildActionConverter buildActionConverter, object value)
         {
-            if (value is string)
+            switch ((VSLangProj.prjBuildAction)value)
             {
-                string strVal = (string)value;
-                if (strVal.Equals("Compile", StringComparison.OrdinalIgnoreCase))
+            case VSLangProj.prjBuildAction.prjBuildActionCompile:
+                return "Compile";
+            case VSLangProj.prjBuildAction.prjBuildActionContent:
+                return "Content";
+            case VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource:
+                return "EmbeddedResource";
+            case VSLangProj.prjBuildAction.prjBuildActionNone:
+                return "None";
+            default:
+                if (buildActionConverter != null)
                 {
-                    return VSLangProj.prjBuildAction.prjBuildActionCompile;
-                }
-                else if (strVal.Equals("Content", StringComparison.OrdinalIgnoreCase))
-                {
-                    return VSLangProj.prjBuildAction.prjBuildActionContent;
+                    // Not standard buildAction, so must have been registered.
+                    // Convert it to the name of the BuildAction at position index in the StandardValues from the BuildActionConverter
+                    int index = (int)value;
+                    var actions = buildActionConverter.RegisteredBuildActions;
+                    if (index >= 0 && index < actions.Count)
+                    {
+                        return actions[index].Name;
+                    }
                 }
-                else if (strVal.Equals("EmbeddedResource", StringComparison.OrdinalIgnoreCase))
+                return "None";
+            }
+        }
+        
+        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+        {
+            if (value is string)
+            {
+                var reply = ConvertFromString(GetBuildActionConverter(context), (string)value);
+                if (reply != null) return reply;
+            }
+            return base.ConvertFrom(context, culture, value);
+        }
+
+        public object ConvertFromString(BuildActionConverter buildActionConverter, string value)
+        {
+            if (value.Equals("Compile", StringComparison.OrdinalIgnoreCase))
+            {
+                return VSLangProj.prjBuildAction.prjBuildActionCompile;
+            }
+            else if (value.Equals("Content", StringComparison.OrdinalIgnoreCase))
+            {
+                return VSLangProj.prjBuildAction.prjBuildActionContent;
+            }
+            else if (value.Equals("EmbeddedResource", StringComparison.OrdinalIgnoreCase))
+            {
+                return VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource;
+            }
+            else if (value.Equals("None", StringComparison.OrdinalIgnoreCase))
+            {
+                return VSLangProj.prjBuildAction.prjBuildActionNone;
+            }
+            else
+            {
+                if (buildActionConverter != null)
                 {
-                    return VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource;
+                    // Not standard buildAction, so must have been registered.
+                    // Convert it to the index in the StandardValues from the BuildActionConverter.
+                    var actions = buildActionConverter.RegisteredBuildActions;
+                    var reply = actions.ToList().FindIndex(i => value.Equals(i.Name, StringComparison.OrdinalIgnoreCase));
+                    if (reply != -1) return (VSLangProj.prjBuildAction)reply;
                 }
-                else if (strVal.Equals("None", StringComparison.OrdinalIgnoreCase))
+            }
+            return VSLangProj.prjBuildAction.prjBuildActionNone;
+        }
+
+        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+        {
+            var buildActionConverter = GetBuildActionConverter(context);
+            if(buildActionConverter != null)
+            {
+                var results = new List<VSLangProj.prjBuildAction>();
+                foreach (var a in buildActionConverter.RegisteredBuildActions)
                 {
-                    return VSLangProj.prjBuildAction.prjBuildActionNone;
+                    results.Add((VSLangProj.prjBuildAction)this.ConvertFrom(context, CultureInfo.CurrentUICulture, a.Name));
                 }
+                return new StandardValuesCollection(results);
+            }
+            else
+            {
+                return new StandardValuesCollection(new[] { VSLangProj.prjBuildAction.prjBuildActionNone, VSLangProj.prjBuildAction.prjBuildActionCompile, VSLangProj.prjBuildAction.prjBuildActionContent, VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource });
             }
-            return base.ConvertFrom(context, culture, value);
         }
 
-        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+        private static BuildActionConverter GetBuildActionConverter(ITypeDescriptorContext context)
         {
-            return new StandardValuesCollection(new[] { VSLangProj.prjBuildAction.prjBuildActionNone, VSLangProj.prjBuildAction.prjBuildActionCompile, VSLangProj.prjBuildAction.prjBuildActionContent, VSLangProj.prjBuildAction.prjBuildActionEmbeddedResource });
+            if (context != null)
+            {
+                BuildableNodeProperties nodeProperties = context.Instance as BuildableNodeProperties;
+                if (nodeProperties != null)
+                {
+                    return nodeProperties.Node.ProjectMgr.BuildActionConverter;
+                }
+            }
+            return null;
         }
     }
 
@@ -1553,4 +1613,4 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
         }
         #endregion
     }
-}
+}
\ No newline at end of file
diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectFactory.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectFactory.cs
index 3ca5e30..eeab5c4 100644
--- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectFactory.cs
+++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectFactory.cs
@@ -644,7 +644,7 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
                 {
                     //Now iterate through the project items and copy them to the new location
                     //All projects under the solution retain its folder hierarchy
-                    var types = new[] { "Compile", "None", "Content", "EmbeddedResource", "BaseApplicationManifest", "ApplicationDefinition", "Page" };
+                    var types = new[] { "Compile", "None", "Content", "EmbeddedResource", "Resource", "BaseApplicationManifest", "ApplicationDefinition", "Page" };
 
                     var metadataLookup =
                             convertedProject
diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/TypeConverters.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/TypeConverters.cs
index 42b67f2..fec88d2 100644
--- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/TypeConverters.cs
+++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/TypeConverters.cs
@@ -14,6 +14,7 @@ using System.Runtime.InteropServices;
 using System.Windows.Forms;
 using System.Xml;
 using System.Diagnostics;
+using System.Collections.ObjectModel;
 
 // NOTE:
 // When converting, System.TypeConverter.Convert* passes us CultureInfo.CurrentCulture - this is wrong!
@@ -143,6 +144,14 @@ namespace Microsoft.VisualStudio.FSharp.ProjectSystem
     {
         List<BuildAction> buildActions = new List<BuildAction>();
 
+        public ReadOnlyCollection<BuildAction> RegisteredBuildActions
+        {
+            get
+            {
+                return buildActions.AsReadOnly();
+            }
+        }
+
         public BuildActionConverter()
         {
             ResetBuildActionsToDefaults();

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-cli-apps/packages/fsharp.git



More information about the Pkg-cli-apps-commits mailing list