aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/wix/WixToolset.Data/ErrorMessages.cs17
-rw-r--r--src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs6
-rw-r--r--src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs61
-rw-r--r--src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs57
-rw-r--r--src/wix/WixToolset.Core/Link/SymbolWithSection.cs21
-rw-r--r--src/wix/WixToolset.Core/LinkerErrors.cs68
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs41
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs14
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs2
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs17
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs13
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs12
12 files changed, 251 insertions, 78 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs
index 889d1762..e149d54a 100644
--- a/src/api/wix/WixToolset.Data/ErrorMessages.cs
+++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs
@@ -323,21 +323,6 @@ namespace WixToolset.Data
323 return Message(null, Ids.DuplicateSourcesForOutput, "Multiple source files ({0}) have resulted in the same output file '{1}'. This is likely because the source files only differ in extension or path. Rename the source files to avoid this problem.", sourceList, outputFile); 323 return Message(null, Ids.DuplicateSourcesForOutput, "Multiple source files ({0}) have resulted in the same output file '{1}'. This is likely because the source files only differ in extension or path. Rename the source files to avoid this problem.", sourceList, outputFile);
324 } 324 }
325 325
326 public static Message DuplicateSymbol(SourceLineNumber sourceLineNumbers, string symbolName)
327 {
328 return Message(sourceLineNumbers, Ids.DuplicateSymbol, "Duplicate symbol '{0}' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", symbolName);
329 }
330
331 public static Message DuplicateSymbol(SourceLineNumber sourceLineNumbers, string symbolName, string referencingSourceLineNumber)
332 {
333 return Message(sourceLineNumbers, Ids.DuplicateSymbol, "Duplicate symbol '{0}' referenced by {1}. This typically means that an Id is duplicated. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.", symbolName, referencingSourceLineNumber);
334 }
335
336 public static Message DuplicateSymbol2(SourceLineNumber sourceLineNumbers)
337 {
338 return Message(sourceLineNumbers, Ids.DuplicateSymbol2, "Location of symbol related to previous error.");
339 }
340
341 public static Message DuplicateTransform(string transform) 326 public static Message DuplicateTransform(string transform)
342 { 327 {
343 return Message(null, Ids.DuplicateTransform, "The transform {0} was included twice on the command line. Each transform can be applied to a patch only once.", transform); 328 return Message(null, Ids.DuplicateTransform, "The transform {0} was included twice on the command line. Each transform can be applied to a patch only once.", transform);
@@ -2369,8 +2354,6 @@ namespace WixToolset.Data
2369 InvalidDateTimeFormat = 88, 2354 InvalidDateTimeFormat = 88,
2370 MultipleEntrySections = 89, 2355 MultipleEntrySections = 89,
2371 MultipleEntrySections2 = 90, 2356 MultipleEntrySections2 = 90,
2372 DuplicateSymbol = 91,
2373 DuplicateSymbol2 = 92,
2374 MissingEntrySection = 93, 2357 MissingEntrySection = 93,
2375 UnresolvedReference = 94, 2358 UnresolvedReference = 94,
2376 MultiplePrimaryReferences = 95, 2359 MultiplePrimaryReferences = 95,
diff --git a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
index e614d4eb..f9d6ab59 100644
--- a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
+++ b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
@@ -36,7 +36,7 @@ namespace WixToolset.Core.Link
36 /// <summary> 36 /// <summary>
37 /// Gets the collection of possibly conflicting symbols. 37 /// Gets the collection of possibly conflicting symbols.
38 /// </summary> 38 /// </summary>
39 public IEnumerable<SymbolWithSection> PossibleConflicts { get; private set; } 39 public IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; private set; }
40 40
41 /// <summary> 41 /// <summary>
42 /// Gets the collection of redundant symbols that should not be included 42 /// Gets the collection of redundant symbols that should not be included
@@ -140,9 +140,7 @@ namespace WixToolset.Core.Link
140 { 140 {
141 if (symbolWithSection.Overrides is null) 141 if (symbolWithSection.Overrides is null)
142 { 142 {
143 var fullName = symbolWithSection.GetFullName(); 143 this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol));
144
145 this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol.SourceLineNumbers, fullName));
146 } 144 }
147 } 145 }
148 146
diff --git a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs
index 3a07d366..2851fa60 100644
--- a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs
+++ b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs
@@ -9,7 +9,7 @@ namespace WixToolset.Core.Link
9 9
10 internal class ReportConflictingSymbolsCommand 10 internal class ReportConflictingSymbolsCommand
11 { 11 {
12 public ReportConflictingSymbolsCommand(IMessaging messaging, IEnumerable<SymbolWithSection> possibleConflicts, IEnumerable<IntermediateSection> resolvedSections) 12 public ReportConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, ISet<IntermediateSection> resolvedSections)
13 { 13 {
14 this.Messaging = messaging; 14 this.Messaging = messaging;
15 this.PossibleConflicts = possibleConflicts; 15 this.PossibleConflicts = possibleConflicts;
@@ -18,35 +18,62 @@ namespace WixToolset.Core.Link
18 18
19 private IMessaging Messaging { get; } 19 private IMessaging Messaging { get; }
20 20
21 private IEnumerable<SymbolWithSection> PossibleConflicts { get; } 21 private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
22 22
23 private IEnumerable<IntermediateSection> ResolvedSections { get; } 23 private ISet<IntermediateSection> ResolvedSections { get; }
24 24
25 public void Execute() 25 public void Execute()
26 { 26 {
27 // Do a quick check if there are any possibly conflicting symbols that don't come from tables that allow 27 // Do a quick check if there are any possibly conflicting symbols. Hopefully the symbols with possible conflicts
28 // overriding. Hopefully the symbols with possible conflicts list is usually very short list (empty should 28 // list is a very short list (empty should be the most common).
29 // be the most common). If we find any matches, we'll do a more costly check to see if the possible conflicting 29 //
30 // If we have conflicts then we'll do a more costly check to see if the possible conflicting
30 // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate 31 // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate
31 // (aka: conflicting) symbol. 32 // (aka: conflicting) symbol.
32 var illegalDuplicates = this.PossibleConflicts.Where(s => s.Symbol.Definition.Type != SymbolDefinitionType.WixAction && s.Symbol.Definition.Type != SymbolDefinitionType.WixVariable).ToList(); 33 if (0 < this.PossibleConflicts.Count)
33 if (0 < illegalDuplicates.Count)
34 { 34 {
35 var referencedSections = new HashSet<IntermediateSection>(this.ResolvedSections); 35 foreach (var referencedDuplicate in this.PossibleConflicts.Where(s => this.ResolvedSections.Contains(s.Section)))
36
37 foreach (var referencedDuplicate in illegalDuplicates.Where(s => referencedSections.Contains(s.Section)))
38 { 36 {
39 var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => referencedSections.Contains(s.Section)).ToList(); 37 var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => this.ResolvedSections.Contains(s.Section)).ToList();
40 38
41 if (actuallyReferencedDuplicates.Any()) 39 if (actuallyReferencedDuplicates.Count > 0)
42 { 40 {
43 var fullName = referencedDuplicate.GetFullName(); 41 var conflicts = actuallyReferencedDuplicates.Append(referencedDuplicate).ToList();
42 var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
43 var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
44 var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
45
46 IEnumerable<SymbolWithSection> reportDuplicates = actuallyReferencedDuplicates;
47
48 // If multiple symbols are virtual, use the duplicate virtual symbol message.
49 if (virtualConflicts.Count > 1)
50 {
51 var first = virtualConflicts[0];
52 var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
44 53
45 this.Messaging.Write(ErrorMessages.DuplicateSymbol(referencedDuplicate.Symbol.SourceLineNumbers, fullName)); 54 reportDuplicates = virtualConflicts.Skip(1);
55
56 this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
57 }
58 else if (virtualConflicts.Count == 1 && otherConflicts.Count > 0)
59 {
60 var first = otherConflicts[0];
61 var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
62
63 reportDuplicates = virtualConflicts;
64
65 this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
66 }
67 else
68 {
69 var referencingSourceLineNumber = referencedDuplicate.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
70
71 this.Messaging.Write(LinkerErrors.DuplicateSymbol(referencedDuplicate.Symbol, referencingSourceLineNumber));
72 }
46 73
47 foreach (var duplicate in actuallyReferencedDuplicates) 74 foreach (var duplicate in reportDuplicates)
48 { 75 {
49 this.Messaging.Write(ErrorMessages.DuplicateSymbol2(duplicate.Symbol.SourceLineNumbers)); 76 this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
50 } 77 }
51 } 78 }
52 } 79 }
diff --git a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
index 0edbf39c..0e7a7a52 100644
--- a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
+++ b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
@@ -27,9 +27,9 @@ namespace WixToolset.Core.Link
27 this.BuildingMergeModule = (SectionType.Module == entrySection.Type); 27 this.BuildingMergeModule = (SectionType.Module == entrySection.Type);
28 } 28 }
29 29
30 public IEnumerable<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols; 30 public IReadOnlyCollection<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols;
31 31
32 public IEnumerable<IntermediateSection> ResolvedSections => this.resolvedSections; 32 public ISet<IntermediateSection> ResolvedSections => this.resolvedSections;
33 33
34 private bool BuildingMergeModule { get; } 34 private bool BuildingMergeModule { get; }
35 35
@@ -63,22 +63,25 @@ namespace WixToolset.Core.Link
63 // symbols provided. Then recursively call this method to process the 63 // symbols provided. Then recursively call this method to process the
64 // located symbol's section. All in all this is a very simple depth-first 64 // located symbol's section. All in all this is a very simple depth-first
65 // search of the references per-section. 65 // search of the references per-section.
66 foreach (var wixSimpleReferenceRow in section.Symbols.OfType<WixSimpleReferenceSymbol>()) 66 foreach (var reference in section.Symbols.OfType<WixSimpleReferenceSymbol>())
67 { 67 {
68 // If we're building a Merge Module, ignore all references to the Media table 68 // If we're building a Merge Module, ignore all references to the Media table
69 // because Merge Modules don't have Media tables. 69 // because Merge Modules don't have Media tables.
70 if (this.BuildingMergeModule && wixSimpleReferenceRow.Table == "Media") 70 if (this.BuildingMergeModule && reference.Table == "Media")
71 { 71 {
72 continue; 72 continue;
73 } 73 }
74 74
75 // See if the symbol (and any of its duplicates) are appropriately accessible. 75 // See if the symbol (and any of its duplicates) are appropriately accessible.
76 if (this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection)) 76 if (this.symbolsWithSections.TryGetValue(reference.SymbolicName, out var symbolWithSection))
77 { 77 {
78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection); 78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
79 if (accessible.Count == 1) 79 if (accessible.Count == 1)
80 { 80 {
81 var accessibleSymbol = accessible[0]; 81 var accessibleSymbol = accessible[0];
82
83 accessibleSymbol.AddDirectReference(reference);
84
82 if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section) 85 if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section)
83 { 86 {
84 this.RecursivelyResolveReferences(accessibleSymbol.Section); 87 this.RecursivelyResolveReferences(accessibleSymbol.Section);
@@ -86,32 +89,34 @@ namespace WixToolset.Core.Link
86 } 89 }
87 else if (accessible.Count == 0) 90 else if (accessible.Count == 0)
88 { 91 {
89 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access)); 92 this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName, symbolWithSection.Access));
90 } 93 }
91 else // display errors for the duplicate symbols. 94 else // multiple symbols referenced creates conflicting symbols.
92 { 95 {
93 var accessibleSymbol = accessible[0]; 96 // Remember the direct reference to the symbol for the error reporting later,
94 var accessibleFullName = accessibleSymbol.GetFullName(); 97 // but do NOT continue resolving references found in these conflicting symbols.
95 var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString(); 98 foreach (var conflict in accessible)
96
97 if (String.IsNullOrEmpty(referencingSourceLineNumber))
98 {
99 this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName));
100 }
101 else
102 { 99 {
103 this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName, referencingSourceLineNumber)); 100 // This should NEVER happen.
104 } 101 if (!conflict.PossiblyConflicts.Any())
102 {
103 throw new InvalidOperationException("If a reference can reference multiple symbols, those symbols MUST have already been recognized as possible conflicts.");
104 }
105 105
106 foreach (var accessibleDuplicate in accessible.Skip(1)) 106 conflict.AddDirectReference(reference);
107 { 107
108 this.Messaging.Write(ErrorMessages.DuplicateSymbol2(accessibleDuplicate.Symbol.SourceLineNumbers)); 108 this.referencedSymbols.Add(conflict);
109
110 if (conflict.Section != null)
111 {
112 this.resolvedSections.Add(conflict.Section);
113 }
109 } 114 }
110 } 115 }
111 } 116 }
112 else 117 else
113 { 118 {
114 this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName)); 119 this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName));
115 } 120 }
116 } 121 }
117 } 122 }
@@ -133,14 +138,6 @@ namespace WixToolset.Core.Link
133 138
134 foreach (var dupe in symbolWithSection.PossiblyConflicts) 139 foreach (var dupe in symbolWithSection.PossiblyConflicts)
135 { 140 {
136 //// don't count overridable WixActionSymbols
137 //var symbolAction = symbolWithSection.Symbol as WixActionSymbol;
138 //var dupeAction = dupe.Symbol as WixActionSymbol;
139 //if (symbolAction?.Overridable != dupeAction?.Overridable)
140 //{
141 // continue;
142 //}
143
144 if (this.AccessibleSymbol(referencingSection, dupe)) 141 if (this.AccessibleSymbol(referencingSection, dupe))
145 { 142 {
146 accessibleSymbols.Add(dupe); 143 accessibleSymbols.Add(dupe);
diff --git a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs
index 979aa44f..5bdf8360 100644
--- a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs
+++ b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs
@@ -6,12 +6,14 @@ namespace WixToolset.Core.Link
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq; 7 using System.Linq;
8 using WixToolset.Data; 8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
9 10
10 /// <summary> 11 /// <summary>
11 /// Symbol with section representing a single unique symbol. 12 /// Symbol with section representing a single unique symbol.
12 /// </summary> 13 /// </summary>
13 internal class SymbolWithSection 14 internal class SymbolWithSection
14 { 15 {
16 private List<WixSimpleReferenceSymbol> directReferences;
15 private HashSet<SymbolWithSection> possibleConflicts; 17 private HashSet<SymbolWithSection> possibleConflicts;
16 18
17 /// <summary> 19 /// <summary>
@@ -46,6 +48,11 @@ namespace WixToolset.Core.Link
46 /// <summary> 48 /// <summary>
47 /// Gets any duplicates of this symbol with sections that are possible conflicts. 49 /// Gets any duplicates of this symbol with sections that are possible conflicts.
48 /// </summary> 50 /// </summary>
51 public IEnumerable<WixSimpleReferenceSymbol> DirectReferences => this.directReferences ?? Enumerable.Empty<WixSimpleReferenceSymbol>();
52
53 /// <summary>
54 /// Gets any duplicates of this symbol with sections that are possible conflicts.
55 /// </summary>
49 public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>(); 56 public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>();
50 57
51 /// <summary> 58 /// <summary>
@@ -68,6 +75,20 @@ namespace WixToolset.Core.Link
68 } 75 }
69 76
70 /// <summary> 77 /// <summary>
78 /// Adds a reference that directly points to this symbol.
79 /// </summary>
80 /// <param name="reference">The direct reference.</param>
81 public void AddDirectReference(WixSimpleReferenceSymbol reference)
82 {
83 if (null == this.directReferences)
84 {
85 this.directReferences = new List<WixSimpleReferenceSymbol>();
86 }
87
88 this.directReferences.Add(reference);
89 }
90
91 /// <summary>
71 /// Override a virtual symbol. 92 /// Override a virtual symbol.
72 /// </summary> 93 /// </summary>
73 /// <param name="virtualSymbolWithSection">Virtual symbol with section that is being overridden.</param> 94 /// <param name="virtualSymbolWithSection">Virtual symbol with section that is being overridden.</param>
diff --git a/src/wix/WixToolset.Core/LinkerErrors.cs b/src/wix/WixToolset.Core/LinkerErrors.cs
index 78cd76f0..c234087e 100644
--- a/src/wix/WixToolset.Core/LinkerErrors.cs
+++ b/src/wix/WixToolset.Core/LinkerErrors.cs
@@ -11,6 +11,41 @@ namespace WixToolset.Core
11 return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue); 11 return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue);
12 } 12 }
13 13
14 public static Message DuplicateSymbol(IntermediateSymbol symbol)
15 {
16 return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "Duplicate {0} with identifier '{1}' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", symbol.Definition.Name, symbol.Id.Id);
17 }
18
19 public static Message DuplicateSymbol(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
20 {
21 if (referencingSourceLineNumber is null)
22 {
23 return DuplicateSymbol(symbol);
24 }
25
26 return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "Duplicate {0} with identifier '{1}' referenced by {2}. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
27 }
28
29 public static Message DuplicateVirtualSymbol(IntermediateSymbol symbol)
30 {
31 return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "The virtual {0} with identifier '{1}' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol?", symbol.Definition.Name, symbol.Id.Id);
32 }
33
34 public static Message DuplicateVirtualSymbol(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
35 {
36 if (referencingSourceLineNumber is null)
37 {
38 return DuplicateVirtualSymbol(symbol);
39 }
40
41 return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "The virtual {0} with identifier '{1}' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol? Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
42 }
43
44 public static Message DuplicateSymbol2(IntermediateSymbol symbol)
45 {
46 return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol2, "Location of symbol related to previous error.");
47 }
48
14 public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId) 49 public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId)
15 { 50 {
16 return Message(sourceLineNumbers, Ids.OrphanedPayload, "Found orphaned Payload '{0}'. Make sure to reference it from a Package, the BootstrapperApplication, or the Bundle or move it into its own Fragment so it only gets linked in when actually used.", payloadId); 51 return Message(sourceLineNumbers, Ids.OrphanedPayload, "Found orphaned Payload '{0}'. Make sure to reference it from a Package, the BootstrapperApplication, or the Bundle or move it into its own Fragment so it only gets linked in when actually used.", payloadId);
@@ -46,9 +81,34 @@ namespace WixToolset.Core
46 return Message(sourceLineNumbers, Ids.UncompressedPayloadInContainer, "The payload '{0}' is uncompressed and cannot be added to container '{1}'. Remove its Compressed attribute and provide a @SourceFile value to allow it to be added to a container.", payloadId, containerId); 81 return Message(sourceLineNumbers, Ids.UncompressedPayloadInContainer, "The payload '{0}' is uncompressed and cannot be added to container '{1}'. Remove its Compressed attribute and provide a @SourceFile value to allow it to be added to a container.", payloadId, containerId);
47 } 82 }
48 83
49 public static Message VirtualSymbolNotFoundForOverride(SourceLineNumber sourceLineNumbers, string id) 84 public static Message VirtualSymbolNotFoundForOverride(IntermediateSymbol symbol)
85 {
86 return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Could not find a virtual symbol to override with the {0} symbol '{1}'. Remove the override access modifier or include the code with the virtual symbol.", symbol.Definition.Name, symbol.Id.Id);
87 }
88
89 public static Message VirtualSymbolNotFoundForOverride(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
90 {
91 if (referencingSourceLineNumber is null)
92 {
93 return VirtualSymbolNotFoundForOverride(symbol);
94 }
95
96 return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Could not find a virtual symbol to override with the {0} symbol '{1}'. Remove the override access modifier or include the code with the virtual symbol. Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
97 }
98
99 public static Message VirtualSymbolMustBeOverridden(IntermediateSymbol symbol)
50 { 100 {
51 return Message(sourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Did not find virtual symbol for override symbol '{0}'",id); 101 return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolMustBeOverridden, "The {0} symbol '{1}' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict.", symbol.Definition.Name, symbol.Id.Id);
102 }
103
104 public static Message VirtualSymbolMustBeOverridden(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
105 {
106 if (referencingSourceLineNumber is null)
107 {
108 return VirtualSymbolMustBeOverridden(symbol);
109 }
110
111 return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolMustBeOverridden, "The {0} symbol '{1}' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict. Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
52 } 112 }
53 113
54 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) 114 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
@@ -58,6 +118,9 @@ namespace WixToolset.Core
58 118
59 public enum Ids 119 public enum Ids
60 { 120 {
121 DuplicateSymbol = 91,
122 DuplicateSymbol2 = 92,
123
61 OrphanedPayload = 7000, 124 OrphanedPayload = 7000,
62 PackageInMultipleContainers = 7001, 125 PackageInMultipleContainers = 7001,
63 PayloadSharedWithBA = 7002, 126 PayloadSharedWithBA = 7002,
@@ -67,6 +130,7 @@ namespace WixToolset.Core
67 BAContainerCannotContainRemotePayload = 7006, 130 BAContainerCannotContainRemotePayload = 7006,
68 DuplicateBindPathVariableOnCommandLine = 7007, 131 DuplicateBindPathVariableOnCommandLine = 7007,
69 VirtualSymbolNotFoundForOverride = 7008, 132 VirtualSymbolNotFoundForOverride = 7008,
133 VirtualSymbolMustBeOverridden = 7009,
70 } // last available is 7099. 7100 is WindowsInstallerBackendWarnings. 134 } // last available is 7099. 7100 is WindowsInstallerBackendWarnings.
71 } 135 }
72} 136}
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
index d0e31760..5e40114f 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
@@ -78,8 +78,8 @@ namespace WixToolsetTest.CoreIntegration
78 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs"); 78 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs");
79 WixAssert.CompareLineByLine(new[] 79 WixAssert.CompareLineByLine(new[]
80 { 80 {
81 @"ln 8: Duplicate symbol 'Directory:TestFolder' referenced by <sourceFolder>\DuplicateCrossFragmentReference.wxs(4). This typically means that an Id is duplicated. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.", 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 12: Location of symbol related to previous error." 82 "ln 8: Location of symbol related to previous error."
83 }, errors); 83 }, errors);
84 } 84 }
85 85
@@ -89,7 +89,7 @@ namespace WixToolsetTest.CoreIntegration
89 var errors = BuildForFailure("TestData", "AccessModifier", "OverrideWithoutVirtualSymbol.wxs"); 89 var errors = BuildForFailure("TestData", "AccessModifier", "OverrideWithoutVirtualSymbol.wxs");
90 WixAssert.CompareLineByLine(new[] 90 WixAssert.CompareLineByLine(new[]
91 { 91 {
92 "ln 5: Did not find virtual symbol for override symbol 'Directory:TestFolder'", 92 "ln 5: Could not find a virtual symbol to override with the Directory symbol 'TestFolder'. Remove the override access modifier or include the code with the virtual symbol.",
93 }, errors); 93 }, errors);
94 } 94 }
95 95
@@ -99,7 +99,40 @@ namespace WixToolsetTest.CoreIntegration
99 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs"); 99 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs");
100 WixAssert.CompareLineByLine(new[] 100 WixAssert.CompareLineByLine(new[]
101 { 101 {
102 "ln 14: Duplicate symbol 'Directory:TestFolder' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", 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."
104 }, errors);
105 }
106
107 [Fact]
108 public void CannotCompileDuplicatedVirtual()
109 {
110 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedVirtualSymbol.wxs");
111 WixAssert.CompareLineByLine(new[]
112 {
113 "ln 6: The virtual Directory with identifier 'TestFolder' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol?",
114 "ln 10: Location of symbol related to previous error."
115 }, errors);
116 }
117
118 [Fact]
119 public void CannotCompilePublicWithVirtualSymbol()
120 {
121 var errors = BuildForFailure("TestData", "AccessModifier", "VirtualSymbolWithoutOverride.wxs");
122 WixAssert.CompareLineByLine(new[]
123 {
124 "ln 9: 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.",
125 "ln 5: Location of symbol related to previous error."
126 }, errors);
127 }
128
129 [Fact]
130 public void CannotCompilePublicAndOverrideWithVirtualSymbol()
131 {
132 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatePublicOverrideVirtualSymbol.wxs");
133 WixAssert.CompareLineByLine(new[]
134 {
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.",
103 "ln 6: Location of symbol related to previous error." 136 "ln 6: Location of symbol related to previous error."
104 }, errors); 137 }, errors);
105 } 138 }
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
index 7bf10e3f..9931a45a 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
@@ -4,8 +4,8 @@ namespace WixToolsetTest.CoreIntegration
4{ 4{
5 using System.IO; 5 using System.IO;
6 using System.Linq; 6 using System.Linq;
7 using WixInternal.TestSupport;
8 using WixInternal.Core.TestPackage; 7 using WixInternal.Core.TestPackage;
8 using WixInternal.TestSupport;
9 using WixToolset.Data; 9 using WixToolset.Data;
10 using Xunit; 10 using Xunit;
11 11
@@ -97,8 +97,16 @@ namespace WixToolsetTest.CoreIntegration
97 "-o", msiPath 97 "-o", msiPath
98 }, out var messages); 98 }, out var messages);
99 99
100 Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol).Count()); 100 var errors = messages.Where(m => m.Level == MessageLevel.Error)
101 Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol2).Count()); 101 .Select(m => $"ln {m.SourceLineNumbers.LineNumber}: {m}".Replace(baseFolder, "<baseFolder>").Replace(folder, "<sourceFolder>"))
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."
109 }, errors);
102 } 110 }
103 } 111 }
104 112
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs
index 8d8ac801..54375f67 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs
@@ -66,7 +66,7 @@ namespace WixToolsetTest.CoreIntegration
66 66
67 WixAssert.CompareLineByLine(new[] 67 WixAssert.CompareLineByLine(new[]
68 { 68 {
69 "Duplicate symbol 'WixChainItem:collision' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", 69 "Duplicate WixChainItem with identifier 'collision' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
70 "Location of symbol related to previous error.", 70 "Location of symbol related to previous error.",
71 }, result.Messages.Select(m => m.ToString()).ToArray()); 71 }, result.Messages.Select(m => m.ToString()).ToArray());
72 72
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs
new file mode 100644
index 00000000..7ecf4445
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Package Name="Duplicated Override Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
5 <StandardDirectory Id="ProgramFilesFolder">
6 <Directory Id="override TestFolder" Name="Override Test Folder" />
7 </StandardDirectory>
8
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="virtual TestFolder" Name="Test Folder" />
11 </StandardDirectory>
12
13 <StandardDirectory Id="ProgramFilesFolder">
14 <Directory Id="TestFolder" Name="Collision Test Folder" />
15 </StandardDirectory>
16 </Package>
17</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs
new file mode 100644
index 00000000..e97d0b57
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Package Name="Duplicated Override Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
5 <StandardDirectory Id="ProgramFilesFolder">
6 <Directory Id="virtual TestFolder" Name="First Virtual Test Folder" />
7 </StandardDirectory>
8
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="virtual TestFolder" Name="Second Virtual Test Folder" />
11 </StandardDirectory>
12 </Package>
13</Wix>
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs
new file mode 100644
index 00000000..3db854f5
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs
@@ -0,0 +1,12 @@
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 <StandardDirectory Id="ProgramFilesFolder">
5 <Directory Id="virtual TestFolder" Name="Test Folder" />
6 </StandardDirectory>
7
8 <StandardDirectory Id="ProgramFilesFolder">
9 <Directory Id="TestFolder" Name="Missing Override Access Modifier" />
10 </StandardDirectory>
11 </Package>
12</Wix>