Пример #1
0
            /// <summary>
            /// Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
            /// Meaning needs to be specified if the enclosing declaration is given
            /// </summary>
            private void BuildSymbolDisplay(ISymbol inputSymbol, ISymbolWriter writer, INode enclosingDeclaration = null, SymbolFlags inputMeaning = SymbolFlags.None, SymbolFormatFlags flags = SymbolFormatFlags.None, TypeFormatFlags typeFlags = TypeFormatFlags.None)
            {
                Contract.Assert(inputSymbol != null);
                Contract.Assert(writer != null);

                // HINT: To simplify migration we're using "local" functions via delegates.
                // This code could be changed in the future, once C# would have local functions.
                Action <ISymbol, SymbolFlags> walkSymbol = null;

                ISymbol          parentSymbol = null;
                Action <ISymbol> appendParentTypeArgumentsAndSymbolName = null;

                appendParentTypeArgumentsAndSymbolName = (ISymbol symbol) =>
                {
                    if (parentSymbol != null)
                    {
                        // Write type arguments of instantiated class/interface here
                        if ((flags & SymbolFormatFlags.WriteTypeParametersOrArguments) != SymbolFormatFlags.None)
                        {
                            if ((symbol.Flags & SymbolFlags.Instantiated) != SymbolFlags.None)
                            {
                                // TODO: check types to avoid redundant ToArray call.
                                BuildDisplayForTypeArgumentsAndDelimiters(
                                    m_checker.GetTypeParametersOfClassOrInterface(parentSymbol),
                                    ((ITransientSymbol)symbol).Mapper, writer, enclosingDeclaration);
                            }
                            else
                            {
                                BuildTypeParameterDisplayFromSymbol(parentSymbol, writer, enclosingDeclaration);
                            }
                        }

                        WritePunctuation(writer, SyntaxKind.DotToken);
                    }

                    parentSymbol = symbol;
                    AppendSymbolNameOnly(symbol, writer);
                };

                // Let the writer know we just wrote out a symbol.  The declaration emitter writer uses
                // this to determine if an import it has previously seen (and not written out) needs
                // to be written to the file once the walk of the tree is complete.
                //
                // NOTE(cyrusn): This approach feels somewhat unfortunate.  A simple pass over the tree
                // up front (for example, during checking) could determine if we need to emit the imports
                // and we could then access that data during declaration emit.
                writer.TrackSymbol(inputSymbol, enclosingDeclaration, inputMeaning);

                walkSymbol = (ISymbol symbol, SymbolFlags meaning) =>
                {
                    if (symbol != null)
                    {
                        var accessibleSymbolChain = m_checker.GetAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, (flags & SymbolFormatFlags.UseOnlyExternalAliasing) != SymbolFormatFlags.None);

                        if (accessibleSymbolChain == null ||
                            m_checker.NeedsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.Count == 1 ? meaning : GetQualifiedLeftMeaning(meaning)))
                        {
                            // Go up and add our parent.
                            walkSymbol(
                                m_checker.GetParentOfSymbol(accessibleSymbolChain != null ? accessibleSymbolChain[0] : symbol),
                                GetQualifiedLeftMeaning(meaning));
                        }

                        if (accessibleSymbolChain != null)
                        {
                            foreach (var accessibleSymbol in accessibleSymbolChain)
                            {
                                appendParentTypeArgumentsAndSymbolName(accessibleSymbol);
                            }
                        }
                        else
                        {
                            // If we didn't find accessible symbol chain for this symbol, break if this is external module
                            if (parentSymbol == null && symbol.DeclarationList.Any(n => HasExternalModuleSymbol(n)))
                            {
                                return;
                            }

                            // if this is anonymous type break
                            if ((symbol.Flags & SymbolFlags.TypeLiteral) != SymbolFlags.None || (symbol.Flags & SymbolFlags.ObjectLiteral) != SymbolFlags.None)
                            {
                                return;
                            }

                            appendParentTypeArgumentsAndSymbolName(symbol);
                        }
                    }
                };

                // Get qualified name if the symbol is not a type parameter
                // and there is an enclosing declaration or we specifically
                // asked for it
                var isTypeParameter = inputSymbol.Flags & SymbolFlags.TypeParameter;
                var typeFormatFlag  = TypeFormatFlags.UseFullyQualifiedType & typeFlags;

                if (isTypeParameter == SymbolFlags.None && (enclosingDeclaration != null || typeFormatFlag != TypeFormatFlags.None))
                {
                    walkSymbol(inputSymbol, inputMeaning);
                    return;
                }

                appendParentTypeArgumentsAndSymbolName(inputSymbol);
            }