private BoundNode RewriteCatch(BoundCatchBlock node, ArrayBuilder <BoundExpression> prologue, ArrayBuilder <LocalSymbol> newLocals) { AddLocals(node.Locals, newLocals); var rewrittenCatchLocals = newLocals.ToImmutableAndFree(); // If exception variable got lifted, IntroduceFrame will give us frame init prologue. // It needs to run before the exception variable is accessed. // To ensure that, we will make exception variable a sequence that performs prologue as its its sideeffecs. BoundExpression rewrittenExceptionSource = null; var rewrittenFilter = (BoundExpression)this.Visit(node.ExceptionFilterOpt); if (node.ExceptionSourceOpt != null) { rewrittenExceptionSource = (BoundExpression)Visit(node.ExceptionSourceOpt); if (prologue.Count > 0) { rewrittenExceptionSource = new BoundSequence( rewrittenExceptionSource.Syntax, ImmutableArray.Create <LocalSymbol>(), prologue.ToImmutable(), rewrittenExceptionSource, rewrittenExceptionSource.Type); } } else if (prologue.Count > 0) { Debug.Assert(rewrittenFilter != null); rewrittenFilter = new BoundSequence( rewrittenFilter.Syntax, ImmutableArray.Create <LocalSymbol>(), prologue.ToImmutable(), rewrittenFilter, rewrittenFilter.Type); } // done with this. prologue.Free(); // rewrite filter and body // NOTE: this will proxy all accesses to exception local if that got lifted. var exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt); var rewrittenBlock = (BoundBlock)this.Visit(node.Body); return(node.Update( rewrittenCatchLocals, rewrittenExceptionSource, exceptionTypeOpt, rewrittenFilter, rewrittenBlock)); }
override protected ImmutableArray <LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder <LocalSymbol>(_syntax.Declaration.Variables.Count); _syntax.Declaration.Type.VisitRankSpecifiers((rankSpecifier, args) => { foreach (var size in rankSpecifier.Sizes) { if (size.Kind() != SyntaxKind.OmittedArraySizeExpression) { ExpressionVariableFinder.FindExpressionVariables(args.binder, args.locals, size); } } }, (binder: this, locals: locals)); foreach (VariableDeclaratorSyntax declarator in _syntax.Declaration.Variables) { locals.Add(MakeLocal(_syntax.Declaration, declarator, LocalDeclarationKind.FixedVariable)); // also gather expression-declared variables from the bracketed argument lists and the initializers ExpressionVariableFinder.FindExpressionVariables(this, locals, declarator); } return(locals.ToImmutable()); } return(ImmutableArray <LocalSymbol> .Empty); }
internal static SourceText ToSourceText( ArrayBuilder <SourceText> segments, SourceText original, bool adjustSegments ) { if (adjustSegments) { TrimInaccessibleText(segments); ReduceSegmentCountIfNecessary(segments); } if (segments.Count == 0) { return(SourceText.From(string.Empty, original.Encoding, original.ChecksumAlgorithm)); } else if (segments.Count == 1) { return(segments[0]); } else { return(new CompositeText( segments.ToImmutable(), original.Encoding, original.ChecksumAlgorithm )); } }
public CacheEntry ToReferenceCacheEntry() { return(new CacheEntry( _checksum, _language, _itemsBuilder.ToImmutable())); }
public DataModel() { var fields = from field in typeof(FunctionId).GetFields() where !field.IsSpecialName select field; var builder = new ArrayBuilder <ActivityLevel?>(); var features = new Dictionary <string, ActivityLevel>(); var root = new ActivityLevel("All"); foreach (var field in fields) { var value = (int)field.GetRawConstantValue(); var name = field.Name; var featureNames = name.Split('_'); var featureName = featureNames.Length > 1 ? featureNames[0] : "Uncategorized"; if (!features.TryGetValue(featureName, out var parent)) { parent = new ActivityLevel(featureName, root, createChildList: true); features[featureName] = parent; } builder.SetItem(value, new ActivityLevel(name, parent, createChildList: false)); } _activities = builder.ToImmutable(); root.SortChildren(); RootNode = root; }
public CacheEntry ToCacheEntry() { return(new CacheEntry( _checksum, _language, _simpleItemBuilder, _complexItemBuilder.ToImmutable())); }
public ImmutableArray <BoundStatement> GetStatements() { if (_statements == null) { return(ImmutableArray <BoundStatement> .Empty); } return(_statements.ToImmutable()); }
public TypeImportCompletionCacheEntry ToReferenceCacheEntry() { return(new TypeImportCompletionCacheEntry( _assemblySymbolKey, _checksum, _language, _itemsBuilder.ToImmutable(), _publicItemCount)); }
private void AddConjunct(BoundExpression test) { if (_sideEffectBuilder.Count != 0) { test = _factory.Sequence(ImmutableArray <LocalSymbol> .Empty, _sideEffectBuilder.ToImmutable(), test); _sideEffectBuilder.Clear(); } _conjunctBuilder.Add(test); }
private static ImmutableArray <RefKind> GetRefKindsOrNull(ArrayBuilder <RefKind> refKinds) { foreach (var refKind in refKinds) { if (refKind != RefKind.None) { return(refKinds.ToImmutable()); } } return(default(ImmutableArray <RefKind>)); }
public static PropertySetAbstractValue GetInstance(ArrayBuilder <PropertySetAbstractValueKind> propertyAbstractValues) { if (TryGetPooledInstance(propertyAbstractValues, out PropertySetAbstractValue instance)) { return(instance); } else { return(new PropertySetAbstractValue(propertyAbstractValues.ToImmutable())); } }
public ImmutableArray <Cci.ILocalDefinition> LocalsInOrder() { if (_lazyAllLocals == null) { return(ImmutableArray <Cci.ILocalDefinition> .Empty); } else { return(_lazyAllLocals.ToImmutable()); } }
public ImmutableArray <BoundStatement> GetStatements(LocalSubstituter substituterOpt = null) { if (_statements == null) { return(ImmutableArray <BoundStatement> .Empty); } if (substituterOpt == null) { return(_statements.ToImmutable()); } return(_statements.SelectAsArray((statement, substituter) => (BoundStatement)substituter.Visit(statement), substituterOpt)); }
override protected ImmutableArray<LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder<LocalSymbol>(_syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in _syntax.Declaration.Variables) { locals.Add(MakeLocal(_syntax.Declaration, declarator, LocalDeclarationKind.FixedVariable)); } return locals.ToImmutable(); } return ImmutableArray<LocalSymbol>.Empty; }
override protected ImmutableArray <LocalSymbol> BuildLocals() { if (syntax.Declaration != null) { var locals = new ArrayBuilder <LocalSymbol>(syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in syntax.Declaration.Variables) { locals.Add(SourceLocalSymbol.MakeLocal(this.Owner, this, syntax.Declaration.Type, declarator.Identifier, declarator.Initializer, LocalDeclarationKind.Using)); } return(locals.ToImmutable()); } return(ImmutableArray <LocalSymbol> .Empty); }
override protected ImmutableArray <LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder <LocalSymbol>(1); locals.Add(MakeLocal(_syntax.Declaration, LocalDeclarationKind.FixedVariable)); // also gather expression-declared variables from the bracketed argument lists and the initializers ExpressionVariableFinder.FindExpressionVariables(this, locals, _syntax.Declaration); return(locals.ToImmutable()); } return(ImmutableArray <LocalSymbol> .Empty); }
private ImmutableArray <StatementSyntax> Analyze() { bool badRegion = false; // only one pass is needed. Scan(ref badRegion); if (badRegion) { return(ImmutableArray <StatementSyntax> .Empty); } _branchesOutOf.Sort((x, y) => x.SpanStart - y.SpanStart); return(_branchesOutOf.ToImmutable()); }
override protected ImmutableArray <LocalSymbol> BuildLocals() { if (syntax.Declaration != null) { var locals = new ArrayBuilder <LocalSymbol>(syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in syntax.Declaration.Variables) { locals.Add(MakeLocal(syntax.Declaration, declarator, LocalDeclarationKind.UsingVariable)); } return(locals.ToImmutable()); } return(ImmutableArray <LocalSymbol> .Empty); }
override protected ImmutableArray<LocalSymbol> BuildLocals() { if (syntax.Declaration != null) { var locals = new ArrayBuilder<LocalSymbol>(syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in syntax.Declaration.Variables) { locals.Add(SourceLocalSymbol.MakeLocal(this.Owner, this, syntax.Declaration.Type, declarator.Identifier, declarator.Initializer, LocalDeclarationKind.Fixed)); } return locals.ToImmutable(); } return ImmutableArray<LocalSymbol>.Empty; }
internal ImmutableArray <Symbol> BindXmlNameAttribute( XmlNameAttributeSyntax syntax, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo ) { var identifier = syntax.Identifier; if (identifier.IsMissing) { return(ImmutableArray <Symbol> .Empty); } var name = identifier.Identifier.ValueText; var lookupResult = LookupResult.GetInstance(); this.LookupSymbolsWithFallback( lookupResult, name, arity: 0, useSiteInfo: ref useSiteInfo ); if (lookupResult.Kind == LookupResultKind.Empty) { lookupResult.Free(); return(ImmutableArray <Symbol> .Empty); } // If we found something, it must be viable, since only parameters or type parameters // of the current member are considered. Debug.Assert(lookupResult.IsMultiViable); ArrayBuilder <Symbol> lookupSymbols = lookupResult.Symbols; Debug.Assert( lookupSymbols[0].Kind == SymbolKind.TypeParameter || lookupSymbols[0].Kind == SymbolKind.Parameter ); Debug.Assert(lookupSymbols.All(sym => sym.Kind == lookupSymbols[0].Kind)); // We can sort later when we disambiguate. ImmutableArray <Symbol> result = lookupSymbols.ToImmutable(); lookupResult.Free(); return(result); }
override protected ImmutableArray<LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder<LocalSymbol>(_syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in _syntax.Declaration.Variables) { locals.Add(MakeLocal(_syntax.Declaration, declarator, LocalDeclarationKind.FixedVariable)); // also gather expression-declared variables from the bracketed argument lists and the initializers ExpressionVariableFinder.FindExpressionVariables(this, locals, declarator); } return locals.ToImmutable(); } return ImmutableArray<LocalSymbol>.Empty; }
override protected ImmutableArray<LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder<LocalSymbol>(_syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in _syntax.Declaration.Variables) { locals.Add(MakeLocal(_syntax.Declaration, declarator, LocalDeclarationKind.FixedVariable)); if (declarator.Initializer != null) { ExpressionVariableFinder.FindExpressionVariables(this, locals, declarator.Initializer.Value); } } return locals.ToImmutable(); } return ImmutableArray<LocalSymbol>.Empty; }
override protected ImmutableArray <LocalSymbol> BuildLocals() { if (_syntax.Declaration != null) { var locals = new ArrayBuilder <LocalSymbol>(_syntax.Declaration.Variables.Count); foreach (VariableDeclaratorSyntax declarator in _syntax.Declaration.Variables) { locals.Add(MakeLocal(RefKind.None, _syntax.Declaration, declarator, LocalDeclarationKind.FixedVariable)); if (declarator.Initializer != null) { PatternVariableFinder.FindPatternVariables(this, locals, declarator.Initializer.Value); } } return(locals.ToImmutable()); } return(ImmutableArray <LocalSymbol> .Empty); }
/// <summary> /// Get the import strings for a given method, following forward pointers as necessary. /// </summary> /// <returns> /// For each namespace enclosing the method, a list of import strings, innermost to outermost. /// There should always be at least one entry, for the global namespace. /// </returns> public static ImmutableArray <ImmutableArray <string> > GetCSharpGroupedImportStrings(this ISymUnmanagedReader reader, int methodToken, out ImmutableArray <string> externAliasStrings) { externAliasStrings = default(ImmutableArray <string>); ImmutableArray <short> groupSizes = default(ImmutableArray <short>); bool seenForward = false; RETRY: var bytes = reader.GetCustomDebugInfo(methodToken); if (bytes == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } int offset = 0; byte globalVersion; byte unusedGlobalCount; ReadGlobalHeader(bytes, ref offset, out globalVersion, out unusedGlobalCount); CheckVersion(globalVersion, methodToken); while (offset < bytes.Length) { byte version; CustomDebugInfoKind kind; int size; ReadRecordHeader(bytes, ref offset, out version, out kind, out size); CheckVersion(version, methodToken); if (kind == CustomDebugInfoKind.UsingInfo) { if (!groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one Using record for method {0}", FormatMethodToken(methodToken))); } ReadUsingRecord(bytes, ref offset, size, out groupSizes); } else if (kind == CustomDebugInfoKind.ForwardInfo) { if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Did not expect both Forward and ForwardToModule records for method {0}", FormatMethodToken(methodToken))); } ReadForwardRecord(bytes, ref offset, size, out methodToken); if (!seenForward) // Follow at most one forward link. { seenForward = true; goto RETRY; } } else if (kind == CustomDebugInfoKind.ForwardToModuleInfo) { if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one ForwardToModule record for method {0}", FormatMethodToken(methodToken))); } int moduleInfoMethodToken; ReadForwardToModuleRecord(bytes, ref offset, size, out moduleInfoMethodToken); ImmutableArray <string> allModuleInfoImportStrings = GetImportStrings(reader.GetBaselineMethod(moduleInfoMethodToken)); ArrayBuilder <string> externAliasBuilder = ArrayBuilder <string> .GetInstance(); foreach (string importString in allModuleInfoImportStrings) { if (IsCSharpExternAliasInfo(importString)) { externAliasBuilder.Add(importString); } } externAliasStrings = externAliasBuilder.ToImmutableAndFree(); } else { SkipRecord(bytes, ref offset, size); } } if (groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Didn't find usings info for method {0}", FormatMethodToken(methodToken))); } ImmutableArray <string> importStrings = GetImportStrings(reader.GetBaselineMethod(methodToken)); int numImportStrings = importStrings.Length; ArrayBuilder <ImmutableArray <string> > resultBuilder = ArrayBuilder <ImmutableArray <string> > .GetInstance(groupSizes.Length); ArrayBuilder <string> groupBuilder = ArrayBuilder <string> .GetInstance(); int pos = 0; foreach (short groupSize in groupSizes) { for (int i = 0; i < groupSize; i++, pos++) { if (pos >= numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates more imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } string importString = importStrings[pos]; if (IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Encountered extern alias info before all import strings were consumed (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } resultBuilder.Add(groupBuilder.ToImmutable()); groupBuilder.Clear(); } if (externAliasStrings.IsDefault) { Debug.Assert(groupBuilder.Count == 0); // Extern alias detail strings (prefix "Z") are not included in the group counts. for (; pos < numImportStrings; pos++) { string importString = importStrings[pos]; if (!IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Expected only extern alias info strings after consuming the indicated number of imports (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } externAliasStrings = groupBuilder.ToImmutableAndFree(); } else { groupBuilder.Free(); if (pos < numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates fewer imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } } return(resultBuilder.ToImmutableAndFree()); }
public ImmutableArray <LocalSymbol> GetLocals() { return((_locals == null) ? ImmutableArray <LocalSymbol> .Empty : _locals.ToImmutable()); }
/// <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); }
public void RetargetExtensionMethods() { var source = @"class C { } static class S1 { internal static void E(this object x, object y) { } } static class S2 { internal static void E<T, U>(this T t, U u) { } }"; var compilation = CreateCompilation(source); var sourceModule = compilation.SourceModule; var sourceAssembly = (SourceAssemblySymbol)sourceModule.ContainingAssembly; var sourceNamespace = sourceModule.GlobalNamespace; var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); retargetingAssembly.SetCorLibrary(sourceAssembly.CorLibrary); var retargetingModule = retargetingAssembly.Modules[0]; var retargetingNamespace = retargetingModule.GlobalNamespace; var sourceMethods = new ArrayBuilder <MethodSymbol>(); sourceNamespace.GetExtensionMethods(sourceMethods, null, 0, LookupOptions.AllMethodsOnArityZero); Utils.CheckSymbols(sourceMethods.ToImmutable(), "void S1.E(object x, object y)", "void S2.E<T, U>(T t, U u)"); var retargetingMethods = new ArrayBuilder <MethodSymbol>(); retargetingNamespace.GetExtensionMethods(retargetingMethods, null, 0, LookupOptions.AllMethodsOnArityZero); Utils.CheckSymbols(retargetingMethods.ToImmutable(), "void S1.E(object x, object y)", "void S2.E<T, U>(T t, U u)"); for (int i = 0; i < sourceMethods.Count; i++) { CheckMethods(sourceMethods[i], retargetingMethods[i]); } sourceMethods = new ArrayBuilder <MethodSymbol>(); sourceNamespace.GetExtensionMethods(sourceMethods, "E", 2, LookupOptions.Default); Utils.CheckSymbols(sourceMethods.ToImmutable(), "void S2.E<T, U>(T t, U u)"); var sourceMethod = sourceMethods[0]; retargetingMethods = new ArrayBuilder <MethodSymbol>(); retargetingNamespace.GetExtensionMethods(retargetingMethods, "E", 2, LookupOptions.Default); Utils.CheckSymbols(retargetingMethods.ToImmutable(), "void S2.E<T, U>(T t, U u)"); var retargetingMethod = retargetingMethods[0]; var sourceType = sourceNamespace.GetMember <NamedTypeSymbol>("C"); var retargetingType = retargetingNamespace.GetMember <NamedTypeSymbol>("C"); CheckTypes(sourceType, retargetingType); CheckMethods(sourceMethod, retargetingMethod); var sourceReduced = sourceMethod.ReduceExtensionMethod(sourceType); var retargetingReduced = retargetingMethod.ReduceExtensionMethod(retargetingType); CheckReducedExtensionMethods(sourceReduced, retargetingReduced); }
private BoundNode RewriteCatch(BoundCatchBlock node, ArrayBuilder <BoundExpression> prologue, ArrayBuilder <LocalSymbol> newLocals) { LocalSymbol rewrittenCatchLocal = null; if (newLocals.Count > 0) { Debug.Assert(newLocals.Count == 1, "must be only one local that is the frame reference"); Debug.Assert(this.proxies.ContainsKey(node.LocalOpt), "original local should be proxied"); // getting new locals means that our original local was lifted into a closure // and instead of an actual local catch will own frame reference. rewrittenCatchLocal = newLocals[0]; } else if (node.LocalOpt != null) { // local was not lifted, but its type may need to be rewritten // this happens when it has a generic type which needs to be rewritten // when lambda body was moved to a separate method. var origLocal = node.LocalOpt; Debug.Assert(!this.proxies.ContainsKey(origLocal), "captured local should not need rewriting"); var newType = VisitType(origLocal.Type); if (newType == origLocal.Type) { // keeping same local rewrittenCatchLocal = origLocal; } else { // need a local of a different type rewrittenCatchLocal = new SynthesizedLocal(CurrentMethod, newType, origLocal.Name, declarationKind: LocalDeclarationKind.Catch); localMap.Add(origLocal, rewrittenCatchLocal); } } // If exception variable got lifted, IntroduceFrame will give us frame init prologue. // It needs to run before the exception variable is accessed. // To ensure that, we will make exception variable a sequence that performs prologue as its its sideeffecs. BoundExpression rewrittenExceptionSource = null; if (node.ExceptionSourceOpt != null) { rewrittenExceptionSource = (BoundExpression)Visit(node.ExceptionSourceOpt); if (prologue.Count > 0) { rewrittenExceptionSource = new BoundSequence( rewrittenExceptionSource.Syntax, ImmutableArray.Create <LocalSymbol>(), prologue.ToImmutable(), rewrittenExceptionSource, rewrittenExceptionSource.Type); } } // done with these. newLocals.Free(); prologue.Free(); // rewrite filter and body // NOTE: this will proxy all accesses to exception local if that got lifted. var exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt); var rewrittenFilter = (BoundExpression)this.Visit(node.ExceptionFilterOpt); var rewrittenBlock = (BoundBlock)this.Visit(node.Body); return(node.Update( rewrittenCatchLocal, rewrittenExceptionSource, exceptionTypeOpt, rewrittenFilter, rewrittenBlock)); }
/// <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)); } // avoid run time boxing and ToString operations if we can reasonably convert to a string at compile time loweredLeft = ConvertConcatExprToStringIfPossible(syntax, loweredLeft); loweredRight = ConvertConcatExprToStringIfPossible(syntax, loweredRight); // 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: 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; default: result = RewriteStringConcatenationManyExprs(syntax, leftFlattened.ToImmutable()); break; } leftFlattened.Free(); return(result); }
private static ImmutableArray<RefKind> GetRefKindsOrNull(ArrayBuilder<RefKind> refKinds) { foreach (var refKind in refKinds) { if (refKind != RefKind.None) { return refKinds.ToImmutable(); } } return default(ImmutableArray<RefKind>); }
/// <summary> /// Get the import strings for a given method, following forward pointers as necessary. /// </summary> /// <returns> /// For each namespace enclosing the method, a list of import strings, innermost to outermost. /// There should always be at least one entry, for the global namespace. /// </returns> public static ImmutableArray <ImmutableArray <string> > GetCSharpGroupedImportStrings(this ISymUnmanagedReader reader, int methodToken, int methodVersion, out ImmutableArray <string> externAliasStrings) { externAliasStrings = default(ImmutableArray <string>); ImmutableArray <short> groupSizes = default(ImmutableArray <short>); bool seenForward = false; RETRY: byte[] bytes = reader.GetCustomDebugInfo(methodToken, methodVersion); if (bytes == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } foreach (var record in GetCustomDebugInfoRecords(bytes)) { switch (record.Kind) { case CustomDebugInfoKind.UsingInfo: if (!groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one Using record for method {0}", FormatMethodToken(methodToken))); } groupSizes = DecodeUsingRecord(record.Data); break; case CustomDebugInfoKind.ForwardInfo: if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Did not expect both Forward and ForwardToModule records for method {0}", FormatMethodToken(methodToken))); } methodToken = DecodeForwardRecord(record.Data); // Follow at most one forward link (as in FUNCBRECEE::ensureNamespaces). // NOTE: Dev11 may produce chains of forward links (e.g. for System.Collections.Immutable). if (!seenForward) { seenForward = true; goto RETRY; } break; case CustomDebugInfoKind.ForwardToModuleInfo: if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one ForwardToModule record for method {0}", FormatMethodToken(methodToken))); } int moduleInfoMethodToken = DecodeForwardToModuleRecord(record.Data); ImmutableArray <string> allModuleInfoImportStrings = reader.GetMethodByVersion(moduleInfoMethodToken, methodVersion).GetImportStrings(); ArrayBuilder <string> externAliasBuilder = ArrayBuilder <string> .GetInstance(); foreach (string importString in allModuleInfoImportStrings) { if (IsCSharpExternAliasInfo(importString)) { externAliasBuilder.Add(importString); } } externAliasStrings = externAliasBuilder.ToImmutableAndFree(); break; } } if (groupSizes.IsDefault) { // This can happen in malformed PDBs (e.g. chains of forwards). return(default(ImmutableArray <ImmutableArray <string> >)); } var method = reader.GetMethodByVersion(methodToken, methodVersion); if (method == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } ImmutableArray <string> importStrings = method.GetImportStrings(); int numImportStrings = importStrings.Length; ArrayBuilder <ImmutableArray <string> > resultBuilder = ArrayBuilder <ImmutableArray <string> > .GetInstance(groupSizes.Length); ArrayBuilder <string> groupBuilder = ArrayBuilder <string> .GetInstance(); int pos = 0; foreach (short groupSize in groupSizes) { for (int i = 0; i < groupSize; i++, pos++) { if (pos >= numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates more imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } string importString = importStrings[pos]; if (IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Encountered extern alias info before all import strings were consumed (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } resultBuilder.Add(groupBuilder.ToImmutable()); groupBuilder.Clear(); } if (externAliasStrings.IsDefault) { Debug.Assert(groupBuilder.Count == 0); // Extern alias detail strings (prefix "Z") are not included in the group counts. for (; pos < numImportStrings; pos++) { string importString = importStrings[pos]; if (!IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Expected only extern alias info strings after consuming the indicated number of imports (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } externAliasStrings = groupBuilder.ToImmutableAndFree(); } else { groupBuilder.Free(); if (pos < numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates fewer imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } } return(resultBuilder.ToImmutableAndFree()); }
public override BoundNode VisitRangeExpression(BoundRangeExpression node) { Debug.Assert(node != null && node.MethodOpt != null); bool needLifting = false; var operandsBuilder = new ArrayBuilder <BoundExpression>(); var left = node.LeftOperand; if (left != null) { operandsBuilder.Add(tryOptimizeOperand(left)); } var right = node.RightOperand; if (right != null) { operandsBuilder.Add(tryOptimizeOperand(right)); } ImmutableArray <BoundExpression> operands = operandsBuilder.ToImmutable(); if (needLifting) { return(LiftRangeExpression(node, operands)); } else { BoundExpression rangeCreation = MakeCall( node.Syntax, rewrittenReceiver: null, node.MethodOpt, operands, node.MethodOpt.ReturnType.TypeSymbol); if (node.Type.IsNullableType()) { if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor)) { return(BadExpression(node.Syntax, node.Type, node)); } return(new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCreation)); } return(rangeCreation); } BoundExpression tryOptimizeOperand(BoundExpression operand) { Debug.Assert(operand != null); operand = VisitExpression(operand); if (NullableNeverHasValue(operand)) { operand = new BoundDefaultExpression(operand.Syntax, operand.Type.GetNullableUnderlyingType()); } else { operand = NullableAlwaysHasValue(operand) ?? operand; if (operand.Type.IsNullableType()) { needLifting = true; } } return(operand); } }