Пример #1
0
        internal void RemoveNamespacesFromResult(LookupResult result)
        {
            var correctSymbols = ArrayBuilder <Symbol> .GetInstance();

            try
            {
                foreach (var s in result.Symbols)
                {
                    if (s.Kind != SymbolKind.Namespace)
                    {
                        correctSymbols.Add(s);
                    }
                }
                if (correctSymbols.Count != result.Symbols.Count)
                {
                    result.Clear();
                    result.Symbols.AddRange(correctSymbols);
                }
                return;
            }
            finally
            {
                correctSymbols.Free();
            }
        }
Пример #2
0
        /// <summary>
        /// Look for any symbols in scope with the given name and arity.
        /// </summary>
        /// <remarks>
        /// Makes a second attempt if the results are not viable, in order to produce more detailed failure information (symbols and diagnostics).
        /// </remarks>
        private Binder XSLookupSymbolsWithFallback(LookupResult result, string name, int arity, ref HashSet <DiagnosticInfo> useSiteDiagnostics, ConsList <Symbol> basesBeingResolved = null, LookupOptions options = LookupOptions.Default)
        {
            Debug.Assert(options.AreValid());

            // don't create diagnosis instances unless lookup fails
            var binder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics);

            FilterResults(result, options);
            if (result.Kind != LookupResultKind.Viable && result.Kind != LookupResultKind.Empty)
            {
                result.Clear();
                // retry to get diagnosis
                var otherBinder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics);
                Debug.Assert(binder == otherBinder);
            }

            Debug.Assert(result.IsMultiViable || result.IsClear || result.Error != null);
            return(binder);
        }
Пример #3
0
        /// <summary>
        /// Report appropriate diagnostics when lookup of a pattern member (i.e. GetEnumerator, Current, or MoveNext) fails.
        /// </summary>
        /// <param name="lookupResult">Failed lookup result.</param>
        /// <param name="patternType">Type in which member was looked up.</param>
        /// <param name="memberName">Name of looked up member.</param>
        /// <param name="warningsOnly">True if failures should result in warnings; false if they should result in errors.</param>
        /// <param name="diagnostics">Populated appropriately.</param>
        private void ReportPatternMemberLookupDiagnostics(LookupResult lookupResult, TypeSymbol patternType, string memberName, bool warningsOnly, DiagnosticBag diagnostics)
        {
            if (lookupResult.Symbols.Any())
            {
                if (warningsOnly)
                {
                    ReportEnumerableWarning(diagnostics, patternType, lookupResult.Symbols.First());
                }
                else
                {
                    lookupResult.Clear();

                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    this.LookupMembersInType(
                        lookupResult,
                        patternType,
                        memberName,
                        arity: 0,
                        basesBeingResolved: null,
                        options: LookupOptions.Default,
                        originalBinder: this,
                        diagnose: true,
                        useSiteDiagnostics: ref useSiteDiagnostics);

                    diagnostics.Add(this.syntax.Expression, useSiteDiagnostics);

                    if (lookupResult.Error != null)
                    {
                        diagnostics.Add(lookupResult.Error, this.syntax.Expression.Location);
                    }
                }
            }
            else if (!warningsOnly)
            {
                diagnostics.Add(ErrorCode.ERR_NoSuchMember, this.syntax.Expression.Location, patternType, memberName);
            }
        }
