BinderFactory.BinderFactoryVisitor.cs 56.9 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed partial class BinderFactory
    {
        private sealed class BinderFactoryVisitor : CSharpSyntaxVisitor<Binder>
        {
18 19
            private int _position;
            private readonly BinderFactory _factory;
P
Pilchie 已提交
20 21 22

            internal BinderFactoryVisitor(BinderFactory factory)
            {
23
                _factory = factory;
P
Pilchie 已提交
24 25 26 27 28 29
            }

            internal int Position
            {
                set
                {
30
                    _position = value;
P
Pilchie 已提交
31 32 33 34 35 36 37
                }
            }

            private CSharpCompilation compilation
            {
                get
                {
38
                    return _factory._compilation;
P
Pilchie 已提交
39 40 41 42 43 44 45
                }
            }

            private SyntaxTree syntaxTree
            {
                get
                {
46
                    return _factory._syntaxTree;
P
Pilchie 已提交
47 48 49 50 51 52 53
                }
            }

            private BuckStopsHereBinder buckStopsHereBinder
            {
                get
                {
54
                    return _factory._buckStopsHereBinder;
P
Pilchie 已提交
55 56 57 58 59 60 61
                }
            }

            private ConcurrentCache<BinderCacheKey, Binder> binderCache
            {
                get
                {
62
                    return _factory._binderCache;
P
Pilchie 已提交
63 64 65 66 67 68 69
                }
            }

            private bool InScript
            {
                get
                {
70
                    return _factory.InScript;
P
Pilchie 已提交
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
                }
            }

            public override Binder DefaultVisit(SyntaxNode parent)
            {
                return VisitCore(parent.Parent);
            }

            // node, for which we are trying to find a binder is not supposed to be null
            // so we do not need to handle null in the Visit
            public override Binder Visit(SyntaxNode node)
            {
                return VisitCore(node);
            }

            //PERF: nonvirtual implementation of Visit
            private Binder VisitCore(SyntaxNode node)
            {
                return ((CSharpSyntaxNode)node).Accept(this);
            }

            // This is used mainly by the method body binder.  During construction of the method symbol,
            // the contexts are built "by hand" rather than by this builder (see
            // MethodMemberBuilder.EnsureDeclarationBound).
            public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl)
            {
97
                if (!LookupPosition.IsInMethodDeclaration(_position, methodDecl))
P
Pilchie 已提交
98 99 100 101 102
                {
                    return VisitCore(methodDecl.Parent);
                }

                NodeUsage usage;
103
                if (LookupPosition.IsInBody(_position, methodDecl))
P
Pilchie 已提交
104 105 106
                {
                    usage = NodeUsage.MethodBody;
                }
107
                else if (LookupPosition.IsInMethodTypeParameterScope(_position, methodDecl))
P
Pilchie 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
                {
                    usage = NodeUsage.MethodTypeParameters;
                }
                else
                {
                    // Normal - is when method itself is not involved (will use outer binder)
                    //          that would be if position is within the return type or method name
                    usage = NodeUsage.Normal;
                }

                var key = CreateBinderCacheKey(methodDecl, usage);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    var parentType = methodDecl.Parent as TypeDeclarationSyntax;
                    if (parentType != null)
                    {
                        resultBinder = VisitTypeDeclarationCore(parentType, NodeUsage.NamedTypeBodyOrTypeParameters);
                    }
                    else
                    {
                        resultBinder = VisitCore(methodDecl.Parent);
                    }

                    SourceMethodSymbol method = null;
134 135 136

                    if (usage != NodeUsage.Normal && methodDecl.TypeParameterList != null)
                    {
137
                        method = GetMethodSymbol(methodDecl, resultBinder);
P
Pilchie 已提交
138 139 140 141 142
                        resultBinder = new WithMethodTypeParametersBinder(method, resultBinder);
                    }

                    if (usage == NodeUsage.MethodBody)
                    {
143
                        method = method ?? GetMethodSymbol(methodDecl, resultBinder);
P
Pilchie 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156
                        resultBinder = new InMethodBinder(method, resultBinder);
                    }

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers);
                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax parent)
            {
                // If the position isn't in the scope of the method, then proceed to the parent syntax node.
157
                if (!LookupPosition.IsInMethodDeclaration(_position, parent))
P
Pilchie 已提交
158 159 160 161
                {
                    return VisitCore(parent.Parent);
                }

162
                bool inBodyOrInitializer = LookupPosition.IsInConstructorParameterScope(_position, parent);
P
Pilchie 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
                var extraInfo = inBodyOrInitializer ? NodeUsage.ConstructorBodyOrInitializer : NodeUsage.Normal;  // extra info for the cache.
                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    resultBinder = VisitCore(parent.Parent);

                    // NOTE: Don't get the method symbol unless we're sure we need it.
                    if (inBodyOrInitializer)
                    {
                        var method = GetMethodSymbol(parent, resultBinder);
                        if ((object)method != null)
                        {
                            // Ctors cannot be generic
                            //TODO: the error should be given in a different place, but should we ignore or consider the type args?
                            Debug.Assert(method.Arity == 0, "Generic Ctor, What to do?");

181
                            resultBinder = new InMethodBinder(method, resultBinder);
P
Pilchie 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195
                        }
                    }

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitDestructorDeclaration(DestructorDeclarationSyntax parent)
            {
                // If the position isn't in the scope of the method, then proceed to the parent syntax node.
196
                if (!LookupPosition.IsInMethodDeclaration(_position, parent))
P
Pilchie 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
                {
                    return VisitCore(parent.Parent);
                }

                var key = CreateBinderCacheKey(parent, usage: NodeUsage.Normal);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    // Destructors have neither parameters nor type parameters, so there's nothing special to do here.
                    resultBinder = VisitCore(parent.Parent);

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent)
            {
                // If the position isn't in the scope of the method, then proceed to the parent syntax node.
220
                if (!LookupPosition.IsInMethodDeclaration(_position, parent))
P
Pilchie 已提交
221 222 223 224
                {
                    return VisitCore(parent.Parent);
                }

225
                bool inBlock = LookupPosition.IsInBlock(_position, parent.Body);
226
                var extraInfo = inBlock ? NodeUsage.AccessorBody : NodeUsage.Normal;  // extra info for the cache.
P
Pilchie 已提交
227 228 229 230 231 232 233
                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    resultBinder = VisitCore(parent.Parent);

234
                    if (inBlock)
P
Pilchie 已提交
235 236 237 238
                    {
                        var propertyOrEventDecl = parent.Parent.Parent;
                        MethodSymbol accessor = null;

239
                        switch (propertyOrEventDecl.Kind())
P
Pilchie 已提交
240 241 242 243 244 245 246
                        {
                            case SyntaxKind.PropertyDeclaration:
                            case SyntaxKind.IndexerDeclaration:
                                {
                                    var propertySymbol = GetPropertySymbol((BasePropertyDeclarationSyntax)propertyOrEventDecl, resultBinder);
                                    if ((object)propertySymbol != null)
                                    {
247
                                        accessor = (parent.Kind() == SyntaxKind.SetAccessorDeclaration) ? propertySymbol.SetMethod : propertySymbol.GetMethod;
P
Pilchie 已提交
248 249 250 251 252 253 254 255 256 257 258 259
                                    }
                                    break;
                                }
                            case SyntaxKind.EventDeclaration:
                            case SyntaxKind.EventFieldDeclaration:
                                {
                                    // NOTE: it's an error for field-like events to have accessors, 
                                    // but we want to bind them anyway for error tolerance reasons.

                                    var eventSymbol = GetEventSymbol((EventDeclarationSyntax)propertyOrEventDecl, resultBinder);
                                    if ((object)eventSymbol != null)
                                    {
260
                                        accessor = (parent.Kind() == SyntaxKind.AddAccessorDeclaration) ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
P
Pilchie 已提交
261 262 263 264
                                    }
                                    break;
                                }
                            default:
265
                                throw ExceptionUtilities.UnexpectedValue(propertyOrEventDecl.Kind());
P
Pilchie 已提交
266 267 268 269
                        }

                        if ((object)accessor != null)
                        {
270
                            resultBinder = new InMethodBinder(accessor, resultBinder);
P
Pilchie 已提交
271 272 273 274 275 276 277 278 279 280 281 282
                        }
                    }

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax parent)
            {
                // If the position isn't in the scope of the method, then proceed to the parent syntax node.
283
                if (!LookupPosition.IsInMethodDeclaration(_position, parent))
P
Pilchie 已提交
284 285 286 287
                {
                    return VisitCore(parent.Parent);
                }

288
                bool inBody = LookupPosition.IsInBody(_position, parent);
P
Pilchie 已提交
289 290 291 292 293 294 295 296 297 298 299
                var extraInfo = inBody ? NodeUsage.OperatorBody : NodeUsage.Normal;  // extra info for the cache.
                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    resultBinder = VisitCore(parent.Parent);

                    MethodSymbol method = GetMethodSymbol(parent, resultBinder);
                    if ((object)method != null && inBody)
                    {
300
                        resultBinder = new InMethodBinder(method, resultBinder);
P
Pilchie 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
                    }

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitOperatorDeclaration(OperatorDeclarationSyntax parent)
            {
                return VisitOperatorOrConversionDeclaration(parent);
            }

            public override Binder VisitConversionOperatorDeclaration(ConversionOperatorDeclarationSyntax parent)
            {
                return VisitOperatorOrConversionDeclaration(parent);
            }

            public override Binder VisitFieldDeclaration(FieldDeclarationSyntax parent)
            {
                return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);
            }

            public override Binder VisitEventDeclaration(EventDeclarationSyntax parent)
            {
                return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);
            }

            public override Binder VisitEventFieldDeclaration(EventFieldDeclarationSyntax parent)
            {
                return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);
            }

            public override Binder VisitPropertyDeclaration(PropertyDeclarationSyntax parent)
            {
338
                if (!LookupPosition.IsInBody(_position, parent))
339 340 341 342 343
                {
                    return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);
                }

                return VisitPropertyOrIndexerExpressionBody(parent);
