/// <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); }
// 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); }
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()); } } }
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); } }
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()); }
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); } }
/// <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(); } } }
/// <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); }
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(); }
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(); }
// 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(); } } }
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); } } } }
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)); } }
/// <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; }
/// <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; }
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); } } }
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); } } }
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; }
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()]); }
/// <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; }
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" ); }
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; }
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; }
/// <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(); } }