diff options
Diffstat (limited to 'src/WixToolset.Core/Link/ResolveReferencesCommand.cs')
-rw-r--r-- | src/WixToolset.Core/Link/ResolveReferencesCommand.cs | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs new file mode 100644 index 00000000..5a985f3f --- /dev/null +++ b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs | |||
@@ -0,0 +1,178 @@ | |||
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.Link | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Diagnostics; | ||
8 | using System.Linq; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Data.Rows; | ||
11 | |||
12 | /// <summary> | ||
13 | /// Resolves all the simple references in a section. | ||
14 | /// </summary> | ||
15 | internal class ResolveReferencesCommand : ICommand | ||
16 | { | ||
17 | private Section entrySection; | ||
18 | private IDictionary<string, Symbol> symbols; | ||
19 | private HashSet<Symbol> referencedSymbols; | ||
20 | private HashSet<Section> resolvedSections; | ||
21 | |||
22 | public ResolveReferencesCommand(Section entrySection, IDictionary<string, Symbol> symbols) | ||
23 | { | ||
24 | this.entrySection = entrySection; | ||
25 | this.symbols = symbols; | ||
26 | } | ||
27 | |||
28 | public bool BuildingMergeModule { private get; set; } | ||
29 | |||
30 | public IEnumerable<Symbol> ReferencedSymbols { get { return this.referencedSymbols; } } | ||
31 | |||
32 | public IEnumerable<Section> ResolvedSections { get { return this.resolvedSections; } } | ||
33 | |||
34 | /// <summary> | ||
35 | /// Resolves all the simple references in a section. | ||
36 | /// </summary> | ||
37 | public void Execute() | ||
38 | { | ||
39 | this.resolvedSections = new HashSet<Section>(); | ||
40 | this.referencedSymbols = new HashSet<Symbol>(); | ||
41 | |||
42 | this.RecursivelyResolveReferences(this.entrySection); | ||
43 | } | ||
44 | |||
45 | /// <summary> | ||
46 | /// Recursive helper function to resolve all references of passed in section. | ||
47 | /// </summary> | ||
48 | /// <param name="section">Section with references to resolve.</param> | ||
49 | /// <remarks>Note: recursive function.</remarks> | ||
50 | private void RecursivelyResolveReferences(Section section) | ||
51 | { | ||
52 | // If we already resolved this section, move on to the next. | ||
53 | if (!this.resolvedSections.Add(section)) | ||
54 | { | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | // Process all of the references contained in this section using the collection of | ||
59 | // symbols provided. Then recursively call this method to process the | ||
60 | // located symbol's section. All in all this is a very simple depth-first | ||
61 | // search of the references per-section. | ||
62 | Table wixSimpleReferenceTable; | ||
63 | if (section.Tables.TryGetTable("WixSimpleReference", out wixSimpleReferenceTable)) | ||
64 | { | ||
65 | foreach (WixSimpleReferenceRow wixSimpleReferenceRow in wixSimpleReferenceTable.Rows) | ||
66 | { | ||
67 | Debug.Assert(wixSimpleReferenceRow.Section == section); | ||
68 | |||
69 | // If we're building a Merge Module, ignore all references to the Media table | ||
70 | // because Merge Modules don't have Media tables. | ||
71 | if (this.BuildingMergeModule && "Media" == wixSimpleReferenceRow.TableName) | ||
72 | { | ||
73 | continue; | ||
74 | } | ||
75 | |||
76 | Symbol symbol; | ||
77 | if (!this.symbols.TryGetValue(wixSimpleReferenceRow.SymbolicName, out symbol)) | ||
78 | { | ||
79 | Messaging.Instance.OnMessage(WixErrors.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName)); | ||
80 | } | ||
81 | else // see if the symbol (and any of its duplicates) are appropriately accessible. | ||
82 | { | ||
83 | IList<Symbol> accessible = DetermineAccessibleSymbols(section, symbol); | ||
84 | if (!accessible.Any()) | ||
85 | { | ||
86 | Messaging.Instance.OnMessage(WixErrors.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbol.Access)); | ||
87 | } | ||
88 | else if (1 == accessible.Count) | ||
89 | { | ||
90 | Symbol accessibleSymbol = accessible[0]; | ||
91 | this.referencedSymbols.Add(accessibleSymbol); | ||
92 | |||
93 | if (null != accessibleSymbol.Section) | ||
94 | { | ||
95 | RecursivelyResolveReferences(accessibleSymbol.Section); | ||
96 | } | ||
97 | } | ||
98 | else // display errors for the duplicate symbols. | ||
99 | { | ||
100 | Symbol accessibleSymbol = accessible[0]; | ||
101 | string referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers.ToString(); | ||
102 | if (String.IsNullOrEmpty(referencingSourceLineNumber)) | ||
103 | { | ||
104 | Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name)); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name, referencingSourceLineNumber)); | ||
109 | } | ||
110 | |||
111 | foreach (Symbol accessibleDuplicate in accessible.Skip(1)) | ||
112 | { | ||
113 | Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol2(accessibleDuplicate.Row.SourceLineNumbers)); | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Determine if the symbol and any of its duplicates are accessbile by referencing section. | ||
123 | /// </summary> | ||
124 | /// <param name="referencingSection">Section referencing the symbol.</param> | ||
125 | /// <param name="symbol">Symbol being referenced.</param> | ||
126 | /// <returns>List of symbols accessible by referencing section.</returns> | ||
127 | private IList<Symbol> DetermineAccessibleSymbols(Section referencingSection, Symbol symbol) | ||
128 | { | ||
129 | List<Symbol> symbols = new List<Symbol>(); | ||
130 | |||
131 | if (AccessibleSymbol(referencingSection, symbol)) | ||
132 | { | ||
133 | symbols.Add(symbol); | ||
134 | } | ||
135 | |||
136 | foreach (Symbol dupe in symbol.PossiblyConflictingSymbols) | ||
137 | { | ||
138 | if (AccessibleSymbol(referencingSection, dupe)) | ||
139 | { | ||
140 | symbols.Add(dupe); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | foreach (Symbol dupe in symbol.RedundantSymbols) | ||
145 | { | ||
146 | if (AccessibleSymbol(referencingSection, dupe)) | ||
147 | { | ||
148 | symbols.Add(dupe); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | return symbols; | ||
153 | } | ||
154 | |||
155 | /// <summary> | ||
156 | /// Determine if a single symbol is accessible by the referencing section. | ||
157 | /// </summary> | ||
158 | /// <param name="referencingSection">Section referencing the symbol.</param> | ||
159 | /// <param name="symbol">Symbol being referenced.</param> | ||
160 | /// <returns>True if symbol is accessible.</returns> | ||
161 | private bool AccessibleSymbol(Section referencingSection, Symbol symbol) | ||
162 | { | ||
163 | switch (symbol.Access) | ||
164 | { | ||
165 | case AccessModifier.Public: | ||
166 | return true; | ||
167 | case AccessModifier.Internal: | ||
168 | return symbol.Row.Section.IntermediateId.Equals(referencingSection.IntermediateId) || (null != symbol.Row.Section.LibraryId && symbol.Row.Section.LibraryId.Equals(referencingSection.LibraryId)); | ||
169 | case AccessModifier.Protected: | ||
170 | return symbol.Row.Section.IntermediateId.Equals(referencingSection.IntermediateId); | ||
171 | case AccessModifier.Private: | ||
172 | return referencingSection == symbol.Section; | ||
173 | default: | ||
174 | throw new InvalidOperationException(); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||