P
Pilchie 已提交
344 345 346 347
            }

            public override Binder VisitIndexerDeclaration(IndexerDeclarationSyntax parent)
            {
348
                if (!LookupPosition.IsInBody(_position, parent))
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
                {
                    return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);
                }

                return VisitPropertyOrIndexerExpressionBody(parent);
            }

            private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSyntax parent)
            {
                var key = CreateBinderCacheKey(parent, NodeUsage.AccessorBody);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    resultBinder = VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers);

                    var propertySymbol = GetPropertySymbol(parent, resultBinder);
                    var accessor = propertySymbol.GetMethod;
                    if ((object)accessor != null)
                    {
                        resultBinder = new InMethodBinder(accessor, resultBinder);
                    }

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
P
Pilchie 已提交
376 377 378 379 380 381 382 383
            }

            private NamedTypeSymbol GetContainerType(Binder binder, CSharpSyntaxNode node)
            {
                var container = binder.ContainingMemberOrLambda as NamedTypeSymbol;
                if ((object)container == null)
                {
                    Debug.Assert(binder.ContainingMemberOrLambda is NamespaceSymbol);
384
                    if (node.Parent.Kind() == SyntaxKind.CompilationUnit && syntaxTree.Options.Kind != SourceCodeKind.Regular)
P
Pilchie 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
                    {
                        container = compilation.ScriptClass;
                    }
                    else
                    {
                        container = ((NamespaceSymbol)binder.ContainingMemberOrLambda).ImplicitType;
                    }
                }

                return container;
            }

            /// <summary>
            /// Get the name of the method so that it can be looked up in the containing type.
            /// </summary>
            /// <param name="baseMethodDeclarationSyntax">Non-null declaration syntax.</param>
            /// <param name="outerBinder">Binder for the scope around the method (may be null for operators, constructors, and destructors).</param>
            private static string GetMethodName(BaseMethodDeclarationSyntax baseMethodDeclarationSyntax, Binder outerBinder)
            {
404
                switch (baseMethodDeclarationSyntax.Kind())
P
Pilchie 已提交
405 406 407 408 409 410 411 412
                {
                    case SyntaxKind.ConstructorDeclaration:
                        return (baseMethodDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword) ? WellKnownMemberNames.StaticConstructorName : WellKnownMemberNames.InstanceConstructorName);
                    case SyntaxKind.DestructorDeclaration:
                        return WellKnownMemberNames.DestructorName;
                    case SyntaxKind.OperatorDeclaration:
                        return OperatorFacts.OperatorNameFromDeclaration((OperatorDeclarationSyntax)baseMethodDeclarationSyntax);
                    case SyntaxKind.ConversionOperatorDeclaration:
413
                        return ((ConversionOperatorDeclarationSyntax)baseMethodDeclarationSyntax).ImplicitOrExplicitKeyword.Kind() == SyntaxKind.ImplicitKeyword
P
Pilchie 已提交
414 415 416 417 418 419
                            ? WellKnownMemberNames.ImplicitConversionName
                            : WellKnownMemberNames.ExplicitConversionName;
                    case SyntaxKind.MethodDeclaration:
                        MethodDeclarationSyntax methodDeclSyntax = (MethodDeclarationSyntax)baseMethodDeclarationSyntax;
                        return ExplicitInterfaceHelpers.GetMemberName(outerBinder, methodDeclSyntax.ExplicitInterfaceSpecifier, methodDeclSyntax.Identifier.ValueText);
                    default:
420
                        throw ExceptionUtilities.UnexpectedValue(baseMethodDeclarationSyntax.Kind());
P
Pilchie 已提交
421 422 423 424 425 426 427 428 429 430 431 432
                }
            }

            /// <summary>
            /// Get the name of the property, indexer, or event so that it can be looked up in the containing type.
            /// </summary>
            /// <param name="basePropertyDeclarationSyntax">Non-null declaration syntax.</param>
            /// <param name="outerBinder">Non-null binder for the scope around the member.</param>
            private static string GetPropertyOrEventName(BasePropertyDeclarationSyntax basePropertyDeclarationSyntax, Binder outerBinder)
            {
                ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifierSyntax = basePropertyDeclarationSyntax.ExplicitInterfaceSpecifier;

433
                switch (basePropertyDeclarationSyntax.Kind())
P
Pilchie 已提交
434 435 436 437 438 439 440 441 442 443 444
                {
                    case SyntaxKind.PropertyDeclaration:
                        var propertyDecl = (PropertyDeclarationSyntax)basePropertyDeclarationSyntax;
                        return ExplicitInterfaceHelpers.GetMemberName(outerBinder, explicitInterfaceSpecifierSyntax, propertyDecl.Identifier.ValueText);
                    case SyntaxKind.IndexerDeclaration:
                        return ExplicitInterfaceHelpers.GetMemberName(outerBinder, explicitInterfaceSpecifierSyntax, WellKnownMemberNames.Indexer);
                    case SyntaxKind.EventDeclaration:
                    case SyntaxKind.EventFieldDeclaration:
                        var eventDecl = (EventDeclarationSyntax)basePropertyDeclarationSyntax;
                        return ExplicitInterfaceHelpers.GetMemberName(outerBinder, explicitInterfaceSpecifierSyntax, eventDecl.Identifier.ValueText);
                    default:
445
                        throw ExceptionUtilities.UnexpectedValue(basePropertyDeclarationSyntax.Kind());
P
Pilchie 已提交
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
                }
            }

            // Get the correct methods symbol within container that corresponds to the given method syntax.
            private SourceMethodSymbol GetMethodSymbol(BaseMethodDeclarationSyntax baseMethodDeclarationSyntax, Binder outerBinder)
            {
                NamedTypeSymbol container = GetContainerType(outerBinder, baseMethodDeclarationSyntax);
                if ((object)container == null)
                {
                    return null;
                }

                string methodName = GetMethodName(baseMethodDeclarationSyntax, outerBinder);
                return (SourceMethodSymbol)GetMemberSymbol(methodName, baseMethodDeclarationSyntax.FullSpan, container, SymbolKind.Method);
            }

            private SourcePropertySymbol GetPropertySymbol(BasePropertyDeclarationSyntax basePropertyDeclarationSyntax, Binder outerBinder)
            {
464
                Debug.Assert(basePropertyDeclarationSyntax.Kind() == SyntaxKind.PropertyDeclaration || basePropertyDeclarationSyntax.Kind() == SyntaxKind.IndexerDeclaration);
P
Pilchie 已提交
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507

                NamedTypeSymbol container = GetContainerType(outerBinder, basePropertyDeclarationSyntax);
                if ((object)container == null)
                {
                    return null;
                }

                string propertyName = GetPropertyOrEventName(basePropertyDeclarationSyntax, outerBinder);
                return (SourcePropertySymbol)GetMemberSymbol(propertyName, basePropertyDeclarationSyntax.Span, container, SymbolKind.Property);
            }

            private SourceEventSymbol GetEventSymbol(EventDeclarationSyntax eventDeclarationSyntax, Binder outerBinder)
            {
                NamedTypeSymbol container = GetContainerType(outerBinder, eventDeclarationSyntax);
                if ((object)container == null)
                {
                    return null;
                }

                string eventName = GetPropertyOrEventName(eventDeclarationSyntax, outerBinder);
                return (SourceEventSymbol)GetMemberSymbol(eventName, eventDeclarationSyntax.Span, container, SymbolKind.Event);
            }

            private Symbol GetMemberSymbol(string memberName, TextSpan memberSpan, NamedTypeSymbol container, SymbolKind kind)
            {
                // return container.GetMembers(methodSyntax.Identifier.ValueText).OfType<SourceMethodSymbol>().Single(m => m.Locations.Any(l => l.SourceTree == tree && methodSyntax.Span.Contains(l.SourceSpan)));
                foreach (Symbol sym in container.GetMembers(memberName))
                {
                    if (sym.Kind != kind)
                    {
                        continue;
                    }

                    if (sym.Kind == SymbolKind.Method)
                    {
                        if (InSpan(sym.Locations[0], this.syntaxTree, memberSpan))
                        {
                            return sym;
                        }

                        // If this is a partial method, the method represents the defining part,
                        // not the implementation (method.Locations includes both parts). If the
                        // span is in fact in the implementation, return that method instead.
508
                        var implementation = ((MethodSymbol)sym).PartialImplementationPart;
P
Pilchie 已提交
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
                        if ((object)implementation != null)
                        {
                            if (InSpan(implementation.Locations[0], this.syntaxTree, memberSpan))
                            {
                                return implementation;
                            }
                        }
                    }
                    else
                    {
                        foreach (Location loc in sym.Locations)
                        {
                            if (InSpan(loc, this.syntaxTree, memberSpan))
                            {
                                return sym;
                            }
                        }
                    }
                }

                return null;
            }

            /// <summary>
            /// Returns true if the location is within the syntax tree and span.
            /// </summary>
            private static bool InSpan(Location location, SyntaxTree syntaxTree, TextSpan span)
            {
                Debug.Assert(syntaxTree != null);
                return (location.SourceTree == syntaxTree) && span.Contains(location.SourceSpan);
            }

            public override Binder VisitDelegateDeclaration(DelegateDeclarationSyntax parent)
            {
543
                if (!LookupPosition.IsInDelegateDeclaration(_position, parent))
P
Pilchie 已提交
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
                {
                    return VisitCore(parent.Parent);
                }

                var key = CreateBinderCacheKey(parent, usage: NodeUsage.Normal);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    Binder outer = VisitCore(parent.Parent); // a binder for the body of the enclosing type or namespace
                    var container = ((NamespaceOrTypeSymbol)outer.ContainingMemberOrLambda).GetSourceTypeMember(parent);

                    // NOTE: Members of the delegate type are in scope in the entire delegate declaration syntax.
                    // NOTE: Hence we can assume that we are in body of the delegate type and explicitly insert the InContainerBinder in the binder chain.
                    resultBinder = new InContainerBinder(container, outer);

                    if (parent.TypeParameterList != null)
                    {
                        resultBinder = new WithClassTypeParametersBinder(container, resultBinder);
                    }

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitEnumDeclaration(EnumDeclarationSyntax parent)
            {
                // This method has nothing to contribute unless the position is actually inside the enum (i.e. not in the declaration part)
576 577
                bool inBody = LookupPosition.IsBetweenTokens(_position, parent.OpenBraceToken, parent.CloseBraceToken) ||
                    LookupPosition.IsInAttributeSpecification(_position, parent.AttributeLists);
P
Pilchie 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
                if (!inBody)
                {
                    return VisitCore(parent.Parent);
                }

                var key = CreateBinderCacheKey(parent, usage: NodeUsage.Normal);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    Binder outer = VisitCore(parent.Parent); // a binder for the body of the type enclosing this type
                    var container = ((NamespaceOrTypeSymbol)outer.ContainingMemberOrLambda).GetSourceTypeMember(parent.Identifier.ValueText, 0, SyntaxKind.EnumDeclaration, parent);

                    resultBinder = new InContainerBinder(container, outer);

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            // PERF: do not override VisitTypeDeclaration,
            //       because C# will not call it and will call least derived one instead
            //       resulting in unnecessary virtual dispatch
            private Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent)
            {
606
                if (!LookupPosition.IsInTypeDeclaration(_position, parent))
P
Pilchie 已提交
607 608 609 610 611 612 613 614
                {
                    return VisitCore(parent.Parent);
                }

                NodeUsage extraInfo = NodeUsage.Normal;

                // we are visiting type declarations fairly frequently
                // and position is more likely to be in the body, so lets check for "inBody" first.
615 616
                if (LookupPosition.IsBetweenTokens(_position, parent.OpenBraceToken, parent.CloseBraceToken) ||
                    LookupPosition.IsInAttributeSpecification(_position, parent.AttributeLists))
P
Pilchie 已提交
617 618 619
                {
                    extraInfo = NodeUsage.NamedTypeBodyOrTypeParameters;
                }
620
                else if (LookupPosition.IsInTypeParameterList(_position, parent))
P
Pilchie 已提交
621 622 623
                {
                    extraInfo = NodeUsage.NamedTypeBodyOrTypeParameters;
                }
624
                else if (LookupPosition.IsBetweenTokens(_position, parent.Keyword, parent.OpenBraceToken))
P
Pilchie 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
                {
                    extraInfo = NodeUsage.NamedTypeBaseList;
                }

                return VisitTypeDeclarationCore(parent, extraInfo);
            }

            private Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage extraInfo)
            {
                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder resultBinder;
                if (!binderCache.TryGetValue(key, out resultBinder))
                {
                    // if node is in the optional type parameter list, then members and type parameters are in scope 
                    //     (needed when binding attributes applied to type parameters).
                    // if node is in the base clause, type parameters are in scope.
                    // if node is in the body, then members and type parameters are in scope.

                    // a binder for the body of the type enclosing this type
                    resultBinder = VisitCore(parent.Parent);

                    if (extraInfo != NodeUsage.Normal)
                    {
                        var typeSymbol = ((NamespaceOrTypeSymbol)resultBinder.ContainingMemberOrLambda).GetSourceTypeMember(parent);

                        if (extraInfo == NodeUsage.NamedTypeBaseList)
                        {
                            // even though there could be no type parameter, we need this binder 
                            // for its "IsAccessible"
                            resultBinder = new WithClassTypeParametersBinder(typeSymbol, resultBinder);
                        }
                        else
                        {
                            resultBinder = new InContainerBinder(typeSymbol, resultBinder);

                            if (parent.TypeParameterList != null)
                            {
                                resultBinder = new WithClassTypeParametersBinder(typeSymbol, resultBinder);
                            }
                        }
                    }

                    resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers);

                    binderCache.TryAdd(key, resultBinder);
                }

                return resultBinder;
            }

            public override Binder VisitClassDeclaration(ClassDeclarationSyntax node)
            {
                return VisitTypeDeclarationCore(node);
            }

            public override Binder VisitStructDeclaration(StructDeclarationSyntax node)
            {
                return VisitTypeDeclarationCore(node);
            }

            public override Binder VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
            {
                return VisitTypeDeclarationCore(node);
            }

            public override Binder VisitNamespaceDeclaration(NamespaceDeclarationSyntax parent)
            {
693
                if (!LookupPosition.IsInNamespaceDeclaration(_position, parent))
P
Pilchie 已提交
694 695 696 697 698 699
                {
                    return VisitCore(parent.Parent);
                }

                // test for position equality in case the open brace token is missing:
                // namespace X class C { }
700
                bool inBody = LookupPosition.IsBetweenTokens(_position, parent.OpenBraceToken, parent.CloseBraceToken);
P
Pilchie 已提交
701 702 703

                bool inUsing = IsInUsing(parent);

704
                return VisitNamespaceDeclaration(parent, _position, inBody, inUsing);
P
Pilchie 已提交
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
            }

            internal InContainerBinder VisitNamespaceDeclaration(NamespaceDeclarationSyntax parent, int position, bool inBody, bool inUsing)
            {
                Debug.Assert(!inUsing || inBody, "inUsing => inBody");

                var extraInfo = inUsing ? NodeUsage.NamespaceUsings : (inBody ? NodeUsage.NamespaceBody : NodeUsage.Normal);  // extra info for the cache.
                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder result;
                if (!binderCache.TryGetValue(key, out result))
                {
                    InContainerBinder outer;
                    var container = parent.Parent;

720
                    if (InScript && container.Kind() == SyntaxKind.CompilationUnit)
P
Pilchie 已提交
721 722 723 724 725 726 727 728
                    {
                        // Although namespaces are not allowed in script code we still bind them so that we don't report useless errors.
                        // A namespace in script code is not bound within the scope of a Script class, 
                        // but still within scope of compilation unit extern aliases and usings.
                        outer = VisitCompilationUnit((CompilationUnitSyntax)container, inUsing: false, inScript: false);
                    }
                    else
                    {
729
                        outer = (InContainerBinder)_factory.GetBinder(parent.Parent, position);
P
Pilchie 已提交
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
                    }

                    if (!inBody)
                    {
                        // not between the curlies
                        result = outer;
                    }
                    else
                    {
                        // if between the curlies, members are in scope
                        result = MakeNamespaceBinder(parent, parent.Name, outer, inUsing);
                    }

                    binderCache.TryAdd(key, result);
                }

                return (InContainerBinder)result;
            }

            private InContainerBinder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax name, InContainerBinder outer, bool inUsing)
            {
                QualifiedNameSyntax dotted;
                while ((dotted = name as QualifiedNameSyntax) != null)
                {
                    outer = MakeNamespaceBinder(dotted.Left, dotted.Left, outer, inUsing: false);
                    name = dotted.Right;
                }

                NamespaceOrTypeSymbol container = outer.Container;
                NamespaceSymbol ns = ((NamespaceSymbol)container).GetNestedNamespace(name);
                if ((object)ns == null) return outer;
A
Andrew Casey 已提交
761
                return new InContainerBinder(ns, outer, node, inUsing: inUsing);
P
Pilchie 已提交
762 763 764 765 766
            }

            public override Binder VisitCompilationUnit(CompilationUnitSyntax parent)
            {
                return VisitCompilationUnit(
C
Charles Stoner 已提交
767 768 769
                    parent,
                    inUsing: IsInUsing(parent),
                    inScript: InScript);
P
Pilchie 已提交
770 771 772 773 774 775
            }

            internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool inUsing, bool inScript)
            {
                if (compilationUnit != syntaxTree.GetRoot())
                {
776
                    throw new ArgumentOutOfRangeException(nameof(compilationUnit), "node not part of tree");
P
Pilchie 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
                }

                var extraInfo = inUsing
                    ? (inScript ? NodeUsage.CompilationUnitScriptUsings : NodeUsage.CompilationUnitUsings)
                    : (inScript ? NodeUsage.CompilationUnitScript : NodeUsage.Normal);  // extra info for the cache.
                var key = CreateBinderCacheKey(compilationUnit, extraInfo);

                Binder result;
                if (!binderCache.TryGetValue(key, out result))
                {
                    result = this.buckStopsHereBinder;

                    if (inScript)
                    {
                        Debug.Assert((object)compilation.ScriptClass != null);

                        //
                        // Binder chain in script/interactive code:
                        //
A
Andrew Casey 已提交
796 797
                        // + global imports
                        //   + current and previous submission imports (except using aliases)
P
Pilchie 已提交
798 799
                        //     + global namespace
                        //       + host object members
A
Andrew Casey 已提交
800 801
                        //         + previous submissions and corresponding using aliases
                        //           + script class members and using aliases
P
Pilchie 已提交
802 803
                        //

804 805 806 807 808 809
                        bool isSubmissionTree = compilation.IsSubmissionSyntaxTree(compilationUnit.SyntaxTree);
                        if (!isSubmissionTree)
                        {
                            result = result.WithAdditionalFlags(BinderFlags.InLoadedSyntaxTree);
                        }

A
Andrew Casey 已提交
810 811 812 813
                        // This is declared here so it can be captured.  It's initialized below.
                        InContainerBinder scriptClassBinder = null;

                        if (inUsing)
814
                        {
A
Andrew Casey 已提交
815
                            result = result.WithAdditionalFlags(BinderFlags.InScriptUsing);
816
                        }
A
Andrew Casey 已提交
817
                        else
818
                        {
A
Andrew Casey 已提交
819 820 821 822
                            result = new InContainerBinder(container: null, next: result, imports: compilation.GlobalImports);

                            // NB: This binder has a full Imports object, but only the non-alias imports are
                            // ever consumed.  Aliases are actually checked in scriptClassBinder (below).
823 824
                            // Note: #loaded trees don't consume previous submission imports.
                            result = compilation.PreviousSubmission == null || !isSubmissionTree
A
Andrew Casey 已提交
825 826
                                ? new InContainerBinder(result, basesBeingResolved => scriptClassBinder.GetImports(basesBeingResolved))
                                : new InContainerBinder(result, basesBeingResolved =>
A
Andrew Casey 已提交
827
                                    compilation.GetPreviousSubmissionImports().Concat(scriptClassBinder.GetImports(basesBeingResolved)));
828
                        }
P
Pilchie 已提交
829 830 831 832 833 834 835 836

                        result = new InContainerBinder(compilation.GlobalNamespace, result);

                        if (compilation.HostObjectType != null)
                        {
                            result = new HostObjectModelBinder(result);
                        }

A
Andrew Casey 已提交
837 838
                        scriptClassBinder = new InContainerBinder(compilation.ScriptClass, result, compilationUnit, inUsing: inUsing);
                        result = scriptClassBinder;
P
Pilchie 已提交
839 840 841 842 843 844 845 846
                    }
                    else
                    {
                        //
                        // Binder chain in regular code:
                        //
                        // + global namespace with top-level imports
                        // 
A
Andrew Casey 已提交
847
                        result = new InContainerBinder(compilation.GlobalNamespace, result, compilationUnit, inUsing: inUsing);
P
Pilchie 已提交
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
                    }

                    binderCache.TryAdd(key, result);
                }

                return (InContainerBinder)result;
            }

            private static BinderCacheKey CreateBinderCacheKey(CSharpSyntaxNode node, NodeUsage usage)
            {
                Debug.Assert(BitArithmeticUtilities.CountBits((uint)usage) <= 1, "Not a flags enum.");
                return new BinderCacheKey(node, usage);
            }

            /// <summary>
            /// Returns true if containingNode has a child that contains the specified position
            /// and has kind UsingDirective.
            /// </summary>
            /// <remarks>
            /// Usings can't see other usings, so this is extra info when looking at a namespace
            /// or compilation unit scope.
            /// </remarks>
            private bool IsInUsing(CSharpSyntaxNode containingNode)
            {
                TextSpan containingSpan = containingNode.Span;

                SyntaxToken token;
875
                if (containingNode.Kind() != SyntaxKind.CompilationUnit && _position == containingSpan.End)
P
Pilchie 已提交
876 877 878 879 880
                {
                    // This occurs at EOF
                    token = containingNode.GetLastToken();
                    Debug.Assert(token == this.syntaxTree.GetRoot().GetLastToken());
                }
881
                else if (_position < containingSpan.Start || _position > containingSpan.End) //NB: > not >=
P
Pilchie 已提交
882 883 884 885 886
                {
                    return false;
                }
                else
                {
887
                    token = containingNode.FindToken(_position);
P
Pilchie 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
                }

                var node = token.Parent;
                while (node != null && node != containingNode)
                {
                    // ACASEY: the restriction that we're only interested in children
                    // of containingNode (vs descendants) seems to be required for cases like
                    // GetSemanticInfoTests.BindAliasQualifier, which binds an alias name
                    // within a using directive.
                    if (node.IsKind(SyntaxKind.UsingDirective) && node.Parent == containingNode)
                    {
                        return true;
                    }

                    node = node.Parent;
                }
                return false;
            }

            public override Binder VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax parent)
            {
                // Need to step across the structured trivia boundary explicitly - can't just follow Parent references.
                return VisitCore(parent.ParentTrivia.Token.Parent);
            }

            /// <remarks>
            /// Used to detect whether we are in a cref parameter type.
            /// </remarks>
            public override Binder VisitCrefParameter(CrefParameterSyntax parent)
            {
                XmlCrefAttributeSyntax containingAttribute = parent.FirstAncestorOrSelf<XmlCrefAttributeSyntax>(ascendOutOfTrivia: false);
                return VisitXmlCrefAttributeInternal(containingAttribute, NodeUsage.CrefParameterOrReturnType);
            }

            /// <remarks>
            /// Used to detect whether we are in a cref return type.
            /// </remarks>
            public override Binder VisitConversionOperatorMemberCref(ConversionOperatorMemberCrefSyntax parent)
            {
927
                if (parent.Type.Span.Contains(_position))
P
Pilchie 已提交
928 929 930 931 932 933 934 935 936 937
                {
                    XmlCrefAttributeSyntax containingAttribute = parent.FirstAncestorOrSelf<XmlCrefAttributeSyntax>(ascendOutOfTrivia: false);
                    return VisitXmlCrefAttributeInternal(containingAttribute, NodeUsage.CrefParameterOrReturnType);
                }

                return base.VisitConversionOperatorMemberCref(parent);
            }

            public override Binder VisitXmlCrefAttribute(XmlCrefAttributeSyntax parent)
            {
938
                if (!LookupPosition.IsInXmlAttributeValue(_position, parent))
P
Pilchie 已提交
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
                {
                    return VisitCore(parent.Parent);
                }

                var extraInfo = NodeUsage.Normal;  // extra info for the cache.
                return VisitXmlCrefAttributeInternal(parent, extraInfo);
            }

            private Binder VisitXmlCrefAttributeInternal(XmlCrefAttributeSyntax parent, NodeUsage extraInfo)
            {
                Debug.Assert(extraInfo == NodeUsage.Normal || extraInfo == NodeUsage.CrefParameterOrReturnType,
                    "Unexpected extraInfo " + extraInfo);

                var key = CreateBinderCacheKey(parent, extraInfo);

                Binder result;
                if (!binderCache.TryGetValue(key, out result))
                {
                    CrefSyntax crefSyntax = parent.Cref;
                    MemberDeclarationSyntax memberSyntax = GetAssociatedMemberForXmlSyntax(parent);

                    bool inParameterOrReturnType = extraInfo == NodeUsage.CrefParameterOrReturnType;

                    result = (object)memberSyntax == null
                        ? MakeCrefBinderInternal(crefSyntax, VisitCore(parent.Parent), inParameterOrReturnType)
964
                        : MakeCrefBinder(crefSyntax, memberSyntax, _factory, inParameterOrReturnType);
P
Pilchie 已提交
965 966 967 968 969 970 971 972 973

                    binderCache.TryAdd(key, result);
                }

                return result;
            }

            public override Binder VisitXmlNameAttribute(XmlNameAttributeSyntax parent)
            {
974
                if (!LookupPosition.IsInXmlAttributeValue(_position, parent))
P
Pilchie 已提交
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
                {
                    return VisitCore(parent.Parent);
                }

                XmlNameAttributeElementKind elementKind = parent.GetElementKind();


                NodeUsage extraInfo;
                switch (elementKind)
                {
                    case XmlNameAttributeElementKind.Parameter:
                    case XmlNameAttributeElementKind.ParameterReference:
                        extraInfo = NodeUsage.DocumentationCommentParameter;
                        break;
                    case XmlNameAttributeElementKind.TypeParameter:
                        extraInfo = NodeUsage.DocumentationCommentTypeParameter;
                        break;
                    case XmlNameAttributeElementKind.TypeParameterReference:
                        extraInfo = NodeUsage.DocumentationCommentTypeParameterReference;
                        break;
                    default:
                        throw ExceptionUtilities.UnexpectedValue(elementKind);
                }

                // Cleverness: rather than using this node as the key, we're going to use the
                // enclosing doc comment, because all name attributes with the same element
                // kind, in the same doc comment can share the same binder.
                var key = CreateBinderCacheKey(GetEnclosingDocumentationComment(parent), extraInfo);

                Binder result;
                if (!binderCache.TryGetValue(key, out result))
                {
                    result = this.buckStopsHereBinder;

                    Binder outerBinder = VisitCore(GetEnclosingDocumentationComment(parent));
                    if ((object)outerBinder != null)
                    {
                        // The rest of the doc comment is going to report something for containing symbol -
                        // that shouldn't change just because we're in a name attribute.
                        result = result.WithContainingMemberOrLambda(outerBinder.ContainingMemberOrLambda);
                    }

                    MemberDeclarationSyntax memberSyntax = GetAssociatedMemberForXmlSyntax(parent);
                    if ((object)memberSyntax != null)
                    {
                        switch (elementKind)
                        {
                            case XmlNameAttributeElementKind.Parameter:
                            case XmlNameAttributeElementKind.ParameterReference:
                                result = GetParameterNameAttributeValueBinder(memberSyntax, result);
                                break;
                            case XmlNameAttributeElementKind.TypeParameter:
                                result = GetTypeParameterNameAttributeValueBinder(memberSyntax, includeContainingSymbols: false, nextBinder: result);
                                break;
                            case XmlNameAttributeElementKind.TypeParameterReference:
                                result = GetTypeParameterNameAttributeValueBinder(memberSyntax, includeContainingSymbols: true, nextBinder: result);
                                break;
                        }
                    }

                    binderCache.TryAdd(key, result);
                }

                return result;
            }

            /// <summary>
            /// We're in a &lt;param&gt; or &lt;paramref&gt; element, so we want a binder that can see
            /// the parameters of the associated member and nothing else.
            /// </summary>
            private Binder GetParameterNameAttributeValueBinder(MemberDeclarationSyntax memberSyntax, Binder nextBinder)
            {
                BaseMethodDeclarationSyntax baseMethodDeclSyntax = memberSyntax as BaseMethodDeclarationSyntax;
1048
                if ((object)baseMethodDeclSyntax != null && baseMethodDeclSyntax.ParameterList.ParameterCount > 0)
P
Pilchie 已提交
1049 1050 1051 1052 1053 1054 1055
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);
                    MethodSymbol method = GetMethodSymbol(baseMethodDeclSyntax, outerBinder);
                    return new WithParametersBinder(method.Parameters, nextBinder);
                }

                // As in Dev11, we do not allow <param name="value"> on events.