Пример #4
0
        /// <summary>
        /// Called after it is determined that the expression being enumerated is of a type that
        /// has a GetEnumerator method.  Checks to see if the return type of the GetEnumerator
        /// method is suitable (i.e. has Current and MoveNext).
        /// </summary>
        /// <param name="builder">Must be non-null and contain a non-null GetEnumeratorMethod.</param>
        /// <param name="diagnostics">Will be populated with pattern diagnostics.</param>
        /// <returns>True if the return type has suitable members.</returns>
        /// <remarks>
        /// It seems that every failure path reports the same diagnostics, so that is left to the caller.
        /// </remarks>
        private bool SatisfiesForEachPattern(ref ForEachEnumeratorInfo.Builder builder, DiagnosticBag diagnostics)
        {
            Debug.Assert((object)builder.GetEnumeratorMethod != null);

            MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod;
            TypeSymbol   enumeratorType      = getEnumeratorMethod.ReturnType;

            switch (enumeratorType.TypeKind)
            {
            case TypeKind.Class:
            case TypeKind.Struct:
            case TypeKind.Interface:
            case TypeKind.TypeParameter:   // Not specifically mentioned in the spec, but consistent with Dev10.
            case TypeKind.DynamicType:     // Not specifically mentioned in the spec, but consistent with Dev10.
                break;

            case TypeKind.Submission:
                // submission class is synthesized and should never appear in a foreach:
                throw ExceptionUtilities.UnexpectedValue(enumeratorType.TypeKind);

            default:
                return(false);
            }

            // Use a try-finally since there are many return points
            LookupResult lookupResult = LookupResult.GetInstance();

            try
            {
                // If we searched for the accessor directly, we could reuse FindForEachPatternMethod and we
                // wouldn't have to mangle CurrentPropertyName.  However, Dev10 searches for the property and
                // then extracts the accessor, so we should do the same (in case of accessors with non-standard
                // names).
                HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                this.LookupMembersInType(
                    lookupResult,
                    enumeratorType,
                    CurrentPropertyName,
                    arity: 0,
                    basesBeingResolved: null,
                    options: LookupOptions.Default, // properties are not invocable - their accessors are
                    originalBinder: this,
                    diagnose: false,
                    useSiteDiagnostics: ref useSiteDiagnostics);

                diagnostics.Add(this.syntax.Expression, useSiteDiagnostics);
                useSiteDiagnostics = null;

                if (!lookupResult.IsSingleViable)
                {
                    ReportPatternMemberLookupDiagnostics(lookupResult, enumeratorType, CurrentPropertyName, warningsOnly: false, diagnostics: diagnostics);
                    return(false);
                }

                // lookupResult.IsSingleViable above guaranteed there is exactly one symbol.
                Symbol lookupSymbol = lookupResult.SingleSymbolOrDefault;
                Debug.Assert((object)lookupSymbol != null);

                if (lookupSymbol.IsStatic || lookupSymbol.DeclaredAccessibility != Accessibility.Public || lookupSymbol.Kind != SymbolKind.Property)
                {
                    return(false);
                }

                // NOTE: accessor can be inherited from overridden property
                MethodSymbol currentPropertyGetterCandidate = ((PropertySymbol)lookupSymbol).GetOwnOrInheritedGetMethod();

                if ((object)currentPropertyGetterCandidate == null)
                {
                    return(false);
                }
                else
                {
                    bool isAccessible = this.IsAccessible(currentPropertyGetterCandidate, ref useSiteDiagnostics);
                    diagnostics.Add(this.syntax.Expression, useSiteDiagnostics);

                    if (!isAccessible)
                    {
                        // NOTE: per Dev10 and the spec, the property has to be public, but the accessor just has to be accessible
                        return(false);
                    }
                }

                builder.CurrentPropertyGetter = currentPropertyGetterCandidate;

                lookupResult.Clear(); // Reuse the same LookupResult

                MethodSymbol moveNextMethodCandidate = FindForEachPatternMethod(enumeratorType, MoveNextMethodName, lookupResult, warningsOnly: false, diagnostics: diagnostics);

                // SPEC VIOLATION: Dev10 checks the return type of the original definition, rather than the return type of the actual method.

                if ((object)moveNextMethodCandidate == null ||
                    moveNextMethodCandidate.IsStatic || moveNextMethodCandidate.DeclaredAccessibility != Accessibility.Public ||
                    ((MethodSymbol)moveNextMethodCandidate.OriginalDefinition).ReturnType.SpecialType != SpecialType.System_Boolean)
                {
                    return(false);
                }

                builder.MoveNextMethod = moveNextMethodCandidate;

                return(true);
            }
            finally
            {
                lookupResult.Free();
            }
        }
