Пример #1
0
        /// <summary>
        /// Adds aliases of a specified reference to the merged set of aliases.
        /// Consider the following special cases:
        /// 
        /// o {} + {} = {} 
        ///   If neither reference has any aliases then the result has no aliases.
        /// 
        /// o {A} + {} = {A, global}
        ///   {} + {A} = {A, global}
        ///   
        ///   If one and only one of the references has aliases we add the global alias since the 
        ///   referenced declarations should now be accessible both via existing aliases 
        ///   as well as unqualified.
        ///   
        /// o {A, A} + {A, B, B} = {A, A, B, B}
        ///   We preserve dups in each alias array, but avoid making more dups when merging.
        /// </summary>
        internal void Merge(MetadataReference reference)
        {
            if (reference.Properties.HasRecursiveAliases)
            {
                if (RecursiveAliasesOpt == null)
                {
                    RecursiveAliasesOpt = ArrayBuilder<string>.GetInstance();
                    RecursiveAliasesOpt.AddRange(reference.Properties.Aliases);
                    return;
                }
            }
            else
            {
                if (AliasesOpt == null)
                {
                    AliasesOpt = ArrayBuilder<string>.GetInstance();
                    AliasesOpt.AddRange(reference.Properties.Aliases);
                    return;
                }
            }

            Merge(
                aliases: reference.Properties.HasRecursiveAliases ? RecursiveAliasesOpt : AliasesOpt, 
                newAliases: reference.Properties.Aliases);
        }
Пример #2
0
        // Given C<int>.D<string, double>, yields { int, string, double }
        public static void GetAllTypeArguments(this NamedTypeSymbol type, ArrayBuilder<TypeSymbol> builder)
        {
            var outer = type.ContainingType;
            if (outer != null)
            {
                outer.GetAllTypeArguments(builder);
            }

            builder.AddRange(type.TypeArguments);
        }
Пример #3
0
        internal static void GetConsolidatedTypeArguments(this ITypeReference typeReference, ArrayBuilder<ITypeReference> consolidatedTypeArguments, EmitContext context)
        {
            INestedTypeReference nestedTypeReference = typeReference.AsNestedTypeReference;
            nestedTypeReference?.GetContainingType(context).GetConsolidatedTypeArguments(consolidatedTypeArguments, context);

            IGenericTypeInstanceReference genTypeInstance = typeReference.AsGenericTypeInstanceReference;
            if (genTypeInstance != null)
            {
                consolidatedTypeArguments.AddRange(genTypeInstance.GetGenericArguments(context));
            }
        }
 /// <summary>
 /// Finds references using the externally defined <see cref="IFindReferencesResultProvider"/>s.
 /// </summary>
 private async Task AddExternalReferencesAsync(Document document, int position, ArrayBuilder<INavigableItem> builder, CancellationToken cancellationToken)
 {
     // CONSIDER: Do the computation in parallel.
     foreach (var provider in _externalReferencesProviders)
     {
         var references = await provider.FindReferencesAsync(document, position, cancellationToken).ConfigureAwait(false);
         if (references != null)
         {
             builder.AddRange(references.WhereNotNull());
         }
     }
 }
Пример #5
0
        public static void AppendReferenceChanges(IEnumerable<ProjectChanges> projectChangesList, PreviewEngine engine, ArrayBuilder<AbstractChange> builder)
        {
            foreach (var projectChanges in projectChangesList)
            {
                var projectId = projectChanges.ProjectId;
                var oldSolution = projectChanges.OldProject.Solution;
                var newSolution = projectChanges.NewProject.Solution;
                var projectName = oldSolution.GetProject(projectId).Name;

                // Metadata references
                var addedMetadataReferenceChanges = projectChanges
                    .GetAddedMetadataReferences()
                    .Select(r => new MetadataReferenceChange(r, projectId, projectName, isAdded: true, engine: engine));
                builder.AddRange(addedMetadataReferenceChanges);

                var removedMetadataReferenceChanges = projectChanges
                    .GetRemovedMetadataReferences()
                    .Select(r => new MetadataReferenceChange(r, projectId, projectName, isAdded: false, engine: engine));
                builder.AddRange(removedMetadataReferenceChanges);

                // Project references
                var addedProjectReferenceChanges = projectChanges
                    .GetAddedProjectReferences()
                    .Select(r => new ProjectReferenceChange(r, newSolution.GetProject(r.ProjectId).Name, projectId, projectName, isAdded: true, engine: engine));
                builder.AddRange(addedProjectReferenceChanges);

                var removedProjectReferenceChanges = projectChanges
                    .GetRemovedProjectReferences()
                    .Select(r => new ProjectReferenceChange(r, oldSolution.GetProject(r.ProjectId).Name, projectId, projectName, isAdded: false, engine: engine));
                builder.AddRange(removedProjectReferenceChanges);

                // Analyzer references
                var addedAnalyzerReferenceChanges = projectChanges
                    .GetAddedAnalyzerReferences()
                    .Select(r => new AnalyzerReferenceChange(r, projectId, projectName, isAdded: true, engine: engine));
                builder.AddRange(addedAnalyzerReferenceChanges);

                var removedAnalyzerReferenceChanges = projectChanges
                    .GetRemovedAnalyzerReferences()
                    .Select(r => new AnalyzerReferenceChange(r, projectId, projectName, isAdded: false, engine: engine));
                builder.AddRange(removedAnalyzerReferenceChanges);
            }
        }
Пример #6
0
        public void AddRange()
        {
            var builder = new ArrayBuilder<int>();

            builder.AddRange(new int[0], 0, 0);
            AssertEx.Equal(new int[0], builder.ToArray());

            builder.AddRange(new[] { 1, 2, 3 }, 0, 3);
            AssertEx.Equal(new[] { 1, 2, 3 }, builder.ToArray());

            builder.AddRange(new[] { 1, 2, 3 }, 2, 0);
            AssertEx.Equal(new[] { 1, 2, 3 }, builder.ToArray());

            builder.AddRange(new[] { 1, 2, 3 }, 1, 1);
            AssertEx.Equal(new[] { 1, 2, 3, 2 }, builder.ToArray());

            builder.AddRange(new[] { 1, 2, 3 }, 1, 2);
            AssertEx.Equal(new[] { 1, 2, 3, 2, 2, 3 }, builder.ToArray());

            builder.AddRange(new[] { 1, 2, 3 }, 2, 1);
            AssertEx.Equal(new[] { 1, 2, 3, 2, 2, 3, 3 }, builder.ToArray());
        }
Пример #7
0
        public static void GetExpressionSymbols(this BoundExpression node, ArrayBuilder<Symbol> symbols, BoundNode parent, Binder binder)
        {
            switch (node.Kind)
            {
                case BoundKind.MethodGroup:
                    // Special case: if we are looking for info on "M" in "new Action(M)" in the context of a parent 
                    // then we want to get the symbol that overload resolution chose for M, not on the whole method group M.
                    var delegateCreation = parent as BoundDelegateCreationExpression;
                    if (delegateCreation != null && (object)delegateCreation.MethodOpt != null)
                    {
                        symbols.Add(delegateCreation.MethodOpt);
                    }
                    else
                    {
                        symbols.AddRange(CSharpSemanticModel.GetReducedAndFilteredMethodGroupSymbols(binder, (BoundMethodGroup)node));
                    }
                    break;

                case BoundKind.BadExpression:
                    symbols.AddRange(((BoundBadExpression)node).Symbols);
                    break;

                case BoundKind.DelegateCreationExpression:
                    var expr = (BoundDelegateCreationExpression)node;
                    var ctor = expr.Type.GetMembers(WellKnownMemberNames.InstanceConstructorName).FirstOrDefault();
                    if ((object)ctor != null)
                    {
                        symbols.Add(ctor);
                    }
                    break;

                case BoundKind.Call:
                    // Either overload resolution succeeded for this call or it did not. If it did not
                    // succeed then we've stashed the original method symbols from the method group,
                    // and we should use those as the symbols displayed for the call. If it did succeed
                    // then we did not stash any symbols; just fall through to the default case.

                    var originalMethods = ((BoundCall)node).OriginalMethodsOpt;
                    if (originalMethods.IsDefault)
                    {
                        goto default;
                    }
                    symbols.AddRange(originalMethods);
                    break;

                case BoundKind.IndexerAccess:
                    // Same behavior as for a BoundCall: if overload resolution failed, pull out stashed candidates;
                    // otherwise use the default behavior.

                    var originalIndexers = ((BoundIndexerAccess)node).OriginalIndexersOpt;
                    if (originalIndexers.IsDefault)
                    {
                        goto default;
                    }
                    symbols.AddRange(originalIndexers);
                    break;

                default:
                    var symbol = node.ExpressionSymbol;
                    if ((object)symbol != null)
                    {
                        symbols.Add(symbol);
                    }
                    break;
            }
        }
 internal static void AddSegments(ArrayBuilder<SourceText> builder, SourceText text)
 {
     CompositeText composite = text as CompositeText;
     if (composite == null)
     {
         builder.Add(text);
     }
     else
     {
         builder.AddRange(composite.texts);
     }
 }
