/// <summary>
        /// Appends all trees (including any trees from #load'ed files).
        /// </summary>
        private static void AppendAllSyntaxTrees(
            ArrayBuilder <SyntaxTree> treesBuilder,
            SyntaxTree tree,
            string scriptClassName,
            SourceReferenceResolver resolver,
            CommonMessageProvider messageProvider,
            bool isSubmission,
            IDictionary <SyntaxTree, int> ordinalMapBuilder,
            IDictionary <SyntaxTree, ImmutableArray <LoadDirective> > loadDirectiveMapBuilder,
            IDictionary <string, SyntaxTree> loadedSyntaxTreeMapBuilder,
            IDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > declMapBuilder,
            ref DeclarationTable declTable)
        {
            var sourceCodeKind = tree.Options.Kind;

            if (sourceCodeKind == SourceCodeKind.Script)
            {
                AppendAllLoadedSyntaxTrees(treesBuilder, tree, scriptClassName, resolver, messageProvider, isSubmission, ordinalMapBuilder, loadDirectiveMapBuilder, loadedSyntaxTreeMapBuilder, declMapBuilder, ref declTable);
            }

            AddSyntaxTreeToDeclarationMapAndTable(tree, scriptClassName, isSubmission, declMapBuilder, ref declTable);

            treesBuilder.Add(tree);

            ordinalMapBuilder.Add(tree, ordinalMapBuilder.Count);
        }
        private static void RemoveSyntaxTreeFromDeclarationMapAndTable(
            SyntaxTree tree,
            IDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > declMap,
            ref DeclarationTable declTable)
        {
            var lazyRoot = declMap[tree];

            declTable = declTable.RemoveRootDeclaration(lazyRoot);
            declMap.Remove(tree);
        }
        private static void AddSyntaxTreeToDeclarationMapAndTable(
            SyntaxTree tree,
            string scriptClassName,
            bool isSubmission,
            IDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > declMapBuilder,
            ref DeclarationTable declTable)
        {
            var lazyRoot = new Lazy <RootSingleNamespaceDeclaration>(() => DeclarationTreeBuilder.ForTree(tree, scriptClassName, isSubmission));

            declMapBuilder.Add(tree, lazyRoot); // Callers are responsible for checking for existing entries.
            declTable = declTable.AddRootDeclaration(lazyRoot);
        }
예제 #4
0
            public Cache(DeclarationTable table)
            {
                this.MergedRoot = new Lazy <MergedNamespaceDeclaration>(
                    () => MergedNamespaceDeclaration.Create(table._allOlderRootDeclarations.InInsertionOrder.AsImmutable <SingleNamespaceDeclaration>()));

                this.TypeNames = new Lazy <ISet <string> >(
                    () => GetTypeNames(this.MergedRoot.Value));

                this.NamespaceNames = new Lazy <ISet <string> >(
                    () => GetNamespaceNames(this.MergedRoot.Value));

                this.ReferenceDirectives = new Lazy <ImmutableArray <ReferenceDirective> >(
                    () => MergedRoot.Value.Declarations.OfType <RootSingleNamespaceDeclaration>().SelectMany(r => r.ReferenceDirectives).AsImmutable());
            }
            internal State(
                ImmutableArray <SyntaxTree> syntaxTrees,
                ImmutableDictionary <SyntaxTree, int> syntaxTreeOrdinalMap,
                ImmutableDictionary <SyntaxTree, ImmutableArray <LoadDirective> > loadDirectiveMap,
                ImmutableDictionary <string, SyntaxTree> loadedSyntaxTreeMap,
                ImmutableDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > rootNamespaces,
                DeclarationTable declarationTable)
            {
                Debug.Assert(syntaxTrees.All(tree => syntaxTrees[syntaxTreeOrdinalMap[tree]] == tree));
                Debug.Assert(syntaxTrees.SetEquals(rootNamespaces.Keys.AsImmutable(), EqualityComparer <SyntaxTree> .Default));

                this.SyntaxTrees         = syntaxTrees;
                this.OrdinalMap          = syntaxTreeOrdinalMap;
                this.LoadDirectiveMap    = loadDirectiveMap;
                this.LoadedSyntaxTreeMap = loadedSyntaxTreeMap;
                this.RootNamespaces      = rootNamespaces;
                this.DeclarationTable    = declarationTable;
            }
        private static void AppendAllLoadedSyntaxTrees(
            ArrayBuilder <SyntaxTree> treesBuilder,
            SyntaxTree tree,
            string scriptClassName,
            SourceReferenceResolver resolver,
            CommonMessageProvider messageProvider,
            bool isSubmission,
            IDictionary <SyntaxTree, int> ordinalMapBuilder,
            IDictionary <SyntaxTree, ImmutableArray <LoadDirective> > loadDirectiveMapBuilder,
            IDictionary <string, SyntaxTree> loadedSyntaxTreeMapBuilder,
            IDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > declMapBuilder,
            ref DeclarationTable declTable)
        {
            ArrayBuilder <LoadDirective> loadDirectives = null;

            foreach (var directive in tree.GetCompilationUnitRoot().GetLoadDirectives())
            {
                var fileToken = directive.File;
                var path      = (string)fileToken.Value;
                if (path == null)
                {
                    // If there is no path, the parser should have some Diagnostics to report (if we're in an active region).
                    Debug.Assert(!directive.IsActive || tree.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
                    continue;
                }

                var    diagnostics      = DiagnosticBag.GetInstance();
                string resolvedFilePath = null;
                if (resolver == null)
                {
                    diagnostics.Add(
                        messageProvider.CreateDiagnostic(
                            (int)ErrorCode.ERR_SourceFileReferencesNotSupported,
                            directive.Location));
                }
                else
                {
                    resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath);
                    if (resolvedFilePath == null)
                    {
                        diagnostics.Add(
                            messageProvider.CreateDiagnostic(
                                (int)ErrorCode.ERR_NoSourceFile,
                                fileToken.GetLocation(),
                                path,
                                CSharpResources.CouldNotFindFile));
                    }
                    else if (!loadedSyntaxTreeMapBuilder.ContainsKey(resolvedFilePath))
                    {
                        try
                        {
                            var code       = resolver.ReadText(resolvedFilePath);
                            var loadedTree = SyntaxFactory.ParseSyntaxTree(
                                code,
                                tree.Options, // Use ParseOptions propagated from "external" tree.
                                resolvedFilePath);

                            // All #load'ed trees should have unique path information.
                            loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree);

                            AppendAllSyntaxTrees(
                                treesBuilder,
                                loadedTree,
                                scriptClassName,
                                resolver,
                                messageProvider,
                                isSubmission,
                                ordinalMapBuilder,
                                loadDirectiveMapBuilder,
                                loadedSyntaxTreeMapBuilder,
                                declMapBuilder,
                                ref declTable);
                        }
                        catch (Exception e)
                        {
                            diagnostics.Add(
                                CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath),
                                fileToken.GetLocation());
                        }
                    }
                    else
                    {
                        // The path resolved, but we've seen this file before,
                        // so don't attempt to load it again.
                        Debug.Assert(diagnostics.IsEmptyWithoutResolution);
                    }
                }

                if (loadDirectives == null)
                {
                    loadDirectives = ArrayBuilder <LoadDirective> .GetInstance();
                }
                loadDirectives.Add(new LoadDirective(resolvedFilePath, diagnostics.ToReadOnlyAndFree()));
            }

            if (loadDirectives != null)
            {
                loadDirectiveMapBuilder.Add(tree, loadDirectives.ToImmutableAndFree());
            }
        }