Skip to content

Commit 251a9ae

Browse files
Merge pull request #1766 from rainersigwald/item-case-sensitivity-1751
Item references should be case-insensitive
2 parents 133f88a + ae34471 commit 251a9ae

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

src/XMakeBuildEngine/Evaluation/LazyItemEvaluator.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ internal partial class LazyItemEvaluator<P, I, M, D>
4949
/// </summary>
5050
private static CompareInfo s_invariantCompareInfo = CultureInfo.InvariantCulture.CompareInfo;
5151

52-
private Dictionary<string, LazyItemList> _itemLists = new Dictionary<string, LazyItemList>();
52+
// MSBUILDUSECASESENSITIVEITEMNAMES is an escape hatch for the fix
53+
// for https://github.com/Microsoft/msbuild/issues/1751. It should
54+
// be removed (permanently set to false) after establishing that
55+
// it's unneeded (at least by the 16.0 timeframe).
56+
private Dictionary<string, LazyItemList> _itemLists = Environment.GetEnvironmentVariable("MSBUILDUSECASESENSITIVEITEMNAMES") == "1" ?
57+
new Dictionary<string, LazyItemList>() :
58+
new Dictionary<string, LazyItemList>(MSBuildNameIgnoreCaseComparer.Default);
5359

5460
public LazyItemEvaluator(IEvaluatorData<P, I, M, D> data, IItemFactory<I, I> itemFactory, BuildEventContext buildEventContext, ILoggingService loggingService)
5561
{
@@ -365,7 +371,10 @@ private class OperationBuilder
365371
public string ItemType { get; set; }
366372
public ItemSpec<P,I> ItemSpec { get; set; }
367373

368-
public ImmutableDictionary<string, LazyItemList>.Builder ReferencedItemLists { get; } = ImmutableDictionary.CreateBuilder<string, LazyItemList>();
374+
public ImmutableDictionary<string, LazyItemList>.Builder ReferencedItemLists { get; } = Environment.GetEnvironmentVariable("MSBUILDUSECASESENSITIVEITEMNAMES") == "1" ?
375+
ImmutableDictionary.CreateBuilder<string, LazyItemList>() :
376+
ImmutableDictionary.CreateBuilder<string, LazyItemList>(MSBuildNameIgnoreCaseComparer.Default);
377+
369378
public bool ConditionResult { get; set; }
370379

371380
public OperationBuilder(ProjectItemElement itemElement, bool conditionResult)

src/XMakeBuildEngine/UnitTests/Evaluation/Evaluator_Tests.cs

+114
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,68 @@ public void ItemPredecessorToItem()
13951395
Assert.Equal(null, metadatum.Predecessor.Predecessor);
13961396
}
13971397