Пример #9
0
        /// <summary>
        /// Internal helper for MatchPatternInternal
        /// </summary>
        /// <remarks>
        /// PERF: Designed to minimize allocations in common cases.
        /// If there's no match, then null is returned.
        /// If there's a single match, or the caller only wants the first match, then it is returned (as a Nullable)
        /// If there are multiple matches, and the caller wants them all, then a List is allocated.
        /// </remarks>
        /// <param name="candidate">The word being tested.</param>
        /// <param name="segment">The segment of the pattern to check against the candidate.</param>
        /// <param name="matches">The result array to place the matches in.</param>
        /// <param name="fuzzyMatch">If a fuzzy match should be performed</param>
        /// <returns>If there's only one match, then the return value is that match. Otherwise it is null.</returns>
        private bool MatchPatternSegment(
            string candidate,
            PatternSegment segment,
            ArrayBuilder <PatternMatch> matches,
            bool fuzzyMatch)
        {
            if (fuzzyMatch && !_allowFuzzyMatching)
            {
                return(false);
            }

            // First check if the segment matches as is.  This is also useful if the segment contains
            // characters we would normally strip when splitting into parts that we also may want to
            // match in the candidate.  For example if the segment is "@int" and the candidate is
            // "@int", then that will show up as an exact match here.
            //
            // Note: if the segment contains a space or an asterisk then we must assume that it's a
            // multi-word segment.
            if (!ContainsSpaceOrAsterisk(segment.TotalTextChunk.Text))
            {
                var match = MatchPatternChunk(
                    candidate, segment.TotalTextChunk, punctuationStripped: false, fuzzyMatch: fuzzyMatch);
                if (match != null)
                {
                    matches.Add(match.Value);
                    return(true);
                }
            }

            // The logic for pattern matching is now as follows:
            //
            // 1) Break the segment passed in into words.  Breaking is rather simple and a
            //    good way to think about it that if gives you all the individual alphanumeric words
            //    of the pattern.
            //
            // 2) For each word try to match the word against the candidate value.
            //
            // 3) Matching logic is outlined in NonFuzzyMatchPatternChunk. It's not repeated here to
            //    prevent having multiple places to keep up to date.
            //
            // Only if all words have some sort of match is the pattern considered matched.

            // Special case a simple pattern (alpha-numeric with no spaces).  This is the common
            // case and we want to prevent unnecessary overhead.
            var subWordTextChunks = segment.SubWordTextChunks;

            if (subWordTextChunks.Length == 1)
            {
                var result = MatchPatternChunk(
                    candidate, subWordTextChunks[0], punctuationStripped: true, fuzzyMatch: fuzzyMatch);
                if (result == null)
                {
                    return(false);
                }

                matches.Add(result.Value);
                return(true);
            }
            else
            {
                var tempMatches = ArrayBuilder <PatternMatch> .GetInstance();

                try
                {
                    foreach (var subWordTextChunk in subWordTextChunks)
                    {
                        // Try to match the candidate with this word
                        var result = MatchPatternChunk(
                            candidate, subWordTextChunk, punctuationStripped: true, fuzzyMatch: fuzzyMatch);
                        if (result == null)
                        {
                            return(false);
                        }

                        tempMatches.Add(result.Value);
                    }

                    matches.AddRange(tempMatches);
                    return(tempMatches.Count > 0);
                }
                finally
                {
                    tempMatches.Free();
                }
            }
        }
Пример #10
0
        /// <summary>
        /// The strategy of this rewrite is to do rewrite "locally".
        /// We analyze arguments of the concat in a shallow fashion assuming that
        /// lowering and optimizations (including this one) is already done for the arguments.
        /// Based on the arguments we select the most appropriate pattern for the current node.
        ///
        /// NOTE: it is not guaranteed that the node that we chose will be the most optimal since we have only
        ///       local information - i.e. we look at the arguments, but we do not know about siblings.
        ///       When we move to the parent, the node may be rewritten by this or some another optimization.
        ///
        /// Example:
        ///     result = ( "abc" + "def" + null ?? expr1 + "moo" + "baz" ) + expr2
        ///
        /// Will rewrite into:
        ///     result = Concat("abcdef", expr2)
        ///
        /// However there will be transient nodes like  Concat(expr1 + "moo")  that will not be present in the
        /// resulting tree.
        ///
        /// </summary>
        private BoundExpression RewriteStringConcatenation(SyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type)
        {
            Debug.Assert(
                operatorKind == BinaryOperatorKind.StringConcatenation ||
                operatorKind == BinaryOperatorKind.StringAndObjectConcatenation ||
                operatorKind == BinaryOperatorKind.ObjectAndStringConcatenation);

            if (_inExpressionLambda)
            {
                return(RewriteStringConcatInExpressionLambda(syntax, operatorKind, loweredLeft, loweredRight, type));
            }

            // Convert both sides to a string (calling ToString if necessary)
            loweredLeft  = ConvertConcatExprToString(syntax, loweredLeft);
            loweredRight = ConvertConcatExprToString(syntax, loweredRight);

            Debug.Assert(loweredLeft.Type.IsStringType() || loweredLeft.ConstantValue?.IsNull == true || loweredLeft.Type.IsErrorType());
            Debug.Assert(loweredRight.Type.IsStringType() || loweredRight.ConstantValue?.IsNull == true || loweredRight.Type.IsErrorType());

            // try fold two args without flattening.
            var folded = TryFoldTwoConcatOperands(syntax, loweredLeft, loweredRight);

            if (folded != null)
            {
                return(folded);
            }

            // flatten and merge -  ( expr1 + "A" ) + ("B" + expr2) ===> (expr1 + "AB" + expr2)
            ArrayBuilder <BoundExpression> leftFlattened = ArrayBuilder <BoundExpression> .GetInstance();

            ArrayBuilder <BoundExpression> rightFlattened = ArrayBuilder <BoundExpression> .GetInstance();

            FlattenConcatArg(loweredLeft, leftFlattened);
            FlattenConcatArg(loweredRight, rightFlattened);

            if (leftFlattened.Any() && rightFlattened.Any())
            {
                folded = TryFoldTwoConcatOperands(syntax, leftFlattened.Last(), rightFlattened.First());
                if (folded != null)
                {
                    rightFlattened[0] = folded;
                    leftFlattened.RemoveLast();
                }
            }

            leftFlattened.AddRange(rightFlattened);
            rightFlattened.Free();

            BoundExpression result;

            switch (leftFlattened.Count)
            {
            case 0:
                result = _factory.StringLiteral(string.Empty);
                break;

            case 1:
                // All code paths which reach here (through TryFoldTwoConcatOperands) have already called
                // RewriteStringConcatenationOneExpr if necessary
                result = leftFlattened[0];
                break;

            case 2:
                var left  = leftFlattened[0];
                var right = leftFlattened[1];
                result = RewriteStringConcatenationTwoExprs(syntax, left, right);
                break;

            case 3:
            {
                var first  = leftFlattened[0];
                var second = leftFlattened[1];
                var third  = leftFlattened[2];
                result = RewriteStringConcatenationThreeExprs(syntax, first, second, third);
            }
            break;

            case 4:
            {
                var first  = leftFlattened[0];
                var second = leftFlattened[1];
                var third  = leftFlattened[2];
                var fourth = leftFlattened[3];
                result = RewriteStringConcatenationFourExprs(syntax, first, second, third, fourth);
            }
            break;

            default:
                result = RewriteStringConcatenationManyExprs(syntax, leftFlattened.ToImmutable());
                break;
            }

            leftFlattened.Free();
            return(result);
        }
