main
cs 128 lines 6.11 KB
Raw
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;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility.Services;
10
11 internal class FindEntrySectionAndLoadSymbolsCommand
12 {
13 public FindEntrySectionAndLoadSymbolsCommand(IMessaging messaging, IEnumerable<IntermediateSection> sections, OutputType expectedOutpuType)
14 {
15 this.Messaging = messaging;
16 this.Sections = sections;
17 this.ExpectedOutputType = expectedOutpuType;
18 }
19
20 private IMessaging Messaging { get; }
21
22 private IEnumerable<IntermediateSection> Sections { get; }
23
24 private OutputType ExpectedOutputType { get; }
25
26 /// <summary>
27 /// Gets the located entry section after the command is executed.
28 /// </summary>
29 public IntermediateSection EntrySection { get; private set; }
30
31 /// <summary>
32 /// Gets the collection of loaded symbols.
33 /// </summary>
34 public IDictionary<string, SymbolWithSection> SymbolsByName { get; private set; }
35
36 /// <summary>
37 /// Gets the collection of possibly conflicting symbols.
38 /// </summary>
39 public IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; private set; }
40
41 /// <summary>
42 /// Gets the collection of redundant symbols that should not be included
43 /// in the final output.
44 /// </summary>
45 public ISet<IntermediateSymbol> IdenticalDirectorySymbols { get; private set; }
46
47 /// <summary>
48 /// Gets the collection of symbols that are marked as overrides.
49 /// </summary>
50 public IReadOnlyCollection<SymbolWithSection> OverrideSymbols { get; private set; }
51
52 public void Execute()
53 {
54 var symbolsByName = new Dictionary<string, SymbolWithSection>();
55 var possibleConflicts = new HashSet<SymbolWithSection>();
56 var identicalDirectorySymbols = new HashSet<IntermediateSymbol>();
57 var overrideSymbols = new List<SymbolWithSection>();
58
59 if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType))
60 {
61 expectedEntrySectionType = SectionType.Unknown;
62 }
63
64 foreach (var section in this.Sections)
65 {
66 // Try to find the one and only entry section.
67 if (SectionType.Package == section.Type || SectionType.Module == section.Type || SectionType.PatchCreation == section.Type || SectionType.Patch == section.Type || SectionType.Bundle == section.Type)
68 {
69 if (SectionType.Unknown != expectedEntrySectionType && section.Type != expectedEntrySectionType)
70 {
71 this.Messaging.Write(WarningMessages.UnexpectedEntrySection(section.Symbols.FirstOrDefault()?.SourceLineNumbers, section.Type.ToString(), expectedEntrySectionType.ToString()));
72 }
73
74 if (null == this.EntrySection)
75 {
76 this.EntrySection = section;
77 }
78 else
79 {
80 this.Messaging.Write(ErrorMessages.MultipleEntrySections(this.EntrySection.Symbols.FirstOrDefault()?.SourceLineNumbers, this.EntrySection.Id, section.Id));
81 this.Messaging.Write(ErrorMessages.MultipleEntrySections2(section.Symbols.FirstOrDefault()?.SourceLineNumbers));
82 }
83 }
84
85 // Load all the symbols from the section's tables that can be referenced (i.e. have an Id).
86 foreach (var symbol in section.Symbols.Where(t => t.Id != null))
87 {
88 var symbolWithSection = new SymbolWithSection(section, symbol);
89 var fullName = symbolWithSection.GetFullName();
90
91 if (!symbolsByName.TryGetValue(fullName, out var existingSymbol))
92 {
93 symbolsByName.Add(fullName, symbolWithSection);
94 }
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 {
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.
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);
105 identicalDirectorySymbols.Add(symbolWithSection.Symbol);
106 }
107 else
108 {
109 symbolWithSection.AddPossibleConflict(existingSymbol);
110 existingSymbol.AddPossibleConflict(symbolWithSection);
111 possibleConflicts.Add(existingSymbol);
112 }
113 }
114
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;
125 this.OverrideSymbols = overrideSymbols;
126 }
127 }
128 }