aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
blob: 1c2ca8eb9216841b77f2533c30ff01e9c9344bf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 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.

namespace WixToolset.Core.Link
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using WixToolset.Data;
    using WixToolset.Extensibility.Services;

    internal class FindEntrySectionAndLoadSymbolsCommand
    {
        public FindEntrySectionAndLoadSymbolsCommand(IMessaging messaging, IEnumerable<IntermediateSection> sections, OutputType expectedOutpuType)
        {
            this.Messaging = messaging;
            this.Sections = sections;
            this.ExpectedOutputType = expectedOutpuType;
        }

        private IMessaging Messaging { get; }

        private IEnumerable<IntermediateSection> Sections { get; }

        private OutputType ExpectedOutputType { get; }

        /// <summary>
        /// Gets the located entry section after the command is executed.
        /// </summary>
        public IntermediateSection EntrySection { get; private set; }

        /// <summary>
        /// Gets the collection of loaded symbols.
        /// </summary>
        public IDictionary<string, SymbolWithSection> SymbolsByName { get; private set; }

        /// <summary>
        /// Gets the collection of possibly conflicting symbols.
        /// </summary>
        public IEnumerable<SymbolWithSection> PossibleConflicts { get; private set; }

        public void Execute()
        {
            var symbolsByName = new Dictionary<string, SymbolWithSection>();
            var possibleConflicts = new HashSet<SymbolWithSection>();

            if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType))
            {
                expectedEntrySectionType = SectionType.Unknown;
            }

            foreach (var section in this.Sections)
            {
                // Try to find the one and only entry section.
                if (SectionType.Product == section.Type || SectionType.Module == section.Type || SectionType.PatchCreation == section.Type || SectionType.Patch == section.Type || SectionType.Bundle == section.Type)
                {
                    // TODO: remove this?
                    //if (SectionType.Unknown != expectedEntrySectionType && section.Type != expectedEntrySectionType)
                    //{
                    //    string outputExtension = Output.GetExtension(this.ExpectedOutputType);
                    //    this.Messaging.Write(WixWarnings.UnexpectedEntrySection(section.SourceLineNumbers, section.Type.ToString(), expectedEntrySectionType.ToString(), outputExtension));
                    //}

                    if (null == this.EntrySection)
                    {
                        this.EntrySection = section;
                    }
                    else
                    {
                        this.Messaging.Write(ErrorMessages.MultipleEntrySections(this.EntrySection.Symbols.FirstOrDefault()?.SourceLineNumbers, this.EntrySection.Id, section.Id));
                        this.Messaging.Write(ErrorMessages.MultipleEntrySections2(section.Symbols.FirstOrDefault()?.SourceLineNumbers));
                    }
                }

                // Load all the symbols from the section's tables that create symbols.
                foreach (var symbol in section.Symbols.Where(t => t.Id != null))
                {
                    var symbolWithSection = new SymbolWithSection(section, symbol);

                    if (!symbolsByName.TryGetValue(symbolWithSection.Name, out var existingSymbol))
                    {
                        symbolsByName.Add(symbolWithSection.Name, symbolWithSection);
                    }
                    else // uh-oh, duplicate symbols.
                    {
                        // If the duplicate symbols are both private directories, there is a chance that they
                        // point to identical symbols. Identical directory symbols are redundant and will not cause
                        // conflicts.
                        if (AccessModifier.Private == existingSymbol.Access && AccessModifier.Private == symbolWithSection.Access &&
                            SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol))
                        {
                            // Ensure identical symbol's symbol is marked redundant to ensure (should the symbol be
                            // referenced into the final output) it will not add duplicate primary keys during
                            // the .IDT importing.
                            //symbol.Row.Redundant = true; - TODO: remove this
                            existingSymbol.AddRedundant(symbolWithSection);
                        }
                        else
                        {
                            existingSymbol.AddPossibleConflict(symbolWithSection);
                            possibleConflicts.Add(existingSymbol);
                        }
                    }
                }
            }

            this.SymbolsByName = symbolsByName;
            this.PossibleConflicts = possibleConflicts;
        }
    }
}