Пример #11
0
        internal void GetSimpleBuiltInOperators(BinaryOperatorKind kind, ArrayBuilder<BinaryOperatorSignature> operators)
        {
            if (builtInOperators == null)
            {
                var logicalOperators = new ImmutableArray<BinaryOperatorSignature>[]
                {
                    ImmutableArray<BinaryOperatorSignature>.Empty, //multiplication
                    ImmutableArray<BinaryOperatorSignature>.Empty, //addition
                    ImmutableArray<BinaryOperatorSignature>.Empty, //subtraction
                    ImmutableArray<BinaryOperatorSignature>.Empty, //division
                    ImmutableArray<BinaryOperatorSignature>.Empty, //remainder
                    ImmutableArray<BinaryOperatorSignature>.Empty, //left shift
                    ImmutableArray<BinaryOperatorSignature>.Empty, //right shift
                    ImmutableArray<BinaryOperatorSignature>.Empty, //equal
                    ImmutableArray<BinaryOperatorSignature>.Empty, //not equal
                    ImmutableArray<BinaryOperatorSignature>.Empty, //greater than
                    ImmutableArray<BinaryOperatorSignature>.Empty, //less than
                    ImmutableArray<BinaryOperatorSignature>.Empty, //greater than or equal
                    ImmutableArray<BinaryOperatorSignature>.Empty, //less than or equal
                    ImmutableArray.Create<BinaryOperatorSignature>(GetSignature(BinaryOperatorKind.LogicalBoolAnd)), //and
                    ImmutableArray<BinaryOperatorSignature>.Empty, //xor
                    ImmutableArray.Create<BinaryOperatorSignature>(GetSignature(BinaryOperatorKind.LogicalBoolOr)), //or
                };

                var nonLogicalOperators = new ImmutableArray<BinaryOperatorSignature>[]
                {
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntMultiplication),
                        GetSignature(BinaryOperatorKind.UIntMultiplication),
                        GetSignature(BinaryOperatorKind.LongMultiplication),
                        GetSignature(BinaryOperatorKind.ULongMultiplication),
                        GetSignature(BinaryOperatorKind.FloatMultiplication),
                        GetSignature(BinaryOperatorKind.DoubleMultiplication),
                        GetSignature(BinaryOperatorKind.DecimalMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedIntMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedUIntMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedLongMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedULongMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedFloatMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedDoubleMultiplication),
                        GetSignature(BinaryOperatorKind.LiftedDecimalMultiplication),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntAddition),
                        GetSignature(BinaryOperatorKind.UIntAddition),
                        GetSignature(BinaryOperatorKind.LongAddition),
                        GetSignature(BinaryOperatorKind.ULongAddition),
                        GetSignature(BinaryOperatorKind.FloatAddition),
                        GetSignature(BinaryOperatorKind.DoubleAddition),
                        GetSignature(BinaryOperatorKind.DecimalAddition),
                        GetSignature(BinaryOperatorKind.LiftedIntAddition),
                        GetSignature(BinaryOperatorKind.LiftedUIntAddition),
                        GetSignature(BinaryOperatorKind.LiftedLongAddition),
                        GetSignature(BinaryOperatorKind.LiftedULongAddition),
                        GetSignature(BinaryOperatorKind.LiftedFloatAddition),
                        GetSignature(BinaryOperatorKind.LiftedDoubleAddition),
                        GetSignature(BinaryOperatorKind.LiftedDecimalAddition),
                        GetSignature(BinaryOperatorKind.StringConcatenation),
                        GetSignature(BinaryOperatorKind.StringAndObjectConcatenation),
                        GetSignature(BinaryOperatorKind.ObjectAndStringConcatenation),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntSubtraction),
                        GetSignature(BinaryOperatorKind.UIntSubtraction),
                        GetSignature(BinaryOperatorKind.LongSubtraction),
                        GetSignature(BinaryOperatorKind.ULongSubtraction),
                        GetSignature(BinaryOperatorKind.FloatSubtraction),
                        GetSignature(BinaryOperatorKind.DoubleSubtraction),
                        GetSignature(BinaryOperatorKind.DecimalSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedIntSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedUIntSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedLongSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedULongSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedFloatSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedDoubleSubtraction),
                        GetSignature(BinaryOperatorKind.LiftedDecimalSubtraction),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntDivision),
                        GetSignature(BinaryOperatorKind.UIntDivision),
                        GetSignature(BinaryOperatorKind.LongDivision),
                        GetSignature(BinaryOperatorKind.ULongDivision),
                        GetSignature(BinaryOperatorKind.FloatDivision),
                        GetSignature(BinaryOperatorKind.DoubleDivision),
                        GetSignature(BinaryOperatorKind.DecimalDivision),
                        GetSignature(BinaryOperatorKind.LiftedIntDivision),
                        GetSignature(BinaryOperatorKind.LiftedUIntDivision),
                        GetSignature(BinaryOperatorKind.LiftedLongDivision),
                        GetSignature(BinaryOperatorKind.LiftedULongDivision),
                        GetSignature(BinaryOperatorKind.LiftedFloatDivision),
                        GetSignature(BinaryOperatorKind.LiftedDoubleDivision),
                        GetSignature(BinaryOperatorKind.LiftedDecimalDivision),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntRemainder),
                        GetSignature(BinaryOperatorKind.UIntRemainder),
                        GetSignature(BinaryOperatorKind.LongRemainder),
                        GetSignature(BinaryOperatorKind.ULongRemainder),
                        GetSignature(BinaryOperatorKind.FloatRemainder),
                        GetSignature(BinaryOperatorKind.DoubleRemainder),
                        GetSignature(BinaryOperatorKind.DecimalRemainder),
                        GetSignature(BinaryOperatorKind.LiftedIntRemainder),
                        GetSignature(BinaryOperatorKind.LiftedUIntRemainder),
                        GetSignature(BinaryOperatorKind.LiftedLongRemainder),
                        GetSignature(BinaryOperatorKind.LiftedULongRemainder),
                        GetSignature(BinaryOperatorKind.LiftedFloatRemainder),
                        GetSignature(BinaryOperatorKind.LiftedDoubleRemainder),
                        GetSignature(BinaryOperatorKind.LiftedDecimalRemainder),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntLeftShift),
                        GetSignature(BinaryOperatorKind.UIntLeftShift),
                        GetSignature(BinaryOperatorKind.LongLeftShift),
                        GetSignature(BinaryOperatorKind.ULongLeftShift),
                        GetSignature(BinaryOperatorKind.LiftedIntLeftShift),
                        GetSignature(BinaryOperatorKind.LiftedUIntLeftShift),
                        GetSignature(BinaryOperatorKind.LiftedLongLeftShift),
                        GetSignature(BinaryOperatorKind.LiftedULongLeftShift),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntRightShift),
                        GetSignature(BinaryOperatorKind.UIntRightShift),
                        GetSignature(BinaryOperatorKind.LongRightShift),
                        GetSignature(BinaryOperatorKind.ULongRightShift),
                        GetSignature(BinaryOperatorKind.LiftedIntRightShift),
                        GetSignature(BinaryOperatorKind.LiftedUIntRightShift),
                        GetSignature(BinaryOperatorKind.LiftedLongRightShift),
                        GetSignature(BinaryOperatorKind.LiftedULongRightShift),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntEqual),
                        GetSignature(BinaryOperatorKind.UIntEqual),
                        GetSignature(BinaryOperatorKind.LongEqual),
                        GetSignature(BinaryOperatorKind.ULongEqual),
                        GetSignature(BinaryOperatorKind.FloatEqual),
                        GetSignature(BinaryOperatorKind.DoubleEqual),
                        GetSignature(BinaryOperatorKind.DecimalEqual),
                        GetSignature(BinaryOperatorKind.BoolEqual),
                        GetSignature(BinaryOperatorKind.LiftedIntEqual),
                        GetSignature(BinaryOperatorKind.LiftedUIntEqual),
                        GetSignature(BinaryOperatorKind.LiftedLongEqual),
                        GetSignature(BinaryOperatorKind.LiftedULongEqual),
                        GetSignature(BinaryOperatorKind.LiftedFloatEqual),
                        GetSignature(BinaryOperatorKind.LiftedDoubleEqual),
                        GetSignature(BinaryOperatorKind.LiftedDecimalEqual),
                        GetSignature(BinaryOperatorKind.LiftedBoolEqual),
                        GetSignature(BinaryOperatorKind.ObjectEqual),
                        GetSignature(BinaryOperatorKind.StringEqual),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntNotEqual),
                        GetSignature(BinaryOperatorKind.UIntNotEqual),
                        GetSignature(BinaryOperatorKind.LongNotEqual),
                        GetSignature(BinaryOperatorKind.ULongNotEqual),
                        GetSignature(BinaryOperatorKind.FloatNotEqual),
                        GetSignature(BinaryOperatorKind.DoubleNotEqual),
                        GetSignature(BinaryOperatorKind.DecimalNotEqual),
                        GetSignature(BinaryOperatorKind.BoolNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedIntNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedUIntNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedLongNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedULongNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedFloatNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedDoubleNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedDecimalNotEqual),
                        GetSignature(BinaryOperatorKind.LiftedBoolNotEqual),
                        GetSignature(BinaryOperatorKind.ObjectNotEqual),
                        GetSignature(BinaryOperatorKind.StringNotEqual),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntGreaterThan),
                        GetSignature(BinaryOperatorKind.UIntGreaterThan),
                        GetSignature(BinaryOperatorKind.LongGreaterThan),
                        GetSignature(BinaryOperatorKind.ULongGreaterThan),
                        GetSignature(BinaryOperatorKind.FloatGreaterThan),
                        GetSignature(BinaryOperatorKind.DoubleGreaterThan),
                        GetSignature(BinaryOperatorKind.DecimalGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedIntGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedUIntGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedLongGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedULongGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedFloatGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedDoubleGreaterThan),
                        GetSignature(BinaryOperatorKind.LiftedDecimalGreaterThan),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntLessThan),
                        GetSignature(BinaryOperatorKind.UIntLessThan),
                        GetSignature(BinaryOperatorKind.LongLessThan),
                        GetSignature(BinaryOperatorKind.ULongLessThan),
                        GetSignature(BinaryOperatorKind.FloatLessThan),
                        GetSignature(BinaryOperatorKind.DoubleLessThan),
                        GetSignature(BinaryOperatorKind.DecimalLessThan),
                        GetSignature(BinaryOperatorKind.LiftedIntLessThan),
                        GetSignature(BinaryOperatorKind.LiftedUIntLessThan),
                        GetSignature(BinaryOperatorKind.LiftedLongLessThan),
                        GetSignature(BinaryOperatorKind.LiftedULongLessThan),
                        GetSignature(BinaryOperatorKind.LiftedFloatLessThan),
                        GetSignature(BinaryOperatorKind.LiftedDoubleLessThan),
                        GetSignature(BinaryOperatorKind.LiftedDecimalLessThan),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.UIntGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LongGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.ULongGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.FloatGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.DoubleGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.DecimalGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedIntGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedUIntGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedLongGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedULongGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedFloatGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedDoubleGreaterThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedDecimalGreaterThanOrEqual),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.UIntLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LongLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.ULongLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.FloatLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.DoubleLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.DecimalLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedIntLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedUIntLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedLongLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedULongLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedFloatLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedDoubleLessThanOrEqual),
                        GetSignature(BinaryOperatorKind.LiftedDecimalLessThanOrEqual),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntAnd),
                        GetSignature(BinaryOperatorKind.UIntAnd),
                        GetSignature(BinaryOperatorKind.LongAnd),
                        GetSignature(BinaryOperatorKind.ULongAnd),
                        GetSignature(BinaryOperatorKind.BoolAnd),
                        GetSignature(BinaryOperatorKind.LiftedIntAnd),
                        GetSignature(BinaryOperatorKind.LiftedUIntAnd),
                        GetSignature(BinaryOperatorKind.LiftedLongAnd),
                        GetSignature(BinaryOperatorKind.LiftedULongAnd),
                        GetSignature(BinaryOperatorKind.LiftedBoolAnd),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntXor),
                        GetSignature(BinaryOperatorKind.UIntXor),
                        GetSignature(BinaryOperatorKind.LongXor),
                        GetSignature(BinaryOperatorKind.ULongXor),
                        GetSignature(BinaryOperatorKind.BoolXor),
                        GetSignature(BinaryOperatorKind.LiftedIntXor),
                        GetSignature(BinaryOperatorKind.LiftedUIntXor),
                        GetSignature(BinaryOperatorKind.LiftedLongXor),
                        GetSignature(BinaryOperatorKind.LiftedULongXor),
                        GetSignature(BinaryOperatorKind.LiftedBoolXor),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(BinaryOperatorKind.IntOr),
                        GetSignature(BinaryOperatorKind.UIntOr),
                        GetSignature(BinaryOperatorKind.LongOr),
                        GetSignature(BinaryOperatorKind.ULongOr),
                        GetSignature(BinaryOperatorKind.BoolOr),
                        GetSignature(BinaryOperatorKind.LiftedIntOr),
                        GetSignature(BinaryOperatorKind.LiftedUIntOr),
                        GetSignature(BinaryOperatorKind.LiftedLongOr),
                        GetSignature(BinaryOperatorKind.LiftedULongOr),
                        GetSignature(BinaryOperatorKind.LiftedBoolOr),
                    }).AsImmutableOrNull(),
                };

                var allOperators = new[] { nonLogicalOperators, logicalOperators };

                Interlocked.CompareExchange(ref builtInOperators, allOperators, null);
            }

            operators.AddRange(builtInOperators[kind.IsLogical() ? 1 : 0][kind.OperatorIndex()]);
        }
        // Returns an analysis of every matching user-defined binary operator, including whether the
        // operator is applicable or not.

        private void GetUserDefinedOperators(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, ArrayBuilder<BinaryOperatorAnalysisResult> results)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);

            // The following is a slight rewording of the specification to emphasize that not all
            // operands of a binary operation need to have a type.

            // SPEC: An operation of the form x op y, where op is an overloadable binary operator is processed as follows:
            // SPEC: The set of candidate user-defined operators provided by the types (if any) of x and y for the 
            // SPEC: operation operator op(x, y) is determined. The set consists of the union of the candidate operators
            // SPEC: provided by the type of x (if any) and the candidate operators provided by the type of y (if any), 
            // SPEC: each determined using the rules of 7.3.5. Candidate operators only occur in the combined set once.

            var operators = ArrayBuilder<BinaryOperatorAnalysisResult>.GetInstance();
            var leftType = left.Type;
            if (leftType != null)
            {
                GetUserDefinedOperators(kind, leftType, left, right, operators);
            }

            var rightType = right.Type;
            if (rightType != null)
            {
                var rightOperators = ArrayBuilder<BinaryOperatorAnalysisResult>.GetInstance();
                GetUserDefinedOperators(kind, rightType, left, right, rightOperators);
                operators.UnionWith(rightOperators);
                rightOperators.Free();
            }

            results.AddRange(operators);
            operators.Free();
        }