1398+
[Fact]
1399+
public void ItemPredecessorToItemWithCaseChange()
1400+
{
1401+
string content = ObjectModelHelpers.CleanupFileContents(@"
1402+
<Project xmlns='msbuildnamespace' >
1403+
<ItemGroup>
1404+
<item_with_lowercase_name Include='h1'>
1405+
<m>1</m>
1406+
</item_with_lowercase_name>
1407+
<i Include='@(ITEM_WITH_LOWERCASE_NAME)'>
1408+
<m>2;%(m)</m>
1409+
</i>
1410+
</ItemGroup>
1411+
</Project>");
1412+
1413+
Project project = new Project(XmlReader.Create(new StringReader(content)));
1414+
1415+
ProjectMetadataElement metadataElementFromProjectRootElement =
1416+
project.Xml.Items.First().Metadata.First();
1417+
1418+
Assert.Collection(project.GetItems("i"), item =>
1419+
{
1420+
ProjectMetadata metadatum = item.GetMetadata("m");
1421+
1422+
Assert.Equal("2;1", metadatum.EvaluatedValue);
1423+
Assert.Equal("1", metadatum.Predecessor.EvaluatedValue);
1424+
Assert.Same(metadataElementFromProjectRootElement, metadatum.Predecessor.Xml);
1425+
1426+
Assert.Null(metadatum.Predecessor.Predecessor);
1427+
});
1428+
}
1429+
1430+
/// <summary>
1431+
/// Should be removed when escape hatch for #1751 is removed
1432+
/// </summary>
1433+
[Fact]
1434+
public void ItemPredecessorToItemWithCaseChangeAndEscapeHatch()
1435+
{
1436+
using (new Helpers.TemporaryEnvironment("MSBUILDUSECASESENSITIVEITEMNAMES", "1"))
1437+
{
1438+
string content = ObjectModelHelpers.CleanupFileContents(@"
1439+
<Project xmlns='msbuildnamespace' >
1440+
<ItemGroup>
1441+
<item_with_lowercase_name Include='h1'>
1442+
<m>1</m>
1443+
</item_with_lowercase_name>
1444+
<i Include='@(ITEM_WITH_LOWERCASE_NAME)'>
1445+
<m>2;%(m)</m>
1446+
</i>
1447+
</ItemGroup>
1448+
</Project>");
1449+
1450+
Project project = new Project(XmlReader.Create(new StringReader(content)));
1451+
1452+
ProjectMetadataElement metadataElementFromProjectRootElement =
1453+
project.Xml.Items.First().Metadata.First();
1454+
1455+
// empty because of the case mismatch
1456+
Assert.Collection(project.GetItems("i"));
1457+
}
1458+
}
1459+
13981460
/// <summary>
13991461
/// Predecessor of item is item via transform
14001462
/// </summary>
@@ -1421,6 +1483,58 @@ public void ItemPredecessorToItemViaTransform()
14211483
Assert.Equal(null, metadatum.Predecessor);
14221484
}
14231485

1486+
[Fact]
1487+
public void ItemPredecessorToItemViaTransformWithCaseChange()
1488+
{
1489+
string content = ObjectModelHelpers.CleanupFileContents(@"
1490+
<Project xmlns='msbuildnamespace' >
1491+
<ItemGroup>
1492+
<ITEM_WITH_UPPERCASE_NAME Include='h1'>
1493+
<m>1</m>
1494+
</ITEM_WITH_UPPERCASE_NAME>
1495+
<i Include=""@(item_with_uppercase_name->'%(identity)')"">
1496+
<m>2;%(m)</m>
1497+
</i>
1498+
</ItemGroup>
1499+
</Project>");
1500+
1501+
1502+
Project project = new Project(XmlReader.Create(new StringReader(content)));
1503+
1504+
Assert.Collection(project.GetItems("i"), item =>
1505+
{
1506+
Assert.Equal("h1", item.EvaluatedInclude);
1507+
});
1508+
}
1509+
1510+
/// <summary>
1511+
/// Should be removed when escape hatch for #1751 is removed
1512+
/// </summary>
1513+
[Fact]
1514+
public void ItemPredecessorToItemViaTransformWithCaseChangeWithEscapeHatch()
1515+
{
1516+
using (new Helpers.TemporaryEnvironment("MSBUILDUSECASESENSITIVEITEMNAMES", "1"))
1517+
{
1518+
string content = ObjectModelHelpers.CleanupFileContents(@"
1519+
<Project xmlns='msbuildnamespace' >
1520+
<ItemGroup>
1521+
<ITEM_WITH_UPPERCASE_NAME Include='h1'>
1522+
<m>1</m>
1523+
</ITEM_WITH_UPPERCASE_NAME>
1524+
<i Include=""@(item_with_uppercase_name->'%(identity)')"">
1525+
<m>2;%(m)</m>
1526+
</i>
1527+
</ItemGroup>
1528+
</Project>");
1529+
1530+
1531+
Project project = new Project(XmlReader.Create(new StringReader(content)));
1532+
1533+
// Should be empty because of the case mismatch
1534+
Assert.Collection(project.GetItems("i"));
1535+
}
1536+
}
1537+
14241538
/// <summary>
14251539
/// Item predecessors and imports
14261540
/// </summary>

0 commit comments

Comments
 (0)