1056
                SyntaxKind memberKind = memberSyntax.Kind();
P
Pilchie 已提交
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
                if (memberKind == SyntaxKind.PropertyDeclaration || memberKind == SyntaxKind.IndexerDeclaration)
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);

                    BasePropertyDeclarationSyntax propertyDeclSyntax = (BasePropertyDeclarationSyntax)memberSyntax;
                    PropertySymbol property = GetPropertySymbol(propertyDeclSyntax, outerBinder);

                    ImmutableArray<ParameterSymbol> parameters = property.Parameters;

                    // BREAK: Dev11 also allows "value" for readonly properties, but that doesn't
                    // make sense and we don't have a symbol.
                    if ((object)property.SetMethod != null)
                    {
                        Debug.Assert(property.SetMethod.ParameterCount > 0);
                        parameters = parameters.Add(property.SetMethod.Parameters.Last());
                    }

                    if (parameters.Any())
                    {
                        return new WithParametersBinder(parameters, nextBinder);
                    }
                }
                else if (memberKind == SyntaxKind.DelegateDeclaration)
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);
                    SourceNamedTypeSymbol delegateType = ((NamespaceOrTypeSymbol)outerBinder.ContainingMemberOrLambda).GetSourceTypeMember((DelegateDeclarationSyntax)memberSyntax);
                    Debug.Assert((object)delegateType != null);
                    MethodSymbol invokeMethod = delegateType.DelegateInvokeMethod;
                    Debug.Assert((object)invokeMethod != null);
                    ImmutableArray<ParameterSymbol> parameters = invokeMethod.Parameters;
                    if (parameters.Any())
                    {
                        return new WithParametersBinder(parameters, nextBinder);
                    }
                }

                return nextBinder;
            }

            /// <summary>
            /// We're in a &lt;typeparam&gt; or &lt;typeparamref&gt; element, so we want a binder that can see
            /// the type parameters of the associated member and nothing else.
            /// </summary>
            private Binder GetTypeParameterNameAttributeValueBinder(MemberDeclarationSyntax memberSyntax, bool includeContainingSymbols, Binder nextBinder)
            {
                if (includeContainingSymbols)
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);
                    for (NamedTypeSymbol curr = outerBinder.ContainingType; (object)curr != null; curr = curr.ContainingType)
                    {
                        if (curr.Arity > 0)
                        {
                            nextBinder = new WithClassTypeParametersBinder(curr, nextBinder);
                        }
                    }
                }

                // NOTE: don't care about enums, since they don't have type parameters.
                TypeDeclarationSyntax typeDeclSyntax = memberSyntax as TypeDeclarationSyntax;
                if ((object)typeDeclSyntax != null && typeDeclSyntax.Arity > 0)
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);
                    SourceNamedTypeSymbol typeSymbol = ((NamespaceOrTypeSymbol)outerBinder.ContainingMemberOrLambda).GetSourceTypeMember(typeDeclSyntax);

                    // NOTE: don't include anything else in the binder chain.
                    return new WithClassTypeParametersBinder(typeSymbol, nextBinder);
                }