Пример #13
0
        private void AppendSymbolsWithNameAndArity(
            ArrayBuilder<Symbol> results,
            string name,
            int arity,
            Binder binder,
            NamespaceOrTypeSymbol container,
            LookupOptions options)
        {
            Debug.Assert(results != null);

            // Don't need to de-dup since AllMethodsOnArityZero can't be set at this point (not exposed in CommonLookupOptions).
            Debug.Assert((options & LookupOptions.AllMethodsOnArityZero) == 0);

            var lookupResult = LookupResult.GetInstance();

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            binder.LookupSymbolsSimpleName(
                lookupResult,
                container,
                name,
                arity,
                basesBeingResolved: null,
                options: options & ~LookupOptions.IncludeExtensionMethods,
                diagnose: false,
                useSiteDiagnostics: ref useSiteDiagnostics);

            if (lookupResult.IsMultiViable)
            {
                if (lookupResult.Symbols.Any(t => t.Kind == SymbolKind.NamedType || t.Kind == SymbolKind.Namespace || t.Kind == SymbolKind.ErrorType))
                {
                    // binder.ResultSymbol is defined only for type/namespace lookups
                    bool wasError;
                    var diagnostics = DiagnosticBag.GetInstance();  // client code never expects a null diagnostic bag.
                    Symbol singleSymbol = binder.ResultSymbol(lookupResult, name, arity, this.Root, diagnostics, true, out wasError, container, options);
                    diagnostics.Free();

                    if (!wasError)
                    {
                        results.Add(singleSymbol);
                    }
                    else
                    {
                        results.AddRange(lookupResult.Symbols);
                    }
                }
                else
                {
                    results.AddRange(lookupResult.Symbols);
                }
            }

            lookupResult.Free();
        }
Пример #14
0
        // returns all the symbols in the container corresponding to the node
        private void Bind(
            int index, INamespaceOrTypeSymbol rootContainer, ArrayBuilder<ISymbol> results, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var node = _nodes[index];
            if (node.IsRoot)
            {
                return;
            }

            if (_nodes[node.ParentIndex].IsRoot)
            {
                results.AddRange(rootContainer.GetMembers(GetName(node)));
            }
            else
            {
                var containerSymbols = ArrayBuilder<ISymbol>.GetInstance();
                try
                {
                    Bind(node.ParentIndex, rootContainer, containerSymbols, cancellationToken);

                    foreach (var containerSymbol in containerSymbols)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        var nsOrType = containerSymbol as INamespaceOrTypeSymbol;
                        if (nsOrType != null)
                        {
                            results.AddRange(nsOrType.GetMembers(GetName(node)));
                        }
                    }
                }
                finally
                {
                    containerSymbols.Free();
                }
            }
        }
Пример #15
0
        private static async Task AddDeclarationsAsync(
            Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, 
            SearchQuery query, SymbolFilter filter, ArrayBuilder<ISymbol> list, CancellationToken cancellationToken)
        {
            // All entrypoints to this function are Find functions that are only searching
            // for specific strings (i.e. they never do a custom search).
            Debug.Assert(query.Kind != SearchKind.Custom);

            using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken))
            {
                if (referenceOpt != null)
                {
                    var info = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync(
                        solution, referenceOpt, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false);
                    if (info != null)
                    {
                        var symbols = await info.FindAsync(query, assembly, filter, cancellationToken).ConfigureAwait(false);
                        list.AddRange(symbols);
                    }
                }
            }
        }
Пример #16
0
        private static async Task AddDeclarationsAsync(
            Project project,
            SearchQuery query,
            SymbolFilter filter,
            ArrayBuilder<ISymbol> list,
            Compilation startingCompilation,
            IAssemblySymbol startingAssembly,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.SymbolFinder_Project_AddDeclarationsAsync, cancellationToken))
            {
                if (!await project.ContainsSymbolsWithNameAsync(query.GetPredicate(), filter, cancellationToken).ConfigureAwait(false))
                {
                    return;
                }

                var unfilteredSymbols = await GetUnfilteredSymbolsAsync(
                    project, query, filter, startingCompilation, startingAssembly, cancellationToken).ConfigureAwait(false);
                list.AddRange(FilterByCriteria(unfilteredSymbols, filter));
            }
        }
Пример #17
0
 /// <summary>
 /// We use this to restore the old set of pending branches after visiting a construct that contains nested statements.
 /// </summary>
 /// <param name="oldPending">The old pending branches, which are to be merged with the current ones</param>
 protected void RestorePending(ArrayBuilder<PendingBranch> oldPending)
 {
     oldPending.AddRange(this.pendingBranches);
     this.pendingBranches.Free();
     this.pendingBranches = oldPending;
 }
Пример #18
0
        /// <summary>
        /// Finds references using <see cref="SymbolFinder.FindReferencesAsync(ISymbol, Solution, CancellationToken)"/>
        /// </summary>
        private async Task AddSymbolReferencesAsync(Document document, int position, ArrayBuilder<INavigableItem> builder, IWaitContext waitContext)
        {
            var result = await this.FindReferencedSymbolsAsync(document, position, waitContext).ConfigureAwait(false);
            if (result != null)
            {
                var referencedSymbols = result.Item1;
                var searchSolution = result.Item2;

                var q = from r in referencedSymbols
                        from loc in r.Locations
                        select NavigableItemFactory.GetItemFromSymbolLocation(searchSolution, r.Definition, loc.Location);

                builder.AddRange(q);
            }
        }
 public override void AddPreviousLocals(ArrayBuilder<Cci.ILocalDefinition> builder)
 {
     builder.AddRange(_previousLocals.Select((info, index) => new SignatureOnlyLocalDefinition(info.Signature, index)));
 }
        /// <summary>
        /// digs into known concat operators and unwraps their arguments
        /// otherwise returns the expression as-is
        /// 
        /// Generally we only need to recognize same node patterns that we create as a result of concatenation rewrite.
        /// </summary>
        private void FlattenConcatArg(BoundExpression lowered, ArrayBuilder<BoundExpression> flattened)
        {
            switch (lowered.Kind)
            {
                case BoundKind.Call:
                    var boundCall = (BoundCall)lowered;

                    var method = boundCall.Method;
                    if (method.IsStatic && method.ContainingType.SpecialType == SpecialType.System_String)
                    {
                        if ((object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringString) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringString) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringStringString) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObject) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectObject) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectObjectObject))
                        {
                            flattened.AddRange(boundCall.Arguments);
                            return;
                        }

                        if ((object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringArray) ||
                            (object)method == (object)_compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectArray))
                        {
                            var args = boundCall.Arguments[0] as BoundArrayCreation;
                            if (args != null)
                            {
                                var initializer = args.InitializerOpt;
                                if (initializer != null)
                                {
                                    flattened.AddRange(initializer.Initializers);
                                    return;
                                }
                            }
                        }
                    }
                    break;

                case BoundKind.NullCoalescingOperator:
                    var boundCoalesce = (BoundNullCoalescingOperator)lowered;

                    if (boundCoalesce.LeftConversion.IsIdentity)
                    {
                        // The RHS may be a constant value with an identity conversion to string even
                        // if it is not a string: in particular, the null literal behaves this way.
                        // To be safe, check that the constant value is actually a string before
                        // attempting to access its value as a string.

                        var rightConstant = boundCoalesce.RightOperand.ConstantValue;
                        if (rightConstant != null && rightConstant.IsString && rightConstant.StringValue.Length == 0)
                        {
                            flattened.Add(boundCoalesce.LeftOperand);
                            return;
                        }
                    }
                    break;
            }

            // fallback - if nothing above worked, leave arg as-is
            flattened.Add(lowered);
            return;
        }
Пример #21
0
        internal static void AddConflictingParametersOfProperties(
            IEnumerable<ISymbol> properties, string newPropertyName, ArrayBuilder<Location> conflicts)
        {
            // check if the new property name conflicts with any parameter of the properties.
            // Note: referencedSymbols come from the original solution, so there is no need to reverse map the locations of the parameters
            foreach (var symbol in properties)
            {
                var prop = (IPropertySymbol)symbol;

                var conflictingParameter = prop.Parameters.FirstOrDefault(param => string.Compare(param.Name, newPropertyName, StringComparison.OrdinalIgnoreCase) == 0);

                if (conflictingParameter != null)
                {
                    conflicts.AddRange(conflictingParameter.Locations);
                }
            }
        }
Пример #22
0
 private static void AddUnwrappingErrorTypes(ArrayBuilder<Symbol> builder, Symbol s)
 {
     var originalErrorSymbol = s.OriginalDefinition as ErrorTypeSymbol;
     if ((object)originalErrorSymbol != null)
     {
         builder.AddRange(originalErrorSymbol.CandidateSymbols);
     }
     else
     {
         builder.Add(s);
     }
 }
 /// <summary>
 /// Replace any named type in the symbol list with its instance constructors.
 /// Construct all candidates with the implicitly-declared CrefTypeParameterSymbols.
 /// </summary>
 private void GetCrefOverloadResolutionCandidates(ImmutableArray<Symbol> symbols, int arity, TypeArgumentListSyntax typeArgumentListSyntax, ArrayBuilder<Symbol> candidates)
 {
     foreach (Symbol candidate in symbols)
     {
         Symbol constructedCandidate = ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, candidate);
         NamedTypeSymbol constructedCandidateType = constructedCandidate as NamedTypeSymbol;
         if ((object)constructedCandidateType == null)
         {
             // Construct before overload resolution so the signatures will match.
             candidates.Add(constructedCandidate);
         }
         else
         {
             candidates.AddRange(constructedCandidateType.InstanceConstructors);
         }
     }
 }