Пример #5
0
        /// <summary>
        /// Report appropriate diagnostics when lookup of a pattern member (i.e. GetEnumerator, Current, or MoveNext) fails.
        /// </summary>
        /// <param name="lookupResult">Failed lookup result.</param>
        /// <param name="patternType">Type in which member was looked up.</param>
        /// <param name="memberName">Name of looked up member.</param>
        /// <param name="warningsOnly">True if failures should result in warnings; false if they should result in errors.</param>
        /// <param name="diagnostics">Populated appropriately.</param>
        private void ReportPatternMemberLookupDiagnostics(LookupResult lookupResult, TypeSymbol patternType, string memberName, bool warningsOnly, DiagnosticBag diagnostics)
        {
            if (lookupResult.Symbols.Any())
            {
                if (warningsOnly)
                {
                    ReportEnumerableWarning(diagnostics, patternType, lookupResult.Symbols.First());
                }
                else
                {
                    lookupResult.Clear();

                    HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                    this.LookupMembersInType(
                        lookupResult,
                        patternType,
                        memberName,
                        arity: 0,
                        basesBeingResolved: null,
                        options: LookupOptions.Default,
                        originalBinder: this,
                        diagnose: true,
                        useSiteDiagnostics: ref useSiteDiagnostics);

                    diagnostics.Add(_syntax.Expression, useSiteDiagnostics);

                    if (lookupResult.Error != null)
                    {
                        diagnostics.Add(lookupResult.Error, _syntax.Expression.Location);
                    }
                }
            }
            else if (!warningsOnly)
            {
                diagnostics.Add(ErrorCode.ERR_NoSuchMember, _syntax.Expression.Location, patternType, memberName);
            }
        }
Пример #6
0
        private Binder XSLookupSymbolsInternal(
            LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(result.IsClear);
            Debug.Assert(options.AreValid());

            // X# looks for functions first
            //if (Compilation.Options.HasRuntime)
            {
                // check for function calls method calls outside the current class
                bool check = (options.HasFlag(LookupOptions.MustNotBeInstance) && !options.HasFlag(LookupOptions.MustNotBeMethod));
                if (check)
                {
                    var funcOptions = options;
                    funcOptions |= LookupOptions.MustBeInvocableIfMember;
                    Binder scope = this;
                    while (scope != null)
                    {
                        if (scope is InContainerBinder && scope.ContainingType == null) // at the namespace level, so outside of all types
                        {
                            scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, funcOptions, this, diagnose, ref useSiteDiagnostics);
                            FilterResults(result, options);
                            if (!result.IsClear)
                            {
                                break;
                            }
                        }
                        scope = scope.Next;
                    }
                }
            }
            LookupResult functionResults = LookupResult.GetInstance();

            if (!result.IsClear)
            {
                foreach (var symbol in result.Symbols)
                {
                    if (symbol is MethodSymbol)
                    {
                        var ms = symbol as MethodSymbol;
                        if (ms.IsStatic && ms.ContainingType.Name.EndsWith("Functions", XSharpString.Comparison))
                        {
                            SingleLookupResult single = new SingleLookupResult(LookupResultKind.Viable, ms, null);
                            functionResults.MergeEqual(single);
                        }
                    }
                }
                result.Clear();
            }
            Binder binder = null;

            for (var scope = this; scope != null && !result.IsMultiViable; scope = scope.Next)
            {
                if (binder != null)
                {
                    var tmp = LookupResult.GetInstance();
                    scope.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
                    FilterResults(tmp, options);
                    result.MergeEqual(tmp);
                    tmp.Free();
                }
                else
                {
                    scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
                    FilterResults(result, options);
                    if (!result.IsClear)
                    {
                        binder = scope;
                    }
                }
            }
            if (!functionResults.IsClear)
            {
                // compare the function results with the overall results found
                // create a list of functions and methods
                // function first and then the methods
                LookupResult mergedResults = LookupResult.GetInstance();
                mergedResults.MergeEqual(functionResults);
                // now add the symbols from result that do not exist
                for (int j = 0; j < result.Symbols.Count; j++)
                {
                    var sym   = result.Symbols[j];
                    var found = false;
                    for (int i = 0; i < mergedResults.Symbols.Count; i++)
                    {
                        if (sym == mergedResults.Symbols[i])
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        SingleLookupResult single = new SingleLookupResult(LookupResultKind.Viable, sym, null);
                        mergedResults.MergeEqual(single);
                    }
                }
                result.Clear();
                result.MergeEqual(mergedResults);
            }
            // C563 Make sure the error is generated for Inaccessible types.
            if (!result.IsClear && result.Kind == LookupResultKind.Inaccessible && result.Error != null)
            {
                // we only want to add this for internal fields (globals)
                if (result.Symbols[0].Kind == SymbolKind.Field)
                {
                    if (useSiteDiagnostics == null)
                    {
                        useSiteDiagnostics = new HashSet <DiagnosticInfo>();
                    }
                    useSiteDiagnostics.Add(result.Error);
                }
            }
            return(binder);
        }