1125
                if (memberSyntax.Kind() == SyntaxKind.MethodDeclaration)
P
Pilchie 已提交
1126 1127 1128 1129 1130 1131 1132 1133 1134
                {
                    MethodDeclarationSyntax methodDeclSyntax = (MethodDeclarationSyntax)memberSyntax;
                    if (methodDeclSyntax.Arity > 0)
                    {
                        Binder outerBinder = VisitCore(memberSyntax.Parent);
                        MethodSymbol method = GetMethodSymbol(methodDeclSyntax, outerBinder);
                        return new WithMethodTypeParametersBinder(method, nextBinder);
                    }
                }
1135
                else if (memberSyntax.Kind() == SyntaxKind.DelegateDeclaration)
P
Pilchie 已提交
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
                {
                    Binder outerBinder = VisitCore(memberSyntax.Parent);
                    SourceNamedTypeSymbol delegateType = ((NamespaceOrTypeSymbol)outerBinder.ContainingMemberOrLambda).GetSourceTypeMember((DelegateDeclarationSyntax)memberSyntax);
                    ImmutableArray<TypeParameterSymbol> typeParameters = delegateType.TypeParameters;
                    if (typeParameters.Any())
                    {
                        return new WithClassTypeParametersBinder(delegateType, nextBinder);
                    }
                }

                return nextBinder;
            }
        }

        #region In outer type - BinderFactory

        /// <summary>
        /// Given a CrefSyntax and an associated member declaration syntax node,
        /// construct an appropriate binder for binding the cref.
        /// </summary>
        /// <param name="crefSyntax">Cref that will be bound.</param>
        /// <param name="memberSyntax">The member to which the documentation comment (logically) containing
        /// the cref syntax applies.</param>
        /// <param name="factory">Corresponding binder factory.</param>
        /// <param name="inParameterOrReturnType">True to get a special binder for cref parameter and return types.</param>
        /// <remarks>
        /// The CrefSyntax does not actually have to be within the documentation comment on the member - it
        /// could be included from another file.
        /// </remarks>
        internal static Binder MakeCrefBinder(CrefSyntax crefSyntax, MemberDeclarationSyntax memberSyntax, BinderFactory factory, bool inParameterOrReturnType = false)
        {
            Debug.Assert(crefSyntax != null);
            Debug.Assert(memberSyntax != null);

            BaseTypeDeclarationSyntax typeDeclSyntax = memberSyntax as BaseTypeDeclarationSyntax;

            Binder binder = (object)typeDeclSyntax == null
                ? factory.GetBinder(memberSyntax)
                : factory.GetBinder(memberSyntax, typeDeclSyntax.OpenBraceToken.SpanStart);

            return MakeCrefBinderInternal(crefSyntax, binder, inParameterOrReturnType);
        }

        /// <summary>
        /// Internal version of MakeCrefBinder that allows the caller to explicitly set the underlying binder.
        /// </summary>
        private static Binder MakeCrefBinderInternal(CrefSyntax crefSyntax, Binder binder, bool inParameterOrReturnType)
        {
            // After much deliberation, we eventually decided to suppress lookup of inherited members within
            // crefs, in order to match dev11's behavior (Changeset #829014).  Unfortunately, it turns out
            // that dev11 does not suppress these members when performing lookup within parameter and return
            // types, within crefs (DevDiv #586815, #598371).
            // NOTE: always allow pointer types.
            BinderFlags flags = BinderFlags.Cref | BinderFlags.SuppressConstraintChecks | BinderFlags.UnsafeRegion;
            if (inParameterOrReturnType)
            {
                flags |= BinderFlags.CrefParameterOrReturnType;
            }

            binder = binder.WithAdditionalFlags(flags);
            binder = new WithCrefTypeParametersBinder(crefSyntax, binder);
            return binder;
        }

        internal static MemberDeclarationSyntax GetAssociatedMemberForXmlSyntax(CSharpSyntaxNode xmlSyntax)
        {
1202
            Debug.Assert(xmlSyntax is XmlAttributeSyntax || xmlSyntax.Kind() == SyntaxKind.XmlEmptyElement || xmlSyntax.Kind() == SyntaxKind.XmlElementStartTag);
P
Pilchie 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228

            StructuredTriviaSyntax structuredTrivia = GetEnclosingDocumentationComment(xmlSyntax);
            SyntaxTrivia containingTrivia = structuredTrivia.ParentTrivia;
            SyntaxToken associatedToken = (SyntaxToken)containingTrivia.Token;

            CSharpSyntaxNode curr = (CSharpSyntaxNode)associatedToken.Parent;
            while (curr != null)
            {
                MemberDeclarationSyntax memberSyntax = curr as MemberDeclarationSyntax;
                if (memberSyntax != null)
                {
                    // CONSIDER: require that the xml syntax precede the start of the member span?
                    return memberSyntax;
                }
                curr = curr.Parent;
            }

            return null;
        }

        /// <summary>
        /// Walk up from an XML syntax node (attribute or tag) to the enclosing documentation comment trivia.
        /// </summary>
        private static DocumentationCommentTriviaSyntax GetEnclosingDocumentationComment(CSharpSyntaxNode xmlSyntax)
        {
            CSharpSyntaxNode curr = xmlSyntax;
1229
            for (; !SyntaxFacts.IsDocumentationCommentTrivia(curr.Kind()); curr = curr.Parent)
P
Pilchie 已提交
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
            {
            }
            Debug.Assert(curr != null);

            return (DocumentationCommentTriviaSyntax)curr;
        }

        #endregion
    }
}