Пример #24
0
            private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node)
            {
                var expression = _localRewriter.VisitExpression(node.Expression);
                var result     = ArrayBuilder <BoundStatement> .GetInstance();

                // if the expression is "too complex", we copy it to a temp.
                LocalSymbol initialTemp = null;

                if (expression.ConstantValue == null)
                {
                    initialTemp = _factory.SynthesizedLocal(expression.Type, expression.Syntax);
                    result.Add(_factory.Assignment(_factory.Local(initialTemp), expression));
                    expression = _factory.Local(initialTemp);

                    // EnC: We need to insert a hidden sequence point to handle function remapping in case
                    // the containing method is edited while methods invoked in the expression are being executed.
                    if (!node.WasCompilerGenerated && _localRewriter.Instrument)
                    {
                        expression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory);
                    }
                }

                // output the decision tree part
                LowerPatternSwitch(expression, node, result);

                // if the endpoint is reachable, we exit the switch
                if (!node.IsComplete)
                {
                    result.Add(_factory.Goto(node.BreakLabel));
                }
                // at this point the end of result is unreachable.

                _declaredTemps.AddOptional(initialTemp);
                _declaredTemps.AddRange(node.InnerLocals);

                // output the sections of code
                foreach (var section in node.SwitchSections)
                {
                    // Lifetime of these locals is expanded to the entire switch body.
                    _declaredTemps.AddRange(section.Locals);

                    // Start with the part of the decision tree that is in scope of the section variables.
                    // Its endpoint is not reachable (it jumps back into the decision tree code).
                    var sectionSyntax  = (SyntaxNode)section.Syntax;
                    var sectionBuilder = _switchSections[sectionSyntax];

                    // Add labels corresponding to the labels of the switch section.
                    foreach (var label in section.SwitchLabels)
                    {
                        sectionBuilder.Add(_factory.Label(label.Label));
                    }

                    // Add the translated body of the switch section
                    sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements));

                    sectionBuilder.Add(_factory.Goto(node.BreakLabel));

                    ImmutableArray <BoundStatement> statements = sectionBuilder.ToImmutableAndFree();
                    if (section.Locals.IsEmpty)
                    {
                        result.Add(_factory.StatementList(statements));
                    }
                    else
                    {
                        result.Add(new BoundScope(section.Syntax, section.Locals, statements));
                    }
                    // at this point the end of result is unreachable.
                }

                result.Add(_factory.Label(node.BreakLabel));

                BoundStatement translatedSwitch = _factory.Block(_declaredTemps.ToImmutableArray(), node.InnerLocalFunctions, result.ToImmutableAndFree());

                // Only add instrumentation (such as a sequence point) if the node is not compiler-generated.
                if (!node.WasCompilerGenerated && _localRewriter.Instrument)
                {
                    translatedSwitch = _localRewriter._instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch);
                }

                return(translatedSwitch);
            }
        /// <summary>
        /// In the expanded form of a compound assignment (or increment/decrement), the LHS appears multiple times.
        /// If we aren't careful, this can result in repeated side-effects.  This creates (ordered) temps for all of the
        /// subexpressions that could result in side-effects and returns a side-effect-free expression that can be used
        /// in place of the LHS in the expanded form.
        /// </summary>
        /// <param name="originalLHS">The LHS sub-expression of the compound assignment (or increment/decrement).</param>
        /// <param name="stores">Populated with a list of assignment expressions that initialize the temporary locals.</param>
        /// <param name="temps">Populated with a list of temporary local symbols.</param>
        /// <param name="isDynamicAssignment">True if the compound assignment is a dynamic operation.</param>
        /// <returns>
        /// A side-effect-free expression representing the LHS.
        /// The returned node needs to be lowered but its children are already lowered.
        /// </returns>
        private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalLHS, ArrayBuilder<BoundExpression> stores, ArrayBuilder<LocalSymbol> temps, bool isDynamicAssignment)
        {
            // There are five possible cases.
            //
            // Case 1: receiver.Prop += value is transformed into
            // temp = receiver
            // temp.Prop = temp.Prop + value
            // and a later rewriting will turn that into calls to getters and setters.
            //
            // Case 2: collection[i1, i2, i3] += value is transformed into
            // tc = collection
            // t1 = i1
            // t2 = i2
            // t3 = i3
            // tc[t1, t2, t3] = tc[t1, t2, t3] + value
            // and again, a later rewriting will turn that into getters and setters of the indexer.
            //
            // Case 3: local += value (and param += value) needs no temporaries; it simply
            // becomes local = local + value.
            //
            // Case 4: staticField += value needs no temporaries either. However, classInst.field += value becomes
            // temp = classInst
            // temp.field = temp.field + value 
            //
            // Case 5: otherwise, it must be structVariable.field += value or array[index] += value. Either way
            // we have a variable on the left. Transform it into:
            // ref temp = ref variable
            // temp = temp + value

            switch (originalLHS.Kind)
            {
                case BoundKind.PropertyAccess:
                    {
                        // We need to stash away the receiver so that it does not get evaluated twice.
                        // If the receiver is classified as a value of reference type then we can simply say
                        //
                        // R temp = receiver
                        // temp.prop = temp.prop + rhs
                        //
                        // But if the receiver is classified as a variable of struct type then we
                        // cannot make a copy of the value; we need to make sure that we mutate
                        // the original receiver, not the copy.  We have to generate
                        //
                        // ref R temp = ref receiver
                        // temp.prop = temp.prop + rhs
                        //
                        // The rules of C# (in section 7.17.1) require that if you have receiver.prop 
                        // as the target of an assignment such that receiver is a value type, it must
                        // be classified as a variable. If we've gotten this far in the rewriting,
                        // assume that was the case.

                        var prop = (BoundPropertyAccess)originalLHS;

                        // If the property is static or is the receiver is of kind "Base" or "this", then we can just generate prop = prop + value
                        if (prop.ReceiverOpt == null || prop.PropertySymbol.IsStatic || !NeedsTemp(prop.ReceiverOpt))
                        {
                            return prop;
                        }

                        Debug.Assert(prop.ReceiverOpt.Kind != BoundKind.TypeExpression);

                        // Can we ever avoid storing the receiver in a temp? If the receiver is a variable then it 
                        // might be modified by the computation of the getter, the value, or the operation. 
                        // The receiver cannot be a null constant or constant of value type. It could be a 
                        // constant of string type, but there are no mutable properties of a string.
                        // Similarly, there are no mutable properties of a Type object, so the receiver
                        // cannot be a typeof(T) expression. The only situation we know of is where we could
                        // optimize away the temp is if the receiver is a readonly field of reference type,
                        // we are not in a constructor, and the receiver of the *field*, if any, is also idempotent.
                        // It doesn't seem worthwhile to pursue an optimization for this exceedingly rare case.

                        BoundExpression rewrittenReceiver = VisitExpression(prop.ReceiverOpt);
                        if (rewrittenReceiver.Type.IsTypeParameter() && rewrittenReceiver.Type.IsReferenceType)
                        {
                            var memberContainingType = prop.PropertySymbol.ContainingType;

                            // From the verifier prospective type parameters do not contain fields or methods.
                            // the instance must be boxed/constrained to access the member even if known to be a reference
                            // It makes sense to box reference receiver before storing into a temp - no need to box/constrain twice.
                            rewrittenReceiver = BoxReceiver(rewrittenReceiver, memberContainingType);
                        }

                        BoundAssignmentOperator assignmentToTemp;
                        var receiverTemp = this.factory.StoreToTemp(rewrittenReceiver, out assignmentToTemp, refKind: rewrittenReceiver.Type.IsReferenceType ? RefKind.None : RefKind.Ref);
                        stores.Add(assignmentToTemp);
                        temps.Add(receiverTemp.LocalSymbol);

                        // CONSIDER: this is a temporary object that will be rewritten away before this lowering completes.
                        // Mitigation: this will only produce short-lived garbage for compound assignments and increments/decrements of properties.
                        return new BoundPropertyAccess(prop.Syntax, receiverTemp, prop.PropertySymbol, prop.ResultKind, prop.Type);
                    }

                case BoundKind.DynamicMemberAccess:
                    {
                        var memberAccess = (BoundDynamicMemberAccess)originalLHS;
                        if (!NeedsTemp(memberAccess.Receiver))
                        {
                            return memberAccess;
                        }

                        // store receiver to temp:
                        var rewrittenReceiver = VisitExpression(memberAccess.Receiver);
                        BoundAssignmentOperator assignmentToTemp;
                        var receiverTemp = this.factory.StoreToTemp(rewrittenReceiver, out assignmentToTemp);
                        stores.Add(assignmentToTemp);
                        temps.Add(receiverTemp.LocalSymbol);

                        return new BoundDynamicMemberAccess(memberAccess.Syntax, receiverTemp, memberAccess.TypeArgumentsOpt, memberAccess.Name, memberAccess.Invoked, memberAccess.Indexed, memberAccess.Type);
                    }

                case BoundKind.IndexerAccess:
                    {
                        BoundIndexerAccess indexerAccess = (BoundIndexerAccess)originalLHS;

                        var receiverOpt = indexerAccess.ReceiverOpt;
                        Debug.Assert(receiverOpt != null);

                        BoundExpression transformedReceiver;
                        if (NeedsTemp(receiverOpt))
                        {
                            BoundExpression rewrittenReceiver = VisitExpression(receiverOpt);
                            if (rewrittenReceiver.Type.IsTypeParameter() && rewrittenReceiver.Type.IsReferenceType)
                            {
                                var memberContainingType = indexerAccess.Indexer.ContainingType;

                                // From the verifier prospective type parameters do not contain fields or methods.
                                // the instance must be boxed/constrained to access the member even if known to be a reference
                                // It makes sense to box reference receiver before storing into a temp - no need to box/constrain twice.
                                rewrittenReceiver = BoxReceiver(rewrittenReceiver, memberContainingType);
                            }

                            BoundAssignmentOperator assignmentToTemp;
                            var receiverTemp = this.factory.StoreToTemp(rewrittenReceiver, out assignmentToTemp, refKind: rewrittenReceiver.Type.IsReferenceType ? RefKind.None : RefKind.Ref);
                            transformedReceiver = receiverTemp;
                            stores.Add(assignmentToTemp);
                            temps.Add(receiverTemp.LocalSymbol);
                        }
                        else
                        {
                            transformedReceiver = VisitExpression(receiverOpt);
                        }

                        // Dealing with the arguments is a bit tricky because they can be named out-of-order arguments;
                        // we have to preserve both the source-code order of the side effects and the side effects
                        // only being executed once.
                        // 
                        // This is a subtly different problem than the problem faced by the conventional call
                        // rewriter; with the conventional call rewriter we already know that the side effects
                        // will only be executed once because the arguments are only being pushed on the stack once. 
                        // In a compound equality operator on an indexer the indices are placed on the stack twice. 
                        // That is to say, if you have:
                        // 
                        // C().M(z : Z(), x : X(), y : Y())
                        // 
                        // then we can rewrite that into
                        // 
                        // tempc = C()
                        // tempz = Z()
                        // tempc.M(X(), Y(), tempz)
                        // 
                        // See, we can optimize away two of the temporaries, for x and y. But we cannot optimize away any of the
                        // temporaries in
                        // 
                        // C().Collection[z : Z(), x : X(), y : Y()] += 1;
                        // 
                        // because we have to ensure not just that Z() happens first, but in addition that X() and Y() are only 
                        // called once.  We have to generate this as
                        // 
                        // tempc = C().Collection
                        // tempz = Z()
                        // tempx = X()
                        // tempy = Y()
                        // tempc[tempx, tempy, tempz] = tempc[tempx, tempy, tempz] + 1;
                        // 
                        // Fortunately arguments to indexers are never ref or out, so we don't need to worry about that.
                        // However, we can still do the optimization where constants are not stored in
                        // temporaries; if we have
                        // 
                        // C().Collection[z : 123, y : Y(), x : X()] += 1;
                        // 
                        // Then we can generate that as
                        // 
                        // tempc = C().Collection
                        // tempx = X()
                        // tempy = Y()
                        // tempc[tempx, tempy, 123] = tempc[tempx, tempy, 123] + 1;

                        ImmutableArray<BoundExpression> rewrittenArguments = VisitList(indexerAccess.Arguments);

                        CSharpSyntaxNode syntax = indexerAccess.Syntax;
                        PropertySymbol indexer = indexerAccess.Indexer;
                        ImmutableArray<RefKind> argumentRefKinds = indexerAccess.ArgumentRefKindsOpt;
                        bool expanded = indexerAccess.Expanded;
                        ImmutableArray<int> argsToParamsOpt = indexerAccess.ArgsToParamsOpt;

                        ImmutableArray<ParameterSymbol> parameters = indexer.Parameters;
                        BoundExpression[] actualArguments = new BoundExpression[parameters.Length]; // The actual arguments that will be passed; one actual argument per formal parameter.
                        ArrayBuilder<BoundAssignmentOperator> storesToTemps = ArrayBuilder<BoundAssignmentOperator>.GetInstance(rewrittenArguments.Length);
                        ArrayBuilder<RefKind> refKinds = ArrayBuilder<RefKind>.GetInstance(parameters.Length, RefKind.None);

                        // Step one: Store everything that is non-trivial into a temporary; record the
                        // stores in storesToTemps and make the actual argument a reference to the temp.
                        // Do not yet attempt to deal with params arrays or optional arguments.
                        BuildStoresToTemps(expanded, argsToParamsOpt, argumentRefKinds, rewrittenArguments, actualArguments, refKinds, storesToTemps);

                        // Step two: If we have a params array, build the array and fill in the argument.
                        if (expanded)
                        {
                            BoundExpression array = BuildParamsArray(syntax, indexer, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]);
                            BoundAssignmentOperator storeToTemp;
                            var boundTemp = this.factory.StoreToTemp(array, out storeToTemp);
                            stores.Add(storeToTemp);
                            temps.Add(boundTemp.LocalSymbol);
                            actualArguments[actualArguments.Length - 1] = boundTemp;
                        }

                        // Step three: Now fill in the optional arguments. (Dev11 uses the
                        // getter for optional arguments in compound assignments.)
                        var getMethod = indexer.GetOwnOrInheritedGetMethod();
                        Debug.Assert((object)getMethod != null);
                        InsertMissingOptionalArguments(syntax, getMethod.Parameters, actualArguments);

                        // For a call, step four would be to optimize away some of the temps.  However, we need them all to prevent
                        // duplicate side-effects, so we'll skip that step.

                        if (indexer.ContainingType.IsComImport)
                        {
                            RewriteArgumentsForComCall(parameters, actualArguments, refKinds, temps);
                        }

                        rewrittenArguments = actualArguments.AsImmutableOrNull();

                        foreach (BoundAssignmentOperator tempAssignment in storesToTemps)
                        {
                            temps.Add(((BoundLocal)tempAssignment.Left).LocalSymbol);
                            stores.Add(tempAssignment);
                        }

                        storesToTemps.Free();
                        argumentRefKinds = GetRefKindsOrNull(refKinds);
                        refKinds.Free();

                        // CONSIDER: this is a temporary object that will be rewritten away before this lowering completes.
                        // Mitigation: this will only produce short-lived garbage for compound assignments and increments/decrements of indexers.
                        return new BoundIndexerAccess(
                            syntax,
                            transformedReceiver,
                            indexer,
                            rewrittenArguments,
                            default(ImmutableArray<string>),
                            argumentRefKinds,
                            false,
                            default(ImmutableArray<int>),
                            indexerAccess.Type);
                    }

                case BoundKind.Local:
                case BoundKind.Parameter:
                case BoundKind.ThisReference: // a special kind of parameter
                    // No temporaries are needed. Just generate local = local + value
                    return originalLHS;

                case BoundKind.DeclarationExpression:
                    var rewrittenDeclExpr = (BoundExpression)VisitDeclarationExpression((BoundDeclarationExpression)originalLHS);

                    switch (rewrittenDeclExpr.Kind)
                    {
                        case BoundKind.Local:
                            return rewrittenDeclExpr;

                        case BoundKind.Sequence:
                            var sequence = (BoundSequence)rewrittenDeclExpr;
                            stores.AddRange(sequence.SideEffects);
                            temps.AddRange(sequence.Locals);

                            if (sequence.Value.Kind == BoundKind.Local)
                            {
                                return sequence.Value;
                            }

                            break;
                    }

                    throw ExceptionUtilities.Unreachable;
                   
                case BoundKind.FieldAccess:
                    {
                        // * If the field is static then no temporaries are needed. 
                        // * If the field is not static and the receiver is of reference type then generate t = r; t.f = t.f + value
                        // * If the field is not static and the receiver is a variable of value type then we'll fall into the
                        //   general variable case below.

                        var fieldAccess = (BoundFieldAccess)originalLHS;
                        BoundExpression receiverOpt = fieldAccess.ReceiverOpt;

                        //If the receiver is static or is the receiver is of kind "Base" or "this", then we can just generate field = field + value
                        if (receiverOpt == null || fieldAccess.FieldSymbol.IsStatic || !NeedsTemp(receiverOpt))
                        {
                            return fieldAccess;
                        }

                        if (receiverOpt.Type.IsReferenceType)
                        {
                            Debug.Assert(receiverOpt.Kind != BoundKind.TypeExpression);
                            BoundExpression rewrittenReceiver = VisitExpression(receiverOpt);

                            if (rewrittenReceiver.Type.IsTypeParameter())
                            {
                                var memberContainingType = fieldAccess.FieldSymbol.ContainingType;

                                // From the verifier prospective type parameters do not contain fields or methods.
                                // the instance must be "boxed" to access the field
                                // It makes sense to box receiver before storing into a temp - no need to box twice.
                                rewrittenReceiver = BoxReceiver(rewrittenReceiver, memberContainingType);
                            }

                            BoundAssignmentOperator assignmentToTemp;
                            var receiverTemp = this.factory.StoreToTemp(rewrittenReceiver, out assignmentToTemp);
                            stores.Add(assignmentToTemp);
                            temps.Add(receiverTemp.LocalSymbol);
                            return new BoundFieldAccess(fieldAccess.Syntax, receiverTemp, fieldAccess.FieldSymbol, null);
                        }

                        break;
                    }

                case BoundKind.DynamicIndexerAccess:
                    {
                        var indexerAccess = (BoundDynamicIndexerAccess)originalLHS;

                        BoundExpression loweredReceiver;
                        if (NeedsTemp(indexerAccess.ReceiverOpt))
                        {
                            BoundAssignmentOperator assignmentToTemp;
                            var temp = this.factory.StoreToTemp(VisitExpression(indexerAccess.ReceiverOpt), out assignmentToTemp);
                            stores.Add(assignmentToTemp);
                            temps.Add(temp.LocalSymbol);
                            loweredReceiver = temp;
                        }
                        else
                        {
                            loweredReceiver = indexerAccess.ReceiverOpt;
                        }

                        var arguments = indexerAccess.Arguments;
                        var loweredArguments = new BoundExpression[arguments.Length];

                        for (int i = 0; i < arguments.Length; i++)
                        {
                            if (NeedsTemp(arguments[i]))
                            {
                                BoundAssignmentOperator assignmentToTemp;
                                var temp = this.factory.StoreToTemp(VisitExpression(arguments[i]), out assignmentToTemp, refKind: indexerAccess.ArgumentRefKindsOpt.RefKinds(i));
                                stores.Add(assignmentToTemp);
                                temps.Add(temp.LocalSymbol);
                                loweredArguments[i] = temp;
                            }
                            else
                            {
                                loweredArguments[i] = arguments[i];
                            }
                        }

                        return new BoundDynamicIndexerAccess(
                            indexerAccess.Syntax,
                            loweredReceiver,
                            loweredArguments.AsImmutableOrNull(),
                            indexerAccess.ArgumentNamesOpt,
                            indexerAccess.ArgumentRefKindsOpt,
                            indexerAccess.ApplicableIndexers,
                            indexerAccess.Type);
                    }

                case BoundKind.ArrayAccess:
                    if (isDynamicAssignment)
                    {
                        // In non-dynamic array[index] op= R we emit:
                        //   T& tmp = &array[index];
                        //   *tmp = *L op R;
                        // where T is the type of L.
                        // 
                        // If L is an array access, the assignment is dynamic, the compile-time of the array is dynamic[] 
                        // and the runtime type of the array is not object[] (but e.g. string[]) the pointer approach is broken.
                        // T is Object in such case and we can't take a read-write pointer of type Object& to an array element of non-object type.
                        //
                        // In this case we rewrite the assignment as follows:
                        //
                        //   E t_array = array;
                        //   I t_index = index; (possibly more indices)
                        //   T value = t_array[t_index];
                        //   t_array[t_index] = value op R;

                        var arrayAccess = (BoundArrayAccess)originalLHS;
                        var loweredArray = VisitExpression(arrayAccess.Expression);
                        var loweredIndices = VisitList(arrayAccess.Indices);

                        return SpillArrayElementAccess(loweredArray, loweredIndices, stores, temps);
                    }

                    break;

                case BoundKind.PointerElementAccess:
                case BoundKind.PointerIndirectionOperator:
                case BoundKind.RefValueOperator:
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(originalLHS.Kind);
            }

            // We made no transformation above. Either we have array[index] += value or 
            // structVariable.field += value; either way we have a potentially complicated variable-
            // producing expression on the left. Generate
            // ref temp = ref variable; temp = temp + value

            // Rewrite the variable.  Here we depend on the fact that the only forms
            // rewritten here are rewritten the same for lvalues and rvalues.
            BoundExpression rewrittenVariable = VisitExpression(originalLHS);

            BoundAssignmentOperator assignmentToTemp2;
            var variableTemp = this.factory.StoreToTemp(rewrittenVariable, out assignmentToTemp2, refKind: RefKind.Ref);
            stores.Add(assignmentToTemp2);
            temps.Add(variableTemp.LocalSymbol);
            return variableTemp;
        }
