diff --git a/Samples/Directory.Build.targets b/Samples/Directory.Build.targets index dd7fa89..ed1082d 100644 --- a/Samples/Directory.Build.targets +++ b/Samples/Directory.Build.targets @@ -64,6 +64,31 @@ + + + + + + + + + + @@ -84,6 +109,8 @@ + + \ No newline at end of file diff --git a/src/RoslynCodeTaskFactory.UnitTests/CodeTaskFactoryTests.cs b/src/RoslynCodeTaskFactory.UnitTests/CodeTaskFactoryTests.cs index f371815..29c824b 100644 --- a/src/RoslynCodeTaskFactory.UnitTests/CodeTaskFactoryTests.cs +++ b/src/RoslynCodeTaskFactory.UnitTests/CodeTaskFactoryTests.cs @@ -152,6 +152,21 @@ public void CodeLanguageFromTaskBody() TryLoadTaskBodyAndExpectSuccess("code", expectedCodeLanguage: "VB"); } + [Test] + public void CodeTypeClassIgnoresParameterGroupWarning() + { + TryLoadTaskBodyAndExpectSuccess( + taskBody: "code", + parameters: new[] + { + new TaskPropertyInfo("P", typeof(string), false, false), + }, + expectedWarningMessages: new[] + { + "Parameters are discovered through reflection for Type=\"Class\". Values specified in will be ignored.", + }); + } + [Test] public void CodeTypeFromTaskBody() { @@ -466,7 +481,8 @@ private void TryLoadTaskBodyAndExpectSuccess( ISet expectedNamespaces = null, string expectedCodeLanguage = null, CodeTaskFactoryCodeType? expectedCodeType = null, - string expectedSourceCode = null) + string expectedSourceCode = null, + IReadOnlyList expectedWarningMessages = null) { MockBuildEngine buildEngine = new MockBuildEngine(); @@ -478,6 +494,7 @@ private void TryLoadTaskBodyAndExpectSuccess( bool success = CodeTaskFactory.TryLoadTaskBody(log, TaskName, taskBody, parameters ?? new List(), out TaskInfo taskInfo); buildEngine.Errors.ShouldBe(new string[0]); + buildEngine.Warnings.ShouldBe(expectedWarningMessages ?? new string[0]); Assert.True(success); @@ -523,6 +540,8 @@ private sealed class MockBuildEngine : IBuildEngine public string ProjectFileOfTaskNode { get; } = String.Empty; + public IEnumerable Warnings => Events.OfType().Select(i => i.Message); + public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) { throw new NotSupportedException(); diff --git a/src/RoslynCodeTaskFactory/CodeTaskFactory.cs b/src/RoslynCodeTaskFactory/CodeTaskFactory.cs index 499df24..76f6021 100644 --- a/src/RoslynCodeTaskFactory/CodeTaskFactory.cs +++ b/src/RoslynCodeTaskFactory/CodeTaskFactory.cs @@ -187,6 +187,28 @@ public bool Initialize(string taskName, IDictionary pa TaskType = assembly.GetExportedTypes().FirstOrDefault(type => type.Name.Equals(taskName)); } + if (TaskType != null) + { + // Perform automatic parameter detection if the user supplied a class. + // This reduces the burden of the developer by not requiring them to + // manually specify . + // + if (taskInfo.CodeType == CodeTaskFactoryCodeType.Class) + { + PropertyInfo[] properties = TaskType.GetProperties(BindingFlags.Instance | BindingFlags.Public); + _parameters = new TaskPropertyInfo[properties.Length]; + for (int i = 0; i < properties.Length; i++) + { + PropertyInfo property = properties[i]; + _parameters[i] = new TaskPropertyInfo( + property.Name, + property.PropertyType, + property.GetCustomAttribute() != null, + property.GetCustomAttribute() != null); + } + } + } + AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve; // Initialization succeeded if we found a type matching the task name from the compiled assembly @@ -395,6 +417,13 @@ internal static bool TryLoadTaskBody(TaskLoggingHelper log, string taskName, str taskInfo.CodeType = codeType; } + // Warn that is ignored if any parameters are supplied when Type="Class". + // + if (taskInfo.CodeType == CodeTaskFactoryCodeType.Class && parameters.Any()) + { + log.LogWarningWithCodeFromResources("CodeTaskFactory_ParameterGroupIgnoredForCodeTypeClass"); + } + if (languageAttribute != null) { if (String.IsNullOrWhiteSpace(languageAttribute.Value)) diff --git a/src/RoslynCodeTaskFactory/Properties/Strings.Designer.cs b/src/RoslynCodeTaskFactory/Properties/Strings.Designer.cs index 828f2a8..9675260 100644 --- a/src/RoslynCodeTaskFactory/Properties/Strings.Designer.cs +++ b/src/RoslynCodeTaskFactory/Properties/Strings.Designer.cs @@ -159,6 +159,15 @@ internal static string CodeTaskFactory_NoSourceCode { } } + /// + /// Looks up a localized string similar to Parameters are discovered through reflection for Type="Class". Values specified in will be ignored.. + /// + internal static string CodeTaskFactory_ParameterGroupIgnoredForCodeTypeClass { + get { + return ResourceManager.GetString("CodeTaskFactory_ParameterGroupIgnoredForCodeTypeClass", resourceCulture); + } + } + /// /// Looks up a localized string similar to Waiting for debugger to attach ({0} PID {1}). Press enter to continue.... /// diff --git a/src/RoslynCodeTaskFactory/Properties/Strings.resx b/src/RoslynCodeTaskFactory/Properties/Strings.resx index f9e148b..2346bd6 100644 --- a/src/RoslynCodeTaskFactory/Properties/Strings.resx +++ b/src/RoslynCodeTaskFactory/Properties/Strings.resx @@ -159,6 +159,9 @@ MSB3428: You must specify source code within the Code element or a path to a file containing source code. {StrBegin="MSB3428: "} + + Parameters are discovered through reflection for Type="Class". Values specified in <ParameterGroup/> will be ignored. + Waiting for debugger to attach ({0} PID {1}). Press enter to continue...