23
23
24
24
using TaskItem = Microsoft . Build . Execution . ProjectItemInstance . TaskItem ;
25
25
using Task = System . Threading . Tasks . Task ;
26
+ using System . Linq ;
26
27
27
28
#nullable disable
28
29
@@ -256,12 +257,12 @@ void ITaskExecutionHost.InitializeForTask(IBuildEngine2 buildEngine, TargetLoggi
256
257
257
258
TaskRequirements requirements = TaskRequirements . None ;
258
259
259
- if ( _taskFactoryWrapper . TaskFactoryLoadedType . HasSTAThreadAttribute ( ) )
260
+ if ( _taskFactoryWrapper . TaskFactoryLoadedType . HasSTAThreadAttribute )
260
261
{
261
262
requirements |= TaskRequirements . RequireSTAThread ;
262
263
}
263
264
264
- if ( _taskFactoryWrapper . TaskFactoryLoadedType . HasLoadInSeparateAppDomainAttribute ( ) )
265
+ if ( _taskFactoryWrapper . TaskFactoryLoadedType . HasLoadInSeparateAppDomainAttribute )
265
266
{
266
267
requirements |= TaskRequirements . RequireSeparateAppDomain ;
267
268
@@ -399,6 +400,14 @@ bool ITaskExecutionHost.GatherTaskOutputs(string parameterName, ElementLocation
399
400
try
400
401
{
401
402
TaskPropertyInfo parameter = _taskFactoryWrapper . GetProperty ( parameterName ) ;
403
+ foreach ( TaskPropertyInfo prop in _taskFactoryWrapper . TaskFactoryLoadedType . Properties )
404
+ {
405
+ if ( prop . Name . Equals ( parameterName , StringComparison . OrdinalIgnoreCase ) )
406
+ {
407
+ parameter = prop ;
408
+ break ;
409
+ }
410
+ }
402
411
403
412
// flag an error if we find a parameter that has no .NET property equivalent
404
413
ProjectErrorUtilities . VerifyThrowInvalidProject
@@ -420,17 +429,14 @@ bool ITaskExecutionHost.GatherTaskOutputs(string parameterName, ElementLocation
420
429
_taskName
421
430
) ;
422
431
423
- // grab the outputs from the task's designated output parameter (which is a .NET property)
424
- Type type = parameter . PropertyType ;
425
-
426
432
EnsureParameterInitialized ( parameter , _batchBucket . Lookup ) ;
427
433
428
- if ( TaskParameterTypeVerifier . IsAssignableToITask ( type ) )
434
+ if ( parameter . IsAssignableToITask )
429
435
{
430
436
ITaskItem [ ] outputs = GetItemOutputs ( parameter ) ;
431
437
GatherTaskItemOutputs ( outputTargetIsItem , outputTargetName , outputs , parameterLocation , parameter ) ;
432
438
}
433
- else if ( TaskParameterTypeVerifier . IsValueTypeOutputParameter ( type ) )
439
+ else if ( parameter . IsValueTypeOutputParameter )
434
440
{
435
441
string [ ] outputs = GetValueOutputs ( parameter ) ;
436
442
GatherArrayStringAndValueOutputs ( outputTargetIsItem , outputTargetName , outputs , parameterLocation , parameter ) ;
@@ -897,12 +903,14 @@ private TaskFactoryWrapper FindTaskInRegistry(IDictionary<string, string> taskId
897
903
// Map to an intrinsic task, if necessary.
898
904
if ( String . Equals ( returnClass . TaskFactory . TaskType . FullName , "Microsoft.Build.Tasks.MSBuild" , StringComparison . OrdinalIgnoreCase ) )
899
905
{
900
- returnClass = new TaskFactoryWrapper ( new IntrinsicTaskFactory ( typeof ( MSBuild ) ) , new LoadedType ( typeof ( MSBuild ) , AssemblyLoadInfo . Create ( typeof ( TaskExecutionHost ) . GetTypeInfo ( ) . Assembly . FullName , null ) ) , _taskName , null ) ;
906
+ Assembly taskExecutionHostAssembly = typeof ( TaskExecutionHost ) . GetTypeInfo ( ) . Assembly ;
907
+ returnClass = new TaskFactoryWrapper ( new IntrinsicTaskFactory ( typeof ( MSBuild ) ) , new LoadedType ( typeof ( MSBuild ) , AssemblyLoadInfo . Create ( taskExecutionHostAssembly . FullName , null ) , taskExecutionHostAssembly ) , _taskName , null ) ;
901
908
_intrinsicTasks [ _taskName ] = returnClass ;
902
909
}
903
910
else if ( String . Equals ( returnClass . TaskFactory . TaskType . FullName , "Microsoft.Build.Tasks.CallTarget" , StringComparison . OrdinalIgnoreCase ) )
904
911
{
905
- returnClass = new TaskFactoryWrapper ( new IntrinsicTaskFactory ( typeof ( CallTarget ) ) , new LoadedType ( typeof ( CallTarget ) , AssemblyLoadInfo . Create ( typeof ( TaskExecutionHost ) . GetTypeInfo ( ) . Assembly . FullName , null ) ) , _taskName , null ) ;
912
+ Assembly taskExecutionHostAssembly = typeof ( TaskExecutionHost ) . GetTypeInfo ( ) . Assembly ;
913
+ returnClass = new TaskFactoryWrapper ( new IntrinsicTaskFactory ( typeof ( CallTarget ) ) , new LoadedType ( typeof ( CallTarget ) , AssemblyLoadInfo . Create ( taskExecutionHostAssembly . FullName , null ) , taskExecutionHostAssembly ) , _taskName , null ) ;
906
914
_intrinsicTasks [ _taskName ] = returnClass ;
907
915
}
908
916
}
@@ -1008,12 +1016,43 @@ out bool parameterSet
1008
1016
try
1009
1017
{
1010
1018
// check if the task has a .NET property corresponding to the parameter
1011
- TaskPropertyInfo parameter = _taskFactoryWrapper . GetProperty ( parameterName ) ;
1019
+ LoadedType loadedType = _taskFactoryWrapper . TaskFactoryLoadedType ;
1020
+ int indexOfParameter = - 1 ;
1021
+ for ( int i = 0 ; i < loadedType . Properties . Length ; i ++ )
1022
+ {
1023
+ if ( loadedType . Properties [ i ] . Name . Equals ( parameterName ) )
1024
+ {
1025
+ indexOfParameter = i ;
1026
+ break ;
1027
+ }
1028
+ }
1012
1029
1013
- if ( parameter != null )
1030
+ // For most tasks, finding the parameter in our list of known properties is equivalent to
1031
+ // saying the task was properly invoked, as far as this parameter is concerned. However,
1032
+ // that is not true for CodeTaskFactories like RoslynCodeTaskFactory. In that case, they
1033
+ // will often have a list of parameters under the UsingTask declaration. Fortunately, if
1034
+ // your TaskFactory is RoslynCodeTaskFactory, it isn't TaskHostFactory, which means the
1035
+ // types are fully loaded at this stage, and we can access them as we had in the past.
1036
+ TaskPropertyInfo parameter = null ;
1037
+ Type parameterType = null ;
1038
+ if ( indexOfParameter != - 1 )
1039
+ {
1040
+ parameter = loadedType . Properties [ indexOfParameter ] ;
1041
+ parameterType = Type . GetType (
1042
+ loadedType . PropertyAssemblyQualifiedNames ? [ indexOfParameter ] ??
1043
+ parameter . PropertyType . AssemblyQualifiedName ) ;
1044
+ }
1045
+ else
1014
1046
{
1015
- Type parameterType = parameter . PropertyType ;
1047
+ parameter = _taskFactoryWrapper . GetProperty ( parameterName ) ;
1048
+ if ( parameter != null )
1049
+ {
1050
+ parameterType = Type . GetType ( parameter . PropertyType . AssemblyQualifiedName ) ;
1051
+ }
1052
+ }
1016
1053
1054
+ if ( parameter != null )
1055
+ {
1017
1056
EnsureParameterInitialized ( parameter , _batchBucket . Lookup ) ;
1018
1057
1019
1058
// try to set the parameter
@@ -1068,30 +1107,15 @@ out parameterSet
1068
1107
else
1069
1108
{
1070
1109
// flag an error if we find a parameter that has no .NET property equivalent
1071
- if ( _taskFactoryWrapper . TaskFactoryLoadedType . LoadedAssembly is null )
1072
- {
1073
- _taskLoggingContext . LogError
1074
- (
1075
- new BuildEventFileInfo ( parameterLocation ) ,
1076
- "UnexpectedTaskAttribute" ,
1077
- parameterName ,
1078
- _taskName ,
1079
- _taskFactoryWrapper . TaskFactoryLoadedType . Type . Assembly . FullName ,
1080
- _taskFactoryWrapper . TaskFactoryLoadedType . Type . Assembly . Location
1081
- ) ;
1082
- }
1083
- else
1084
- {
1085
- _taskLoggingContext . LogError
1086
- (
1087
- new BuildEventFileInfo ( parameterLocation ) ,
1088
- "UnexpectedTaskAttribute" ,
1089
- parameterName ,
1090
- _taskName ,
1091
- _taskFactoryWrapper . TaskFactoryLoadedType . LoadedAssembly . FullName ,
1092
- _taskFactoryWrapper . TaskFactoryLoadedType . LoadedAssembly . Location
1093
- ) ;
1094
- }
1110
+ _taskLoggingContext . LogError
1111
+ (
1112
+ new BuildEventFileInfo ( parameterLocation ) ,
1113
+ "UnexpectedTaskAttribute" ,
1114
+ parameterName ,
1115
+ _taskName ,
1116
+ _taskFactoryWrapper . TaskFactoryLoadedType . LoadedAssemblyName . FullName ,
1117
+ _taskFactoryWrapper . TaskFactoryLoadedType . Path
1118
+ ) ;
1095
1119
}
1096
1120
}
1097
1121
catch ( AmbiguousMatchException )
0 commit comments