Пример #26
0
        internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<UnaryOperatorSignature> operators)
        {
            if (builtInUnaryOperators == null)
            {
                var allOperators = new ImmutableArray<UnaryOperatorSignature>[]
                {
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.SBytePostfixIncrement),
                        GetSignature(UnaryOperatorKind.BytePostfixIncrement),
                        GetSignature(UnaryOperatorKind.ShortPostfixIncrement),
                        GetSignature(UnaryOperatorKind.UShortPostfixIncrement),
                        GetSignature(UnaryOperatorKind.IntPostfixIncrement),
                        GetSignature(UnaryOperatorKind.UIntPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LongPostfixIncrement),
                        GetSignature(UnaryOperatorKind.ULongPostfixIncrement),
                        GetSignature(UnaryOperatorKind.CharPostfixIncrement),
                        GetSignature(UnaryOperatorKind.FloatPostfixIncrement),
                        GetSignature(UnaryOperatorKind.DoublePostfixIncrement),
                        GetSignature(UnaryOperatorKind.DecimalPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedSBytePostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedBytePostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedShortPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedUShortPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedIntPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedUIntPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedLongPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedULongPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedCharPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedFloatPostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedDoublePostfixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedDecimalPostfixIncrement),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.SBytePostfixDecrement),
                        GetSignature(UnaryOperatorKind.BytePostfixDecrement),
                        GetSignature(UnaryOperatorKind.ShortPostfixDecrement),
                        GetSignature(UnaryOperatorKind.UShortPostfixDecrement),
                        GetSignature(UnaryOperatorKind.IntPostfixDecrement),
                        GetSignature(UnaryOperatorKind.UIntPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LongPostfixDecrement),
                        GetSignature(UnaryOperatorKind.ULongPostfixDecrement),
                        GetSignature(UnaryOperatorKind.CharPostfixDecrement),
                        GetSignature(UnaryOperatorKind.FloatPostfixDecrement),
                        GetSignature(UnaryOperatorKind.DoublePostfixDecrement),
                        GetSignature(UnaryOperatorKind.DecimalPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedSBytePostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedBytePostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedShortPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedUShortPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedIntPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedUIntPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedLongPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedULongPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedCharPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedFloatPostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedDoublePostfixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedDecimalPostfixDecrement),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.SBytePrefixIncrement),
                        GetSignature(UnaryOperatorKind.BytePrefixIncrement),
                        GetSignature(UnaryOperatorKind.ShortPrefixIncrement),
                        GetSignature(UnaryOperatorKind.UShortPrefixIncrement),
                        GetSignature(UnaryOperatorKind.IntPrefixIncrement),
                        GetSignature(UnaryOperatorKind.UIntPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LongPrefixIncrement),
                        GetSignature(UnaryOperatorKind.ULongPrefixIncrement),
                        GetSignature(UnaryOperatorKind.CharPrefixIncrement),
                        GetSignature(UnaryOperatorKind.FloatPrefixIncrement),
                        GetSignature(UnaryOperatorKind.DoublePrefixIncrement),
                        GetSignature(UnaryOperatorKind.DecimalPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedSBytePrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedBytePrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedShortPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedUShortPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedIntPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedUIntPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedLongPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedULongPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedCharPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedFloatPrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedDoublePrefixIncrement),
                        GetSignature(UnaryOperatorKind.LiftedDecimalPrefixIncrement),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.SBytePrefixDecrement),
                        GetSignature(UnaryOperatorKind.BytePrefixDecrement),
                        GetSignature(UnaryOperatorKind.ShortPrefixDecrement),
                        GetSignature(UnaryOperatorKind.UShortPrefixDecrement),
                        GetSignature(UnaryOperatorKind.IntPrefixDecrement),
                        GetSignature(UnaryOperatorKind.UIntPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LongPrefixDecrement),
                        GetSignature(UnaryOperatorKind.ULongPrefixDecrement),
                        GetSignature(UnaryOperatorKind.CharPrefixDecrement),
                        GetSignature(UnaryOperatorKind.FloatPrefixDecrement),
                        GetSignature(UnaryOperatorKind.DoublePrefixDecrement),
                        GetSignature(UnaryOperatorKind.DecimalPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedSBytePrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedBytePrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedShortPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedUShortPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedIntPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedUIntPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedLongPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedULongPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedCharPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedFloatPrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedDoublePrefixDecrement),
                        GetSignature(UnaryOperatorKind.LiftedDecimalPrefixDecrement),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.IntUnaryPlus),
                        GetSignature(UnaryOperatorKind.UIntUnaryPlus),
                        GetSignature(UnaryOperatorKind.LongUnaryPlus),
                        GetSignature(UnaryOperatorKind.ULongUnaryPlus),
                        GetSignature(UnaryOperatorKind.FloatUnaryPlus),
                        GetSignature(UnaryOperatorKind.DoubleUnaryPlus),
                        GetSignature(UnaryOperatorKind.DecimalUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedIntUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedUIntUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedLongUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedULongUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedFloatUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedDoubleUnaryPlus),
                        GetSignature(UnaryOperatorKind.LiftedDecimalUnaryPlus),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.IntUnaryMinus),
                        GetSignature(UnaryOperatorKind.LongUnaryMinus),
                        GetSignature(UnaryOperatorKind.FloatUnaryMinus),
                        GetSignature(UnaryOperatorKind.DoubleUnaryMinus),
                        GetSignature(UnaryOperatorKind.DecimalUnaryMinus),
                        GetSignature(UnaryOperatorKind.LiftedIntUnaryMinus),
                        GetSignature(UnaryOperatorKind.LiftedLongUnaryMinus),
                        GetSignature(UnaryOperatorKind.LiftedFloatUnaryMinus),
                        GetSignature(UnaryOperatorKind.LiftedDoubleUnaryMinus),
                        GetSignature(UnaryOperatorKind.LiftedDecimalUnaryMinus),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.BoolLogicalNegation),
                        GetSignature(UnaryOperatorKind.LiftedBoolLogicalNegation),
                    }).AsImmutableOrNull(),
                    (new []
                    {
                        GetSignature(UnaryOperatorKind.IntBitwiseComplement),
                        GetSignature(UnaryOperatorKind.UIntBitwiseComplement),
                        GetSignature(UnaryOperatorKind.LongBitwiseComplement),
                        GetSignature(UnaryOperatorKind.ULongBitwiseComplement),
                        GetSignature(UnaryOperatorKind.LiftedIntBitwiseComplement),
                        GetSignature(UnaryOperatorKind.LiftedUIntBitwiseComplement),
                        GetSignature(UnaryOperatorKind.LiftedLongBitwiseComplement),
                        GetSignature(UnaryOperatorKind.LiftedULongBitwiseComplement),
                    }).AsImmutableOrNull(),
                    // No built-in operator true or operator false
                    (new UnaryOperatorSignature [0]).AsImmutableOrNull(),
                    (new UnaryOperatorSignature [0]).AsImmutableOrNull(),
                };

                Interlocked.CompareExchange(ref builtInUnaryOperators, allOperators, null);
            }

            operators.AddRange(builtInUnaryOperators[kind.OperatorIndex()]);
        }
