[xbuild] Don't reevaluate project when setting metadata in a dynamic ..
authorAnkit Jain <ankit.jain@xamarin.com>
Thu, 10 Nov 2016 18:26:27 +0000 (13:26 -0500)
committerAnkit Jain <ankit.jain@xamarin.com>
Thu, 10 Nov 2016 23:20:36 +0000 (18:20 -0500)
commit387316fed644b1deeeeef0b385ae52b68aab3151
tree9d61a2bbceb64ad39c6aa38c0614491328f2b80c
parente29e5fd10478da5bdb61b2c6134c08bc99921049
[xbuild] Don't reevaluate project when setting metadata in a dynamic ..

.. item.

If we have a project, that sets some properties or items at runtime,
like in a target:

```
        <Target Name="Build">
                <PropertyGroup>
                        <Bar>Bar01</Bar>
                </PropertyGroup>
```

.. such a property can be accessed as `$(Bar)` subsequently.

Then at later point, a target tries to update metadata on an item group
with existing items, like:

```
<ItemGroup>
<FooItem Include="xyz" />
</ItemGroup>

<Target Name="Foo">
                <ItemGroup>
                        <FooItem>
                                <SomeMetadata>MetadataValue</SomeMetadata>
                        </FooItem>
                </ItemGroup>
```

.. then it is seen that the value for the earlier created `$(Bar)` disappears!
So, if we try to print the value of `$(Bar)` right after that item
group, it would appear as `''`!

The issue is that the metadata update in target `Foo` caused the project
to get re-evaluated, which meant that items/properites created after the
project load were lost! We should not be reevaluating the project when
setting metadata on the basis of dynamic items, like in the target
`Foo`.

These dynamic item groups in a target are represented as
`BuildItemTask`, and these create BuildItems which have their
`IsDynamic` property set. And this is used to avoid re-evaluating the
project in `BuildItem.SetMetadata`.

But when updating metadata (`BuildItem.UpdateMetadata`), we need to
update metadata on the *existing* items, which might not have been
created from such dynamic item groups! So, their `IsDynamic==false`.
Hence, trying to `SetMetadata` on such items would cause the project to
be reevaluated, and thus properties/items like `$(Bar)` would be lost!

Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=45137

In this particular case, `Bar` was the `DesignTimeBuild` property, which
was losing it's value when `ProjectReference`'s `AdditionalProperties`
metadata was set in:

```
 <Target Name="BclBuildAddProjectReferenceProperties"
    <ItemGroup>
      <ProjectReference>
         <AdditionalProperties>$(_BclBuildProjectReferenceProperties);%(ProjectReference.AdditionalProperties)</AdditionalProperties>
     </ProjectReference>
    </ItemGroup>
```
mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs
mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs