@joebigelow / wix / commits / 6a3a695b

Ensure virtual symbols are included when overridden but not referenced

Rob Mensching committed Mar 8, 2024 at 13:58 UTC 6a3a695b5ac3758fbf4a7836f65d7f85fdd121e0
13 files changed +322 -156
src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs
+6 -6
@@ -125,7 +125,7 @@ namespace WixToolsetTest.UI
125 }, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray());
126 }
127
128 - [Fact(Skip = "Linker problem")]
128 + [Fact]
129 public void CanBuildUsingWixUIFeatureTree()
130 {
131 var folder = TestData.Get(@"TestData", "WixUI_FeatureTree");
@@ -161,7 +161,7 @@ namespace WixToolsetTest.UI
161 }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
162 }
163
164 - [Fact(Skip = "Linker problem")]
164 + [Fact]
165 public void CanBuildWithWixUIInstallDirWithCustomizedEula()
166 {
167 var folder = TestData.Get(@"TestData", "WixUI_InstallDir");
@@ -274,7 +274,7 @@ namespace WixToolsetTest.UI
274 }
275 }
276
277 - [Fact(Skip = "Linker problem")]
277 + [Fact]
278 public void CanBuildUsingWixUIMondo()
279 {
280 var folder = TestData.Get(@"TestData", "WixUI_Mondo");
@@ -307,7 +307,7 @@ namespace WixToolsetTest.UI
307 }, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray());
308 WixAssert.CompareLineByLine(new[]
309 {
310 - "InstallUISequence:WelcomeDlg\tInstalled AND PATCH\t1295",
310 + "InstallUISequence:WelcomeDlg\tNOT Installed OR PATCH\t1297",
311 }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
312 }
313
@@ -325,7 +325,7 @@ namespace WixToolsetTest.UI
325 }, results.Where(s => s.StartsWith("Control:ErrorDlg\tY")).Select(s => s.Split('\t')[9]).ToArray());
326 }
327
328 - [Fact(Skip = "Linker problem")]
328 + [Fact]
329 public void CanBuildWithInstallDirAndRemovedDialog()
330 {
331 var folder = TestData.Get(@"TestData", "InstallDir_NoLicense");
@@ -366,7 +366,7 @@ namespace WixToolsetTest.UI
366 }, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
367 }
368
369 - [Fact(Skip = "Linker problem")]
369 + [Fact]
370 public void CanBuildWithInstallDirAndAddedDialog()
371 {
372 var folder = TestData.Get(@"TestData", "InstallDir_SpecialDlg");
src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
+11 -36
@@ -45,10 +45,9 @@ namespace WixToolset.Core.Link
45 public ISet<IntermediateSymbol> IdenticalDirectorySymbols { get; private set; }
46
47 /// <summary>
48 - /// Gets the collection of overridden symbols that should not be included
49 - /// in the final output.
48 + /// Gets the collection of symbols that are marked as overrides.
49 /// </summary>
51 - public ISet<IntermediateSymbol> OverriddenSymbols { get; private set; }
50 + public IReadOnlyCollection<SymbolWithSection> OverrideSymbols { get; private set; }
51
52 public void Execute()
53 {
@@ -56,7 +55,6 @@ namespace WixToolset.Core.Link
55 var possibleConflicts = new HashSet<SymbolWithSection>();
56 var identicalDirectorySymbols = new HashSet<IntermediateSymbol>();
57 var overrideSymbols = new List<SymbolWithSection>();
59 - var overriddenSymbols = new HashSet<IntermediateSymbol>();
58
59 if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType))
60 {
@@ -92,34 +90,15 @@ namespace WixToolset.Core.Link
90
91 if (!symbolsByName.TryGetValue(fullName, out var existingSymbol))
92 {
95 - if (symbolWithSection.Access == AccessModifier.Override)
96 - {
97 - overrideSymbols.Add(symbolWithSection);
98 - }
99 -
93 symbolsByName.Add(fullName, symbolWithSection);
94 }
102 - else // uh-oh, duplicate symbols.
95 + else // duplicate symbol ids MAY be a problem, but not always (e.g. identical directories and virtual symbols that get overridden) so we do NOT report errors here.
96 {
104 - if (AccessModifier.Virtual == existingSymbol.Access && AccessModifier.Override == symbolWithSection.Access)
105 - {
106 - symbolWithSection.OverrideVirtualSymbol(existingSymbol);
107 - symbolsByName[fullName] = symbolWithSection; // replace the virtual symbol with the override symbol.
108 -
109 - overrideSymbols.Add(symbolWithSection);
110 - overriddenSymbols.Add(existingSymbol.Symbol);
111 - }
112 - else if (AccessModifier.Override == existingSymbol.Access && AccessModifier.Virtual == symbolWithSection.Access)
113 - {
114 - existingSymbol.OverrideVirtualSymbol(symbolWithSection);
115 -
116 - overriddenSymbols.Add(symbolWithSection.Symbol);
117 - }
97 // If the duplicate symbols are both private directories, there is a chance that they
98 // point to identical symbols. Identical directory symbols are redundant and will not cause
99 // conflicts.
121 - else if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access &&
122 - SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol))
100 + if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access &&
101 + SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol))
102 {
103 // Ensure identical symbols are tracked to ensure that only one symbol will end up in linked intermediate.
104 identicalDirectorySymbols.Add(existingSymbol.Symbol);
@@ -129,25 +108,21 @@ namespace WixToolset.Core.Link
108 {
109 symbolWithSection.AddPossibleConflict(existingSymbol);
110 existingSymbol.AddPossibleConflict(symbolWithSection);
132 - possibleConflicts.Add(symbolWithSection);
111 + possibleConflicts.Add(existingSymbol);
112 }
113 }
135 - }
136 - }
114
138 - // Ensure override symbols actually overrode a virtual symbol.
139 - foreach (var symbolWithSection in overrideSymbols)
140 - {
141 - if (symbolWithSection.Overrides is null)
142 - {
143 - this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol));
115 + if (symbolWithSection.Access == AccessModifier.Override)
116 + {
117 + overrideSymbols.Add(symbolWithSection);
118 + }
119 }
120 }
121
122 this.SymbolsByName = symbolsByName;
123 this.PossibleConflicts = possibleConflicts;
124 this.IdenticalDirectorySymbols = identicalDirectorySymbols;
150 - this.OverriddenSymbols = overriddenSymbols;
125 + this.OverrideSymbols = overrideSymbols;
126 }
127 }
128 }
src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs new
+159
@@ -0,0 +1,159 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Core.Link
4 +{
5 + using System.Collections.Generic;
6 + using System.Linq;
7 + using WixToolset.Data;
8 + using WixToolset.Data.Symbols;
9 + using WixToolset.Extensibility.Services;
10 +
11 + internal class ProcessConflictingSymbolsCommand
12 + {
13 + public ProcessConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, IReadOnlyCollection<SymbolWithSection> overrideSymbols, ISet<IntermediateSection> resolvedSections)
14 + {
15 + this.Messaging = messaging;
16 + this.PossibleConflicts = possibleConflicts;
17 + this.OverrideSymbols = overrideSymbols;
18 + this.ResolvedSections = resolvedSections;
19 + }
20 +
21 + private IMessaging Messaging { get; }
22 +
23 + private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
24 +
25 + private ISet<IntermediateSection> ResolvedSections { get; }
26 +
27 + private IReadOnlyCollection<SymbolWithSection> OverrideSymbols { get; }
28 +
29 + /// <summary>
30 + /// Gets the collection of overridden symbols that should not be included
31 + /// in the final output.
32 + /// </summary>
33 + public ISet<IntermediateSymbol> OverriddenSymbols { get; private set; }
34 +
35 + public void Execute()
36 + {
37 + var overriddenSymbols = new HashSet<IntermediateSymbol>();
38 +
39 + foreach (var symbolWithConflicts in this.PossibleConflicts)
40 + {
41 + var conflicts = YieldReferencedConflicts(symbolWithConflicts, this.ResolvedSections).ToList();
42 +
43 + if (conflicts.Count > 1)
44 + {
45 + IEnumerable<SymbolWithSection> reportDuplicates;
46 +
47 + var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
48 +
49 + // No virtual symbols, just plain old duplicate errors. This is the easy case.
50 + if (virtualConflicts.Count == 0)
51 + {
52 + var first = conflicts[0];
53 + reportDuplicates = conflicts.Skip(1);
54 +
55 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
56 +
57 + this.Messaging.Write(LinkerErrors.DuplicateSymbol(first.Symbol, referencingSourceLineNumber));
58 + }
59 + else // there are virtual symbols, which complicates conflict resolution and may not be an error at all.
60 + {
61 + var firstVirtualSymbol = virtualConflicts[0];
62 + var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
63 +
64 + // If there is a single virtual symbol, there may be a single override symbol to make this a success case.
65 + // All other scenarios are errors.
66 + if (virtualConflicts.Count == 1)
67 + {
68 + var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
69 +
70 + if (otherConflicts.Count > 0)
71 + {
72 + var first = otherConflicts[0];
73 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
74 +
75 + reportDuplicates = virtualConflicts;
76 +
77 + switch (first.Symbol)
78 + {
79 + case WixActionSymbol action:
80 + this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(action));
81 + break;
82 + default:
83 + this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
84 + break;
85 + }
86 + }
87 + else if (overrideConflicts.Count > 1) // multiple overrides report as normal duplicates.
88 + {
89 + var first = overrideConflicts[0];
90 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
91 +
92 + reportDuplicates = overrideConflicts.Skip(1);
93 +
94 + this.Messaging.Write(LinkerErrors.DuplicateSymbol(first.Symbol, referencingSourceLineNumber));
95 + }
96 + else // the single virtual symbol is overridden by a single override symbol. This is a success case.
97 + {
98 + var overrideSymbol = overrideConflicts[0];
99 +
100 + overriddenSymbols.Add(firstVirtualSymbol.Symbol);
101 +
102 + reportDuplicates = Enumerable.Empty<SymbolWithSection>();
103 + }
104 + }
105 + else // multiple symbols are virtual, use the duplicate virtual symbol message.
106 + {
107 + var first = virtualConflicts[0];
108 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
109 +
110 + reportDuplicates = virtualConflicts.Skip(1);
111 +
112 + this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
113 + }
114 +
115 + // Always point the override symbols at the first virtual symbol to prevent error being reported about missing overrides.
116 + // There may have been errors reported above, but there was at least one virtual symbol to satisfy the overrides so we
117 + // don't want extra errors in this case.
118 + foreach (var overrideSymbol in overrideConflicts)
119 + {
120 + overrideSymbol.OverrideVirtualSymbol(firstVirtualSymbol);
121 + }
122 + }
123 +
124 + foreach (var duplicate in reportDuplicates)
125 + {
126 + this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
127 + }
128 + }
129 + }
130 +
131 + // Ensure referenced override symbols actually overrode a virtual symbol.
132 + foreach (var referencedOverrideSymbol in this.OverrideSymbols.Where(s => this.ResolvedSections.Contains(s.Section)))
133 + {
134 + if (referencedOverrideSymbol.Overrides is null)
135 + {
136 + this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
137 + }
138 + }
139 +
140 + this.OverriddenSymbols = overriddenSymbols;
141 + }
142 +
143 + private static IEnumerable<SymbolWithSection> YieldReferencedConflicts(SymbolWithSection symbolWithConflicts, ISet<IntermediateSection> resolvedSections)
144 + {
145 + if (resolvedSections.Contains(symbolWithConflicts.Section))
146 + {
147 + yield return symbolWithConflicts;
148 + }
149 +
150 + foreach (var possibleConflict in symbolWithConflicts.PossiblyConflicts)
151 + {
152 + if (resolvedSections.Contains(possibleConflict.Section))
153 + {
154 + yield return possibleConflict;
155 + }
156 + }
157 + }
158 + }
159 +}
src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs deleted
-92
@@ -1,92 +0,0 @@
1 -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 -
3 -namespace WixToolset.Core.Link
4 -{
5 - using System.Collections.Generic;
6 - using System.Linq;
7 - using WixToolset.Data;
8 - using WixToolset.Data.Symbols;
9 - using WixToolset.Extensibility.Services;
10 -
11 - internal class ReportConflictingSymbolsCommand
12 - {
13 - public ReportConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, ISet<IntermediateSection> resolvedSections)
14 - {
15 - this.Messaging = messaging;
16 - this.PossibleConflicts = possibleConflicts;
17 - this.ResolvedSections = resolvedSections;
18 - }
19 -
20 - private IMessaging Messaging { get; }
21 -
22 - private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
23 -
24 - private ISet<IntermediateSection> ResolvedSections { get; }
25 -
26 - public void Execute()
27 - {
28 - // Do a quick check if there are any possibly conflicting symbols. Hopefully the symbols with possible conflicts
29 - // list is a very short list (empty should be the most common).
30 - //
31 - // If we have conflicts then we'll do a more costly check to see if the possible conflicting
32 - // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate
33 - // (aka: conflicting) symbol.
34 - if (0 < this.PossibleConflicts.Count)
35 - {
36 - foreach (var referencedDuplicate in this.PossibleConflicts.Where(s => this.ResolvedSections.Contains(s.Section)))
37 - {
38 - var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => this.ResolvedSections.Contains(s.Section)).ToList();
39 -
40 - if (actuallyReferencedDuplicates.Count > 0)
41 - {
42 - var conflicts = actuallyReferencedDuplicates.Append(referencedDuplicate).ToList();
43 - var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
44 - var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
45 - var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
46 -
47 - IEnumerable<SymbolWithSection> reportDuplicates = actuallyReferencedDuplicates;
48 -
49 - // If multiple symbols are virtual, use the duplicate virtual symbol message.
50 - if (virtualConflicts.Count > 1)
51 - {
52 - var first = virtualConflicts[0];
53 - var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
54 -
55 - reportDuplicates = virtualConflicts.Skip(1);
56 -
57 - this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
58 - }
59 - else if (virtualConflicts.Count == 1 && otherConflicts.Count > 0)
60 - {
61 - var first = otherConflicts[0];
62 - var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
63 -
64 - reportDuplicates = virtualConflicts;
65 -
66 - switch (first.Symbol)
67 - {
68 - case WixActionSymbol action:
69 - this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(action));
70 - break;
71 - default:
72 - this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
73 - break;
74 - }
75 - }
76 - else
77 - {
78 - var referencingSourceLineNumber = referencedDuplicate.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
79 -
80 - this.Messaging.Write(LinkerErrors.DuplicateSymbol(referencedDuplicate.Symbol, referencingSourceLineNumber));
81 - }
82 -
83 - foreach (var duplicate in reportDuplicates)
84 - {
85 - this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
86 - }
87 - }
88 - }
89 - }
90 - }
91 - }
92 -}
src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
+59 -4
@@ -76,6 +76,7 @@ namespace WixToolset.Core.Link
76 if (this.symbolsWithSections.TryGetValue(reference.SymbolicName, out var symbolWithSection))
77 {
78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
79 +
80 if (accessible.Count == 1)
81 {
82 var accessibleSymbol = accessible[0];
@@ -91,7 +92,7 @@ namespace WixToolset.Core.Link
92 {
93 this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName, symbolWithSection.Access));
94 }
94 - else // multiple symbols referenced creates conflicting symbols.
95 + else // multiple accessible symbols referenced creates conflicting symbols.
96 {
97 // Remember the direct reference to the symbol for the error reporting later,
98 // but do NOT continue resolving references found in these conflicting symbols.
@@ -122,7 +123,7 @@ namespace WixToolset.Core.Link
123 }
124
125 /// <summary>
125 - /// Determine if the symbol and any of its duplicates are accessbile by referencing section.
126 + /// Determine if the symbol and any of its duplicates are accessbile by the referencing section.
127 /// </summary>
128 /// <param name="referencingSection">Section referencing the symbol.</param>
129 /// <param name="symbolWithSection">Symbol being referenced.</param>
@@ -130,23 +131,77 @@ namespace WixToolset.Core.Link
131 private List<SymbolWithSection> DetermineAccessibleSymbols(IntermediateSection referencingSection, SymbolWithSection symbolWithSection)
132 {
133 var accessibleSymbols = new List<SymbolWithSection>();
134 + List<SymbolWithSection> virtualSymbols = null;
135
136 if (this.AccessibleSymbol(referencingSection, symbolWithSection))
137 {
136 - accessibleSymbols.Add(symbolWithSection);
138 + AddSymbolToCorrectCollection(symbolWithSection, accessibleSymbols, ref virtualSymbols);
139 }
140
141 foreach (var dupe in symbolWithSection.PossiblyConflicts)
142 {
143 if (this.AccessibleSymbol(referencingSection, dupe))
144 {
143 - accessibleSymbols.Add(dupe);
145 + AddSymbolToCorrectCollection(dupe, accessibleSymbols, ref virtualSymbols);
146 + }
147 + }
148 +
149 + // If a virtual symbol is accessible we have some extra work to do.
150 + if (virtualSymbols != null)
151 + {
152 + // If there are multiple virtual symbols accessible that's an error case so add them all and
153 + // they'll be reported as conflicts later.
154 + if (virtualSymbols.Count > 1)
155 + {
156 + accessibleSymbols.AddRange(virtualSymbols);
157 + }
158 + else
159 + {
160 + var overrode = false;
161 +
162 + // If there are any override symbols, skip adding the virtual symbols because they are "overridden".
163 + foreach (var overrideSymbol in accessibleSymbols.Where(symbol => symbol.Access == AccessModifier.Override))
164 + {
165 + overrideSymbol.OverrideVirtualSymbol(virtualSymbols[0]);
166 +
167 + overrode = true;
168 + }
169 +
170 + // If there are no overriding symbols, add the virtual symbol (there is only one but we'll add the collection just in case)
171 + // so it will be reported as a conflict later.
172 + if (!overrode)
173 + {
174 + accessibleSymbols.AddRange(virtualSymbols);
175 + }
176 }
177 }
178
179 return accessibleSymbols;
180 }
181
182 + /// <summary>
183 + /// Add a symbol to the correct collection based on its access.
184 + /// </summary>
185 + /// <param name="symbolWithSection"></param>
186 + /// <param name="accessibleSymbols">Collection of non-virtual symbol that was accessible.</param>
187 + /// <param name="virtualSymbols">Collection of virtual symbol that was accessible</param>
188 + private static void AddSymbolToCorrectCollection(SymbolWithSection symbolWithSection, List<SymbolWithSection> accessibleSymbols, ref List<SymbolWithSection> virtualSymbols)
189 + {
190 + if (symbolWithSection.Access == AccessModifier.Virtual)
191 + {
192 + if (virtualSymbols == null)
193 + {
194 + virtualSymbols = new List<SymbolWithSection>();
195 + }
196 +
197 + virtualSymbols.Add(symbolWithSection);
198 + }
199 + else
200 + {
201 + accessibleSymbols.Add(symbolWithSection);
202 + }
203 + }
204 +
205 /// <summary>
206 /// Determine if a single symbol is accessible by the referencing section.
207 /// </summary>
src/wix/WixToolset.Core/Linker.cs
+6 -3
@@ -190,10 +190,13 @@ namespace WixToolset.Core
190 }
191 }
192
193 - // Report duplicates that would ultimately end up being primary key collisions.
193 + // Process conflicts that may be overridden virtual symbols (that's okay) or end up as primary key collisions (those need to be reported as errors).
194 + ISet<IntermediateSymbol> overriddenSymbols;
195 {
195 - var reportDupes = new ReportConflictingSymbolsCommand(this.Messaging, find.PossibleConflicts, resolve.ResolvedSections);
196 + var reportDupes = new ProcessConflictingSymbolsCommand(this.Messaging, find.PossibleConflicts, find.OverrideSymbols, resolve.ResolvedSections);
197 reportDupes.Execute();
198 +
199 + overriddenSymbols = reportDupes.OverriddenSymbols;
200 }
201
202 if (this.Messaging.EncounteredError)
@@ -222,7 +225,7 @@ namespace WixToolset.Core
225 continue;
226 }
227 }
225 - else if (find.OverriddenSymbols.Contains(symbol))
228 + else if (overriddenSymbols.Contains(symbol))
229 {
230 // Skip the symbols that were overridden.
231 continue;
src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
+19 -6
@@ -62,6 +62,18 @@ namespace WixToolsetTest.CoreIntegration
62 }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Access.AsString() + ":" + d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
63 }
64
65 + [Fact]
66 + public void CanCompileVirtualSymbolThatDoesNotGetOverridden()
67 + {
68 + var dirSymbols = BuildToGetDirectorySymbols("TestData", "AccessModifier", "VirtualSymbolThatDoesNotGetOverridden.wxs");
69 + WixAssert.CompareLineByLine(new[]
70 + {
71 + "virtual:ProgramFilesFolder:TARGETDIR:PFiles",
72 + "virtual:TARGETDIR::SourceDir",
73 + "virtual:TestFolder:ProgramFilesFolder:Used",
74 + }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Access.AsString() + ":" + d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
75 + }
76 +
77 [Fact]
78 public void CannotCompileInvalidCrossFragmentReference()
79 {
@@ -78,8 +90,9 @@ namespace WixToolsetTest.CoreIntegration
90 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs");
91 WixAssert.CompareLineByLine(new[]
92 {
81 - "ln 12: Duplicate Directory with identifier 'TestFolder' referenced by <sourceFolder>\\DuplicateCrossFragmentReference.wxs(4). Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.",
82 - "ln 8: Location of symbol related to previous error."
93 + "ln 8: Duplicate Directory with identifier 'TestFolder' referenced by <sourceFolder>\\DuplicateCrossFragmentReference.wxs(4). Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.",
94 + "ln 12: Location of symbol related to previous error.",
95 + "ln 16: Location of symbol related to previous error."
96 }, errors);
97 }
98
@@ -99,8 +112,8 @@ namespace WixToolsetTest.CoreIntegration
112 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs");
113 WixAssert.CompareLineByLine(new[]
114 {
102 - "ln 14: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
103 - "ln 6: Location of symbol related to previous error."
115 + "ln 6: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
116 + "ln 14: Location of symbol related to previous error."
117 }, errors);
118 }
119
@@ -132,8 +145,8 @@ namespace WixToolsetTest.CoreIntegration
145 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatePublicOverrideVirtualSymbol.wxs");
146 WixAssert.CompareLineByLine(new[]
147 {
135 - "ln 14: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
136 - "ln 6: Location of symbol related to previous error."
148 + "ln 14: The Directory symbol 'TestFolder' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict.",
149 + "ln 10: Location of symbol related to previous error."
150 }, errors);
151 }
152
src/wix/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs
+11 -4
@@ -4,9 +4,9 @@ namespace WixToolsetTest.CoreIntegration
4 {
5 using System.IO;
6 using System.Linq;
7 + using WixInternal.Core.TestPackage;
8 using WixInternal.TestSupport;
9 using WixToolset.Core;
9 - using WixInternal.Core.TestPackage;
10 using WixToolset.Data;
11 using WixToolset.Data.Symbols;
12 using WixToolset.Extensibility.Data;
@@ -101,7 +101,7 @@ namespace WixToolsetTest.CoreIntegration
101 [Fact]
102 public void VariableRedefinitionIsAWarning()
103 {
104 - var folder = TestData.Get(@"TestData\Variables");
104 + var folder = TestData.Get(@"TestData", "Variables");
105
106 using (var fs = new DisposableFileSystem())
107 {
@@ -121,8 +121,15 @@ namespace WixToolsetTest.CoreIntegration
121
122 result.AssertSuccess();
123
124 - var warning = result.Messages.Where(message => message.Id == (int)WarningMessages.Ids.VariableDeclarationCollision);
125 - Assert.Single(warning);
124 + var warning = result.Messages.Where(m => m.Level == MessageLevel.Warning || m.Level == MessageLevel.Error)
125 + .Select(m => $"ln {m.SourceLineNumbers.LineNumber}: {m.Level.ToString().ToLowerInvariant()}: {m}".Replace(baseFolder, "<baseFolder>"))
126 + .ToArray();
127 + WixAssert.CompareLineByLine(new[]
128 + {
129 + "ln 5: warning: The variable 'Bar' with value 'Baz' was previously declared with value 'Bar'.",
130 + "ln 24: warning: It is no longer necessary to define the standard directory 'TARGETDIR'. Use the StandardDirectory element instead.",
131 + "ln 25: warning: It is no longer necessary to define the standard directory 'ProgramFilesFolder'. Use the StandardDirectory element instead."
132 + }, warning);
133 }
134 }
135
src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
+3 -4
@@ -102,10 +102,9 @@ namespace WixToolsetTest.CoreIntegration
102 .ToArray();
103 WixAssert.CompareLineByLine(new[]
104 {
105 - "ln 8: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
106 - "ln 7: Location of symbol related to previous error.",
107 - "ln 9: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
108 - "ln 7: Location of symbol related to previous error."
105 + "ln 7: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
106 + "ln 8: Location of symbol related to previous error.",
107 + "ln 9: Location of symbol related to previous error."
108 }, errors);
109 }
110 }
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicateCrossFragmentReference.wxs
+4
@@ -11,4 +11,8 @@
11 <Fragment>
12 <Directory Id="TestFolder" Name="Dupe 2" />
13 </Fragment>
14 +
15 + <Fragment>
16 + <Directory Id="TestFolder" Name="Dupe 3" />
17 + </Fragment>
18 </Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/OverrideVirtualSymbolWithFragments.wxs
+13
@@ -2,8 +2,21 @@
2 <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Package Name="Override Virtual Symbol With Fragments" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4 <DirectoryRef Id="TestFolder" />
5 +
6 + <PropertyRef Id="A" />
7 + <PropertyRef Id="B" />
8 </Package>
9
10 + <Fragment>
11 + <Property Id="A" Secure="true"/>
12 + <DirectoryRef Id="TestFolder" />
13 + </Fragment>
14 +
15 + <Fragment>
16 + <Property Id="B" Secure="true"/>
17 + <DirectoryRef Id="TestFolder" />
18 + </Fragment>
19 +
20 <Fragment>
21 <StandardDirectory Id="ProgramFilesFolder">
22 <Directory Id="override TestFolder" Name="Override Test Folder Includes Another" />
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolThatDoesNotGetOverridden.wxs new
+30
@@ -0,0 +1,30 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Package Name="Override Without Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4 + <PropertyRef Id="DoesGetReferenced" />
5 + </Package>
6 +
7 + <Fragment>
8 + <Property Id="DoesNotGetReferenced1" Value="Does Not Get Referenced" />
9 +
10 + <StandardDirectory Id="ProgramFilesFolder">
11 + <Directory Id="override TestFolder" Name="IsNotUsed1" />
12 + </StandardDirectory>
13 + </Fragment>
14 +
15 + <Fragment>
16 + <Property Id="DoesNotGetReferenced2" Value="Does Not Get Referenced" />
17 +
18 + <StandardDirectory Id="ProgramFilesFolder">
19 + <Directory Id="override TestFolder" Name="IsNotUsed2" />
20 + </StandardDirectory>
21 + </Fragment>
22 +
23 + <Fragment>
24 + <Property Id="DoesGetReferenced" Value="Is Referenced" />
25 +
26 + <StandardDirectory Id="ProgramFilesFolder">
27 + <Directory Id="virtual TestFolder" Name="Used" />
28 + </StandardDirectory>
29 + </Fragment>
30 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Variables/Package.wxs
+1 -1
@@ -22,7 +22,7 @@
22
23 <Fragment>
24 <Directory Id="override TARGETDIR" Name="SourceDir">
25 - <Directory Id="override ProgramFilesFolder">
25 + <Directory Id="ProgramFilesFolder">
26 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
27 </Directory>
28 </Directory>