Пример #27
0
        /// <summary>
        /// digs into known concat operators and unwraps their arguments
        /// otherwise returns the expression as-is
        /// 
        /// Generally we only need to recognize same node patterns that we create as a result of concatenation rewrite.
        /// </summary>
        private void FlattenConcatArg(BoundExpression lowered, ArrayBuilder<BoundExpression> flattened)
        {
            switch (lowered.Kind)
            {
                case BoundKind.Call:
                    var boundCall = (BoundCall)lowered;

                    var method = boundCall.Method;
                    if (method.IsStatic && method.ContainingType.SpecialType == SpecialType.System_String)
                    {
                        if ((object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringString) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringString) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringStringStringString) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObject) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectObject) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectObjectObject))
                        {
                            flattened.AddRange(boundCall.Arguments);
                            return;
                        }

                        if ((object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatStringArray) ||
                            (object)method == (object)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__ConcatObjectArray))
                        {
                            var args = boundCall.Arguments[0] as BoundArrayCreation;
                            if (args != null)
                            {
                                var initializer = args.InitializerOpt;
                                if (initializer != null)
                                {
                                    flattened.AddRange(initializer.Initializers);
                                    return;
                                }
                            }
                        }
                    }
                    break;

                case BoundKind.NullCoalescingOperator:
                    var boundCoalesce = (BoundNullCoalescingOperator)lowered;

                    if (boundCoalesce.LeftConversion.IsIdentity)
                    {
                        var right = boundCoalesce.RightOperand;
                        if (right.ConstantValue != null && right.ConstantValue.StringValue.Length == 0)
                        {
                            flattened.Add(boundCoalesce.LeftOperand);
                            return;
                        }
                    }
                    break;
            }

            // fallback - if nothing above worked, leave arg as-is
            flattened.Add(lowered);
            return;
        }
Пример #28
0
        public void DebuggerProxy_ArrayBuilder()
        {
            var obj = new ArrayBuilder<int>();
            obj.AddRange(new[] { 1, 2, 3, 4, 5 });

            var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
            Assert.Equal("ArrayBuilder<int>(Count = 5) { 1, 2, 3, 4, 5 }", str);

            str = CSharpObjectFormatter.Instance.FormatObject(obj, s_memberList);
            AssertMembers(str, "ArrayBuilder<int>(Count = 5)",
                 "1",
                 "2",
                 "3",
                 "4",
                 "5"
            );
        }
Пример #29
0
        internal void LookupExtensionMethodsInUsings(
            ArrayBuilder<MethodSymbol> methods,
            string name,
            int arity,
            LookupOptions options,
            bool callerIsSemanticModel)
        {
            Debug.Assert(methods.Count == 0);

            // We need to avoid collecting multiple candidates for an extension method imported both through a namespace and a static class
            // We will look for duplicates only if both of the following flags are set to true
            bool seenNamespaceWithExtensionMethods = false;
            bool seenStaticClassWithExtensionMethods = false;

            foreach (var nsOrType in this.Usings)
            {
                switch (nsOrType.NamespaceOrType.Kind)
                {
                    case SymbolKind.Namespace:
                        {
                            var count = methods.Count;
                            ((NamespaceSymbol)nsOrType.NamespaceOrType).GetExtensionMethods(methods, name, arity, options);

                            // If we found any extension methods, then consider this using as used.
                            if (methods.Count != count)
                            {
                                MarkImportDirective(nsOrType.UsingDirective, callerIsSemanticModel);
                                seenNamespaceWithExtensionMethods = true;
                            }

                            break;
                        }

                    case SymbolKind.NamedType:
                        {
                            var count = methods.Count;
                            ((NamedTypeSymbol)nsOrType.NamespaceOrType).GetExtensionMethods(methods, name, arity, options);

                            // If we found any extension methods, then consider this using as used.
                            if (methods.Count != count)
                            {
                                MarkImportDirective(nsOrType.UsingDirective, callerIsSemanticModel);
                                seenStaticClassWithExtensionMethods = true;
                            }

                            break;
                        }
                }
            }

            if (seenNamespaceWithExtensionMethods && seenStaticClassWithExtensionMethods)
            {
                var methodsNoDuplicates = ArrayBuilder<MethodSymbol>.GetInstance();
                methodsNoDuplicates.AddRange(methods.Distinct());
                if (methodsNoDuplicates.Count < methods.Count)
                {
                    methods.Clear();
                    methods.AddRange(methodsNoDuplicates);
                }

                methodsNoDuplicates.Free();
            }
        }
        // Returns an analysis of every matching user-defined binary operator, including whether the
        // operator is applicable or not.

        private bool GetUserDefinedOperators(
            BinaryOperatorKind kind,
            BoundExpression left,
            BoundExpression right,
            ArrayBuilder<BinaryOperatorAnalysisResult> results,
            ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);

            // The following is a slight rewording of the specification to emphasize that not all
            // operands of a binary operation need to have a type.

            // TODO (tomat): The spec needs to be updated to use identity conversion instead of type equality.

            // Spec 7.3.4 Binary operator overload resolution:
            //   An operation of the form x op y, where op is an overloadable binary operator is processed as follows:
            //   The set of candidate user-defined operators provided by the types (if any) of x and y for the 
            //   operation operator op(x, y) is determined. The set consists of the union of the candidate operators
            //   provided by the type of x (if any) and the candidate operators provided by the type of y (if any), 
            //   each determined using the rules of 7.3.5. Candidate operators only occur in the combined set once.

            var operators = ArrayBuilder<BinaryOperatorAnalysisResult>.GetInstance();
            TypeSymbol leftType = left.Type;
            TypeSymbol strippedLeftType = leftType?.StrippedType();

            bool hadApplicableCandidate = false;

            if ((object)strippedLeftType != null && !OperatorFacts.DefinitelyHasNoUserDefinedOperators(strippedLeftType))
            {
                hadApplicableCandidate = GetUserDefinedOperators(kind, strippedLeftType, left, right, operators, ref useSiteDiagnostics);
                if (!hadApplicableCandidate)
                {
                    operators.Clear();
                }
            }

            TypeSymbol rightType = right.Type;
            TypeSymbol strippedRightType = rightType?.StrippedType();
            if ((object)strippedRightType != null && !strippedRightType.Equals(strippedLeftType) &&
                !OperatorFacts.DefinitelyHasNoUserDefinedOperators(strippedRightType))
            {
                var rightOperators = ArrayBuilder<BinaryOperatorAnalysisResult>.GetInstance();
                hadApplicableCandidate |= GetUserDefinedOperators(kind, strippedRightType, left, right, rightOperators, ref useSiteDiagnostics);
                AddDistinctOperators(operators, rightOperators);
                rightOperators.Free();
            }

            if (hadApplicableCandidate)
            {
                results.AddRange(operators);
            }

            operators.Free();

            return hadApplicableCandidate;
        }
Пример #31
0
 public override void AddPreviousLocals(ArrayBuilder<Cci.ILocalDefinition> builder)
 {
     builder.AddRange(_locals);
 }
        // Get all modules in this compilation, including the source module, added modules, and all
        // modules of referenced assemblies that do not come from an assembly with an extern alias.
        // Metadata imported from aliased assemblies is not visible at the source level except through 
        // the use of an extern alias directive. So exclude them from this list which is used to construct
        // the global namespace.
        private IEnumerable<ModuleSymbol> GetAllUnaliasedModules()
        {
            // Get all assemblies in this compilation, including the source assembly and all referenced assemblies.
            ArrayBuilder<ModuleSymbol> modules = new ArrayBuilder<ModuleSymbol>();

            // NOTE: This includes referenced modules - they count as modules of the compilation assembly.
            modules.AddRange(this.Assembly.Modules);

            foreach (var pair in GetBoundReferenceManager().ReferencedAssembliesMap)
            {
                MetadataReference reference = pair.Key;
                ReferenceManager.ReferencedAssembly referencedAssembly = pair.Value;
                if (reference.Properties.Kind == MetadataImageKind.Assembly) // Already handled modules above.
                {
                    if (referencedAssembly.DeclarationsAccessibleWithoutAlias())
                    {
                        modules.AddRange(referencedAssembly.Symbol.Modules);
                    }
                }
            }

            return modules;
        }
Пример #33
0
        /// <summary>
        /// Internal helper for MatchPatternInternal
        /// </summary>
        /// <remarks>
        /// PERF: Designed to minimize allocations in common cases.
        /// If there's no match, then null is returned.
        /// If there's a single match, or the caller only wants the first match, then it is returned (as a Nullable)
        /// If there are multiple matches, and the caller wants them all, then a List is allocated.
        /// </remarks>
        /// <param name="candidate">The word being tested.</param>
        /// <param name="segment">The segment of the pattern to check against the candidate.</param>
        /// <param name="matches">The result array to place the matches in.</param>
        /// <param name="fuzzyMatch">If a fuzzy match should be performed</param>
        /// <returns>If there's only one match, then the return value is that match. Otherwise it is null.</returns>
        private bool MatchPatternSegment(
            string candidate,
            PatternSegment segment,
            ArrayBuilder <PatternMatch> matches,
            bool fuzzyMatch)
        {
            if (fuzzyMatch && !_allowFuzzyMatching)
            {
                return(false);
            }

            // First check if the segment matches as is.  This is also useful if the segment contains
            // characters we would normally strip when splitting into parts that we also may want to
            // match in the candidate.  For example if the segment is "@int" and the candidate is
            // "@int", then that will show up as an exact match here.
            //
            // Note: if the segment contains a space or an asterisk then we must assume that it's a
            // multi-word segment.
            if (!ContainsSpaceOrAsterisk(segment.TotalTextChunk.Text))
            {
                var match = MatchPatternChunk(
                    candidate, segment.TotalTextChunk, punctuationStripped: false, fuzzyMatch: fuzzyMatch);
                if (match != null)
                {
                    matches.Add(match.Value);
                    return(true);
                }
            }

            // The logic for pattern matching is now as follows:
            //
            // 1) Break the segment passed in into words.  Breaking is rather simple and a
            //    good way to think about it that if gives you all the individual alphanumeric words
            //    of the pattern.
            //
            // 2) For each word try to match the word against the candidate value.
            //
            // 3) Matching is as follows:
            //
            //   a) Check if the word matches the candidate entirely, in an case insensitive or
            //    sensitive manner.  If it does, return that there was an exact match.
            //
            //   b) Check if the word is a prefix of the candidate, in a case insensitive or
            //      sensitive manner.  If it does, return that there was a prefix match.
            //
            //   c) If the word is entirely lowercase, then check if it is contained anywhere in the
            //      candidate in a case insensitive manner.  If so, return that there was a substring
            //      match.
            //
            //      Note: We only have a substring match if the lowercase part is prefix match of
            //      some word part. That way we don't match something like 'Class' when the user
            //      types 'a'. But we would match 'FooAttribute' (since 'Attribute' starts with
            //      'a').
            //
            //   d) If the word was not entirely lowercase, then check if it is contained in the
            //      candidate in a case *sensitive* manner. If so, return that there was a substring
            //      match.
            //
            //   e) If the word was entirely lowercase, then attempt a special lower cased camel cased
            //      match.  i.e. cofipro would match CodeFixProvider.
            //
            //   f) If the word was not entirely lowercase, then attempt a normal camel cased match.
            //      i.e. CoFiPro would match CodeFixProvider, but CofiPro would not.
            //
            //   g) The word is all lower case. Is it a case insensitive substring of the candidate starting
            //      on a part boundary of the candidate?
            //
            // Only if all words have some sort of match is the pattern considered matched.

            var tempMatches = ArrayBuilder <PatternMatch> .GetInstance();

            try
            {
                var subWordTextChunks = segment.SubWordTextChunks;
                foreach (var subWordTextChunk in subWordTextChunks)
                {
                    // Try to match the candidate with this word
                    var result = MatchPatternChunk(
                        candidate, subWordTextChunk, punctuationStripped: true, fuzzyMatch: fuzzyMatch);
                    if (result == null)
                    {
                        return(false);
                    }

                    tempMatches.Add(result.Value);
                }

                matches.AddRange(tempMatches);
                return(tempMatches.Count > 0);
            }
            finally
            {
                tempMatches.Free();
            }
        }