protected internal override object VisitPointerType(PointerTypeSymbol symbol, ArrayBuilder<SymbolDescriptionPart> builder)
        {
            VisitType(symbol.PointedAtType, builder);
            AddPunctuation(SyntaxKind.AsteriskToken, builder);

            return null;
        }
 internal Context(ArrayBuilder<SyntaxTree> builder, Compilation compilation, string path, bool writeToDisk)
 {
     _builder = builder;
     _compilation = compilation;
     _path = path;
     _writeToDisk = writeToDisk;
 }
        protected internal override object VisitArrayType(ArrayTypeSymbol symbol, ArrayBuilder<SymbolDescriptionPart> builder)
        {
            //See spec section 12.1 for the order of rank specificiers
            //e.g. int[][,][,,] is stored as 
            //     ArrayType
            //         Rank = 1
            //         ElementType = ArrayType
            //             Rank = 2
            //             ElementType = ArrayType
            //                 Rank = 3
            //                 ElementType = int

            TypeSymbol underlyingNonArrayType = symbol.ElementType;
            while (underlyingNonArrayType.TypeKind == TypeKind.ArrayType)
            {
                underlyingNonArrayType = ((ArrayTypeSymbol)underlyingNonArrayType).ElementType;
            }

            VisitType(underlyingNonArrayType, builder);

            ArrayTypeSymbol arrayType = symbol;
            while (arrayType != null)
            {
                AddArrayRank(arrayType, builder);
                arrayType = arrayType.ElementType as ArrayTypeSymbol;
            }

            return null;
        }
Exemple #4
0
        internal static void AddSymbolDisplayParts(ArrayBuilder<SymbolDisplayPart> parts, string str)
        {
            PooledStringBuilder pooledBuilder = PooledStringBuilder.GetInstance();
            StringBuilder sb = pooledBuilder.Builder;

            int lastKind = -1;
            foreach (int token in TokenizeString(str, quote: true, nonPrintableSubstitute: '\0', useHexadecimalNumbers: true))
            {
                int kind = token >> 16;

                // merge contiguous tokens of the same kind into a single part:
                if (lastKind >= 0 && lastKind != kind)
                {
                    parts.Add(new SymbolDisplayPart((SymbolDisplayPartKind)lastKind, null, sb.ToString()));
                    sb.Clear();
                }

                lastKind = kind;
                sb.Append(unchecked((char)token));
            }

            if (lastKind >= 0)
            {
                parts.Add(new SymbolDisplayPart((SymbolDisplayPartKind)lastKind, null, sb.ToString()));
            }

            pooledBuilder.Free();
        }
 /// <summary>
 /// Lower the given decision tree into the given statement builder.
 /// </summary>
 public void LowerDecisionTree(BoundExpression expression, DecisionTree decisionTree, ArrayBuilder<BoundStatement> loweredDecisionTree)
 {
     var oldLoweredDecisionTree = this._loweredDecisionTree;
     this._loweredDecisionTree = loweredDecisionTree;
     LowerDecisionTree(expression, decisionTree);
     this._loweredDecisionTree = oldLoweredDecisionTree;
 }
Exemple #6
0
        internal override void GetRows(
            ResultProvider resultProvider,
            ArrayBuilder<EvalResult> rows,
            DkmInspectionContext inspectionContext,
            EvalResultDataItem parent,
            DkmClrValue value,
            int startIndex,
            int count,
            bool visitAll,
            ref int index)
        {
            var fields = GetFields();

            int startIndex2;
            int count2;
            GetIntersection(startIndex, count, index, fields.Count, out startIndex2, out count2);

            int offset = startIndex2 - index;
            for (int i = 0; i < count2; i++)
            {
                var row = GetMemberRow(resultProvider, inspectionContext, value, fields[i + offset], parent);
                rows.Add(row);
            }

            index += fields.Count;
        }
        /// <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);
        }
        private void AccessTupleFields(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
        {
            var target = PlaceholderReplacement(deconstruction.TargetPlaceholder);
            var tupleType = target.Type.IsTupleType ? target.Type : TupleTypeSymbol.Create((NamedTypeSymbol)target.Type);
            var tupleElementTypes = tupleType.TupleElementTypes;

            var numElements = tupleElementTypes.Length;

            CSharpSyntaxNode syntax = node.Syntax;

            // save the target as we need to access it multiple times
            BoundAssignmentOperator assignmentToTemp;
            var savedTuple = _factory.StoreToTemp(target, out assignmentToTemp);
            stores.Add(assignmentToTemp);
            temps.Add(savedTuple.LocalSymbol);

            // list the tuple fields accessors
            var fields = tupleType.TupleElementFields;

            for (int i = 0; i < numElements; i++)
            {
                var field = fields[i];

                DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic();
                if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error)
                {
                    Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, syntax.Location);
                }
                var fieldAccess = MakeTupleFieldAccess(syntax, field, savedTuple, null, LookupResultKind.Empty);

                AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], fieldAccess);
                placeholders.Add(deconstruction.OutputPlaceholders[i]);
            }
        }
        /// <summary>
        /// Create a SequencePointList with the raw sequence points from an ArrayBuilder.
        /// A linked list of instances for each syntax tree is created (almost always of length one).
        /// </summary>
        public static SequencePointList Create(ArrayBuilder<RawSequencePoint> seqPointBuilder, ILBuilder builder)
        {
            if (seqPointBuilder.Count == 0)
            {
                return SequencePointList.s_empty;
            }

            SequencePointList first = null, current = null;
            int totalPoints = seqPointBuilder.Count;
            int last = 0;

            for (int i = 1; i <= totalPoints; ++i)
            {
                if (i == totalPoints || seqPointBuilder[i].SyntaxTree != seqPointBuilder[i - 1].SyntaxTree)
                {
                    // Create a new list
                    SequencePointList next = new SequencePointList(seqPointBuilder[i - 1].SyntaxTree, GetSubArray(seqPointBuilder, last, i - last, builder));
                    last = i;

                    // Link together with any additional.
                    if (current == null)
                    {
                        first = current = next;
                    }
                    else
                    {
                        current._next = next;
                        current = next;
                    }
                }
            }

            return first;
        }
 private static void AddNonIncluded(ArrayBuilder<string> builder, string item)
 {
     if (!builder.Contains(item))
     {
         builder.Add(item);
     }
 }
        private static void GetAllScopes(
            ISymUnmanagedScope root,
            ArrayBuilder<ISymUnmanagedScope> allScopes,
            ArrayBuilder<ISymUnmanagedScope> containingScopes,
            int offset,
            bool isScopeEndInclusive)
        {
            var stack = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
            stack.Push(root);

            while (stack.Any())
            {
                var scope = stack.Pop();
                allScopes.Add(scope);
                if (offset >= 0 && scope.IsInScope(offset, isScopeEndInclusive))
                {
                    containingScopes.Add(scope);
                }

                foreach (var nested in scope.GetScopes())
                {
                    stack.Push(nested);
                }
            }

            stack.Free();
        }
        private DynamicFlagsCustomTypeInfo(ArrayBuilder<bool> dynamicFlags, int startIndex)
        {
            Debug.Assert(dynamicFlags != null);
            Debug.Assert(startIndex >= 0);

            int numFlags = dynamicFlags.Count - startIndex;
            Debug.Assert(numFlags > 0);

            int numBytes = (numFlags + 7) / 8;
            byte[] bytes = new byte[numBytes];
            bool seenTrue = false;
            for (int b = 0; b < numBytes; b++)
            {
                for (int i = 0; i < 8; i++)
                {
                    var f = b * 8 + i;
                    if (f >= numFlags)
                    {
                        Debug.Assert(f == numFlags);
                        goto ALL_FLAGS_READ;
                    }

                    if (dynamicFlags[startIndex + f])
                    {
                        seenTrue = true;
                        bytes[b] |= (byte)(1 << i);
                    }
                }
            }

            ALL_FLAGS_READ:

            _bytes = seenTrue ? new ReadOnlyCollection<byte>(bytes) : null;
        }
        /// <summary>
        /// Applies the conversions.
        /// Adds any new locals to the temps and any new expressions to be evaluated to the stores.
        /// </summary>
        private void ApplyConversions(BoundDeconstructionAssignmentOperator node, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
        {
            int numConversions = node.ConversionSteps.Length;
            var conversionLocals = ArrayBuilder<BoundExpression>.GetInstance();

            foreach (var conversionInfo in node.ConversionSteps)
            {
                // lower the conversions and assignments to locals
                var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, conversionInfo.OutputPlaceholder.Type, SynthesizedLocalKind.LoweringTemp);
                var localBound = new BoundLocal(node.Syntax,
                                               localSymbol,
                                               null,
                                               conversionInfo.OutputPlaceholder.Type)
                { WasCompilerGenerated = true };

                temps.Add(localSymbol);
                conversionLocals.Add(localBound);

                AddPlaceholderReplacement(conversionInfo.OutputPlaceholder, localBound);
                placeholders.Add(conversionInfo.OutputPlaceholder);

                var conversion = VisitExpression(conversionInfo.Assignment);

                stores.Add(conversion);
            }
        }
            internal override void AddSynthesizedAttributes(ref ArrayBuilder<SynthesizedAttributeData> attributes)
            {
                base.AddSynthesizedAttributes(ref attributes);

                var compilation = this.DeclaringCompilation;
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor));
            }
        internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(compilationState, ref attributes);

            CSharpCompilation compilation = this.DeclaringCompilation;

            // do not emit CompilerGenerated attributes for fields inside compiler generated types:
            if (!_containingType.IsImplicitlyDeclared)
            {
                AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
            }

            if (!this.SuppressDynamicAttribute &&
                this.Type.ContainsDynamic() &&
                compilation.HasDynamicEmitAttributes() &&
                compilation.CanEmitBoolean())
            {
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(this.Type, this.CustomModifiers.Length));
            }

            if (Type.ContainsTuple() &&
                compilation.HasTupleNamesAttributes &&
                compilation.CanEmitSpecialType(SpecialType.System_String))
            {
                AddSynthesizedAttribute(ref attributes,
                    compilation.SynthesizeTupleNamesAttributeOpt(Type));
            }
        }
Exemple #16
0
 internal SpillBuilder()
 {
     locals = ArrayBuilder<LocalSymbol>.GetInstance();
     temps = ArrayBuilder<BoundSpillTemp>.GetInstance();
     statements = ArrayBuilder<BoundStatement>.GetInstance();
     fields = ArrayBuilder<FieldSymbol>.GetInstance();
 }
Exemple #17
0
 public LargeTextWriter(Encoding encoding, SourceHashAlgorithm checksumAlgorithm, int length)
 {
     _encoding = encoding;
     _checksumAlgorithm = checksumAlgorithm;
     _chunks = ArrayBuilder<char[]>.GetInstance(1 + length / LargeText.ChunkSize);
     _bufferSize = Math.Min(LargeText.ChunkSize, length);
 }
        internal override void AddSynthesizedAttributes(ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(ref attributes);

            var compilation = this.DeclaringCompilation;
            AddSynthesizedAttribute(ref attributes, compilation.SynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
        }
 internal abstract ReadOnlyCollection<byte> CompileGetLocals(
     ArrayBuilder<LocalAndMethod> locals,
     bool argumentsOnly,
     ImmutableArray<Alias> aliases,
     DiagnosticBag diagnostics,
     out string typeName,
     CompilationTestData testData);
        // Rewrite collection initializer add method calls:
        // 2) new List<int> { 1 };
        //                    ~
        private void AddCollectionInitializers(ref ArrayBuilder<BoundExpression> dynamicSiteInitializers, ArrayBuilder<BoundExpression> result, BoundExpression rewrittenReceiver, ImmutableArray<BoundExpression> initializers)
        {
            Debug.Assert(rewrittenReceiver != null || _inExpressionLambda);

            foreach (var initializer in initializers)
            {
                // In general bound initializers may contain bad expressions or element initializers.
                // We don't lower them if they contain errors, so it's safe to assume an element initializer.

                BoundExpression rewrittenInitializer;
                if (initializer.Kind == BoundKind.CollectionElementInitializer)
                {
                    rewrittenInitializer = MakeCollectionInitializer(rewrittenReceiver, (BoundCollectionElementInitializer)initializer);
                }
                else
                {
                    Debug.Assert(!_inExpressionLambda);
                    Debug.Assert(initializer.Kind == BoundKind.DynamicCollectionElementInitializer);

                    rewrittenInitializer = MakeDynamicCollectionInitializer(rewrittenReceiver, (BoundDynamicCollectionElementInitializer)initializer);
                }

                // the call to Add may be omitted
                if (rewrittenInitializer != null)
                {
                    result.Add(rewrittenInitializer);
                }
            }
        }
        internal void CollectLocalsFromDeconstruction(
            ExpressionSyntax declaration,
            LocalDeclarationKind kind,
            ArrayBuilder<LocalSymbol> locals,
            SyntaxNode deconstructionStatement,
            Binder enclosingBinderOpt = null)
        {
            switch (declaration.Kind())
            {
                case SyntaxKind.TupleExpression:
                    {
                        var tuple = (TupleExpressionSyntax)declaration;
                        foreach (var arg in tuple.Arguments)
                        {
                            CollectLocalsFromDeconstruction(arg.Expression, kind, locals, deconstructionStatement, enclosingBinderOpt);
                        }
                        break;
                    }
                case SyntaxKind.DeclarationExpression:
                    {
                        var declarationExpression = (DeclarationExpressionSyntax)declaration;
                        CollectLocalsFromDeconstruction(
                            declarationExpression.Designation, declarationExpression.Type,
                            kind, locals, deconstructionStatement, enclosingBinderOpt);

                        break;
                    }
                case SyntaxKind.IdentifierName:
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(declaration.Kind());
            }
        }
 private LookupResult(ObjectPool<LookupResult> pool)
 {
     this.pool = pool;
     this.kind = LookupResultKind.Empty;
     this.symbolList = new ArrayBuilder<Symbol>();
     this.error = null;
 }
        DispatchMapEntry[] BuildDispatchMap(NodeFactory factory)
        {
            ArrayBuilder<DispatchMapEntry> dispatchMapEntries = new ArrayBuilder<DispatchMapEntry>();
            
            for (int i = 0; i < _type.RuntimeInterfaces.Length; i++)
            {
                var interfaceType = _type.RuntimeInterfaces[i];
                Debug.Assert(interfaceType.IsInterface);

                List<MethodDesc> virtualSlots;
                factory.VirtualSlots.TryGetValue(interfaceType, out virtualSlots);

                if (virtualSlots != null)
                {
                    for (int j = 0; j < virtualSlots.Count; j++)
                    {
                        MethodDesc declMethod = virtualSlots[j];
                        var implMethod = VirtualFunctionResolution.ResolveInterfaceMethodToVirtualMethodOnType(declMethod, _type.GetClosestMetadataType());

                        // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface
                        // dispatch will walk the inheritance chain).
                        if (implMethod != null)
                        {
                            var entry = new DispatchMapEntry();
                            entry.InterfaceIndex = checked((short)i);
                            entry.InterfaceMethodSlot = checked((short)j);
                            entry.ImplementationMethodSlot = checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, implMethod));
                            dispatchMapEntries.Add(entry);
                        }
                    }
                }
            }

            return dispatchMapEntries.ToArray();
        }
        internal void CollectLocalsFromDeconstruction(
            ExpressionSyntax declaration,
            LocalDeclarationKind kind,
            ArrayBuilder<LocalSymbol> locals,
            SyntaxNode deconstructionStatement,
            Binder enclosingBinderOpt = null)
        {
            switch (declaration.Kind())
            {
                case SyntaxKind.TupleExpression:
                    {
                        var tuple = (TupleExpressionSyntax)declaration;
                        foreach (var arg in tuple.Arguments)
                        {
                            CollectLocalsFromDeconstruction(arg.Expression, kind, locals, deconstructionStatement, enclosingBinderOpt);
                        }
                        break;
                    }
                case SyntaxKind.DeclarationExpression:
                    {
                        var declarationExpression = (DeclarationExpressionSyntax)declaration;
                        CollectLocalsFromDeconstruction(
                            declarationExpression.Designation, declarationExpression.Type,
                            kind, locals, deconstructionStatement, enclosingBinderOpt);

                        break;
                    }
                case SyntaxKind.IdentifierName:
                    break;
                default:
                    // In broken code, we can have an arbitrary expression here. Collect its expression variables.
                    ExpressionVariableFinder.FindExpressionVariables(this, locals, declaration);
                    break;
            }
        }
Exemple #25
0
        /// <summary>
        /// There are two kinds of deconstruction-assignments which this binding handles: tuple and non-tuple.
        ///
        /// Returns a BoundDeconstructionAssignmentOperator with a list of deconstruction steps and assignment steps.
        /// Deconstruct steps for tuples have no invocation to Deconstruct, but steps for non-tuples do.
        /// The caller is responsible for releasing all the ArrayBuilders in checkedVariables.
        /// </summary>
        private BoundDeconstructionAssignmentOperator BindDeconstructionAssignment(
                                                        CSharpSyntaxNode node,
                                                        ExpressionSyntax right,
                                                        ArrayBuilder<DeconstructionVariable> checkedVariables,
                                                        DiagnosticBag diagnostics,
                                                        bool isDeclaration,
                                                        BoundDeconstructValuePlaceholder rhsPlaceholder = null)
        {
            // receiver for first Deconstruct step
            var boundRHS = rhsPlaceholder ?? BindValue(right, diagnostics, BindValueKind.RValue);

            boundRHS = FixTupleLiteral(checkedVariables, boundRHS, node, diagnostics);

            if ((object)boundRHS.Type == null)
            {
                // we could still not infer a type for the RHS
                FailRemainingInferences(checkedVariables, diagnostics);

                return new BoundDeconstructionAssignmentOperator(
                            node, isDeclaration, FlattenDeconstructVariables(checkedVariables), boundRHS,
                            ImmutableArray<BoundDeconstructionDeconstructStep>.Empty,
                            ImmutableArray<BoundDeconstructionAssignmentStep>.Empty,
                            ImmutableArray<BoundDeconstructionAssignmentStep>.Empty,
                            ImmutableArray<BoundDeconstructionConstructionStep>.Empty,
                            GetSpecialType(SpecialType.System_Void, diagnostics, node),
                            hasErrors: true);
            }

            var deconstructionSteps = ArrayBuilder<BoundDeconstructionDeconstructStep>.GetInstance(1);
            var conversionSteps = ArrayBuilder<BoundDeconstructionAssignmentStep>.GetInstance(1);
            var assignmentSteps = ArrayBuilder<BoundDeconstructionAssignmentStep>.GetInstance(1);
            var constructionStepsOpt = isDeclaration ? null : ArrayBuilder<BoundDeconstructionConstructionStep>.GetInstance(1);

            bool hasErrors = !DeconstructIntoSteps(
                                    new BoundDeconstructValuePlaceholder(boundRHS.Syntax, boundRHS.Type),
                                    node,
                                    diagnostics,
                                    checkedVariables,
                                    deconstructionSteps,
                                    conversionSteps,
                                    assignmentSteps,
                                    constructionStepsOpt);

            TypeSymbol returnType = isDeclaration ?
                                            GetSpecialType(SpecialType.System_Void, diagnostics, node) :
                                            hasErrors ?
                                                CreateErrorType() :
                                                constructionStepsOpt.Last().OutputPlaceholder.Type;

            var deconstructions = deconstructionSteps.ToImmutableAndFree();
            var conversions = conversionSteps.ToImmutableAndFree();
            var assignments = assignmentSteps.ToImmutableAndFree();
            var constructions = isDeclaration ? default(ImmutableArray<BoundDeconstructionConstructionStep>) : constructionStepsOpt.ToImmutableAndFree();

            FailRemainingInferences(checkedVariables, diagnostics);

            return new BoundDeconstructionAssignmentOperator(
                            node, isDeclaration, FlattenDeconstructVariables(checkedVariables), boundRHS,
                            deconstructions, conversions, assignments, constructions, returnType, hasErrors: hasErrors);
        }
Exemple #26
0
 private LookupResult(ObjectPool<LookupResult> pool)
 {
     _pool = pool;
     _kind = LookupResultKind.Empty;
     _symbolList = new ArrayBuilder<Symbol>();
     _error = null;
 }
        internal sealed override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(compilationState, ref attributes);

            var compilation = this.DeclaringCompilation;

            if (this.IsParams)
            {
                AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_ParamArrayAttribute__ctor));
            }

            // Synthesize DecimalConstantAttribute if we don't have an explicit custom attribute already:
            var defaultValue = this.ExplicitDefaultConstantValue;
            if (defaultValue != ConstantValue.NotAvailable &&
                defaultValue.SpecialType == SpecialType.System_Decimal &&
                DefaultValueFromAttributes == ConstantValue.NotAvailable)
            {
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDecimalConstantAttribute(defaultValue.DecimalValue));
            }

            if (this.Type.ContainsDynamic())
            {
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(this.Type, this.CustomModifiers.Length, this.RefKind));
            }

            if (Type.ContainsTupleNames())
            {
                AddSynthesizedAttribute(ref attributes,
                    compilation.SynthesizeTupleNamesAttribute(Type));
            }
        }
Exemple #28
0
        /// <summary>
        /// In regular C#, all field initializers are assignments to fields and the assigned expressions
        /// may not reference instance members.
        /// </summary>
        private static void BindRegularCSharpFieldInitializers(
            CSharpCompilation compilation,
            ImmutableArray<FieldInitializers> initializers,
            ArrayBuilder<BoundInitializer> boundInitializers,
            DiagnosticBag diagnostics,
            bool generateDebugInfo,
            out ConsList<Imports> firstDebugImports)
        {
            firstDebugImports = null;

            foreach (FieldInitializers siblingInitializers in initializers)
            {
                var infos = ArrayBuilder<FieldInitializerInfo>.GetInstance(); // Exact size is not known up front.
                var locals = GetFieldInitializerInfos(compilation, siblingInitializers, infos, generateDebugInfo, ref firstDebugImports);

                ArrayBuilder<BoundInitializer> initializersBuilder = locals.IsDefaultOrEmpty ? boundInitializers : ArrayBuilder<BoundInitializer>.GetInstance(infos.Count);

                foreach (var info in infos)
                {
                    BoundFieldInitializer boundInitializer = BindFieldInitializer(info.Binder, info.Initializer.Field, info.EqualsValue, diagnostics);
                    initializersBuilder.Add(boundInitializer);
                }

                Debug.Assert(locals.IsDefaultOrEmpty == (initializersBuilder == boundInitializers));
                if (!locals.IsDefaultOrEmpty)
                {
                    boundInitializers.Add(new BoundInitializationScope((CSharpSyntaxNode)siblingInitializers.TypeDeclarationSyntax.GetSyntax(),
                                                                       locals, initializersBuilder.ToImmutableAndFree()));
                }

                infos.Free();
            }
        }
        public SourceAssemblySymbol(
            PhpCompilation compilation,
            string assemblySimpleName,
            string moduleName)
        {
            Debug.Assert(compilation != null);
            Debug.Assert(!String.IsNullOrWhiteSpace(assemblySimpleName));
            Debug.Assert(!String.IsNullOrWhiteSpace(moduleName));
            
            _compilation = compilation;
            _simpleName = assemblySimpleName;
            
            var moduleBuilder = new ArrayBuilder<ModuleSymbol>(1);

            moduleBuilder.Add(new SourceModuleSymbol(this, compilation.SourceSymbolTables, moduleName));

            //var importOptions = (compilation.Options.MetadataImportOptions == MetadataImportOptions.All) ?
            //    MetadataImportOptions.All : MetadataImportOptions.Internal;

            //foreach (PEModule netModule in netModules)
            //{
            //    moduleBuilder.Add(new PEModuleSymbol(this, netModule, importOptions, moduleBuilder.Count));
            //    // SetReferences will be called later by the ReferenceManager (in CreateSourceAssemblyFullBind for 
            //    // a fresh manager, in CreateSourceAssemblyReuseData for a reused one).
            //}

            _modules = moduleBuilder.ToImmutableAndFree();
        }
        // Virtual function related functionality
        public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string declName)
        {
            MetadataReader metadataReader = _module.MetadataReader;
            var stringComparer = metadataReader.StringComparer;
            ArrayBuilder<MethodImplRecord> foundRecords = new ArrayBuilder<MethodImplRecord>();

            foreach (var methodImplHandle in _typeDefinition.GetMethodImplementations())
            {
                MethodImplementation methodImpl = metadataReader.GetMethodImplementation(methodImplHandle);

                EntityHandle methodDeclCheckHandle = methodImpl.MethodDeclaration;
                HandleKind methodDeclHandleKind = methodDeclCheckHandle.Kind;

                // We want to check that the method name matches before actually getting the MethodDesc. For MethodSpecifications
                // we need to dereference that handle to the underlying member reference to look at name matching.
                if (methodDeclHandleKind == HandleKind.MethodSpecification)
                {
                    methodDeclCheckHandle = metadataReader.GetMethodSpecification((MethodSpecificationHandle)methodDeclCheckHandle).Method;
                    methodDeclHandleKind = methodDeclCheckHandle.Kind;
                }

                bool foundRecord = false;

                switch (methodDeclHandleKind)
                {
                    case HandleKind.MethodDefinition:
                        if (stringComparer.Equals(metadataReader.GetMethodDefinition((MethodDefinitionHandle)methodDeclCheckHandle).Name, declName))
                        {
                            foundRecord = true;
                        }
                        break;

                    case HandleKind.MemberReference:
                        if (stringComparer.Equals(metadataReader.GetMemberReference((MemberReferenceHandle)methodDeclCheckHandle).Name, declName))
                        {
                            foundRecord = true;
                        }
                        break;

                    default:
                        Debug.Assert(false, "unexpected methodDeclHandleKind");
                        break;
                }

                if (foundRecord)
                {
                    MethodImplRecord newRecord = new MethodImplRecord();
                    newRecord.Decl = (MethodDesc)_module.GetObject(methodImpl.MethodDeclaration);
                    newRecord.Body = (MethodDesc)_module.GetObject(methodImpl.MethodBody);

                    foundRecords.Add(newRecord);
                }
            }

            if (foundRecords.Count != 0)
                return foundRecords.ToArray();

            return null;
        }
        private BoundExpression VisitInitializer(BoundExpression node, out InitializerKind kind)
        {
            switch (node.Kind)
            {
            case BoundKind.ObjectInitializerExpression:
            {
                var oi      = (BoundObjectInitializerExpression)node;
                var builder = ArrayBuilder <BoundExpression> .GetInstance();

                foreach (BoundAssignmentOperator a in oi.Initializers)
                {
                    var sym = ((BoundObjectInitializerMember)a.Left).MemberSymbol;

                    // An error is reported in diagnostics pass when a dynamic object initializer is encountered in an ET:
                    Debug.Assert((object)sym != null);

                    InitializerKind elementKind;
                    var             value = VisitInitializer(a.Right, out elementKind);
                    switch (elementKind)
                    {
                    case InitializerKind.CollectionInitializer:
                    {
                        var left = InitializerMemberGetter(sym);
                        builder.Add(ExprFactory("ListBind", left, value));
                        break;
                    }

                    case InitializerKind.Expression:
                    {
                        var left = InitializerMemberSetter(sym);
                        builder.Add(ExprFactory("Bind", left, value));
                        break;
                    }

                    case InitializerKind.MemberInitializer:
                    {
                        var left = InitializerMemberGetter(sym);
                        builder.Add(ExprFactory("MemberBind", left, value));
                        break;
                    }

                    default:
                        throw ExceptionUtilities.UnexpectedValue(elementKind);
                    }
                }

                kind = InitializerKind.MemberInitializer;
                return(_bound.Array(MemberBindingType, builder.ToImmutableAndFree()));
            }

            case BoundKind.CollectionInitializerExpression:
            {
                var ci = (BoundCollectionInitializerExpression)node;
                Debug.Assert(ci.Initializers.Length != 0);
                kind = InitializerKind.CollectionInitializer;

                var builder = ArrayBuilder <BoundExpression> .GetInstance();

                // The method invocation must be a static call.
                // Dynamic calls are not allowed in ETs, an error is reported in diagnostics pass.
                foreach (BoundCollectionElementInitializer i in ci.Initializers)
                {
                    BoundExpression elementInit = ExprFactory("ElementInit", _bound.MethodInfo(i.AddMethod), Expressions(i.Arguments));
                    builder.Add(elementInit);
                }

                return(_bound.Array(ElementInitType, builder.ToImmutableAndFree()));
            }

            default:
            {
                kind = InitializerKind.Expression;
                return(Visit(node));
            }
            }
        }
Exemple #32
0
        // Returns true if there were any applicable candidates.
        private bool CandidateOperators(ArrayBuilder <UnaryOperatorSignature> operators, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            bool anyApplicable = false;

            foreach (var op in operators)
            {
                var conversion = Conversions.ClassifyConversionFromExpression(operand, op.OperandType, ref useSiteDiagnostics);
                if (conversion.IsImplicit)
                {
                    anyApplicable = true;
                    results.Add(UnaryOperatorAnalysisResult.Applicable(op, conversion));
                }
                else
                {
                    results.Add(UnaryOperatorAnalysisResult.Inapplicable(op, conversion));
                }
            }

            return(anyApplicable);
        }
Exemple #33
0
        private void GetAllBuiltInOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // The spec states that overload resolution is performed upon the infinite set of
            // operators defined on enumerated types, pointers and delegates. Clearly we cannot
            // construct the infinite set; we have to pare it down. Previous implementations of C#
            // implement a much stricter rule; they only add the special operators to the candidate
            // set if one of the operands is of the relevant type. This means that operands
            // involving user-defined implicit conversions from class or struct types to enum,
            // pointer and delegate types do not cause the right candidates to participate in
            // overload resolution. It also presents numerous problems involving delegate variance
            // and conversions from lambdas to delegate types.
            //
            // It is onerous to require the actually specified behavior. We should change the
            // specification to match the previous implementation.

            var operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            this.Compilation.builtInOperators.GetSimpleBuiltInOperators(kind, operators);

            GetEnumOperations(kind, operand, operators);

            var pointerOperator = GetPointerOperation(kind, operand);

            if (pointerOperator != null)
            {
                operators.Add(pointerOperator.Value);
            }

            CandidateOperators(operators, operand, results, ref useSiteDiagnostics);
            operators.Free();
        }
Exemple #34
0
        // Returns true if there were any applicable candidates.
        private bool GetUserDefinedOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(operand != null);

            if ((object)operand.Type == null)
            {
                // If the operand has no type -- because it is a null reference or a lambda or a method group --
                // there is no way we can determine what type to search for user-defined operators.
                return(false);
            }

            // Spec 7.3.5 Candidate user-defined operators
            // SPEC: Given a type T and an operation op(A) ... the set of candidate user-defined
            // SPEC: operators provided by T for op(A) is determined as follows:

            // SPEC: If T is a nullable type then T0 is its underlying type; otherwise T0 is T.
            // SPEC: For all operator declarations in T0 and all lifted forms of such operators, if
            // SPEC: at least one operator is applicable with respect to A then the set of candidate
            // SPEC: operators consists of all such applicable operators. Otherwise, if T0 is object
            // SPEC: then the set of candidate operators is empty. Otherwise, the set of candidate
            // SPEC: operators is the set provided by the direct base class of T0, or the effective
            // SPEC: base class of T0 if T0 is a type parameter.

            TypeSymbol type0 = operand.Type.StrippedType();

            // Searching for user-defined operators is expensive; let's take an early out if we can.
            if (OperatorFacts.DefinitelyHasNoUserDefinedOperators(type0))
            {
                return(false);
            }

            string name      = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind);
            var    operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            bool hadApplicableCandidates = false;

            NamedTypeSymbol current = type0 as NamedTypeSymbol;

            if ((object)current == null)
            {
                current = type0.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }

            if ((object)current == null && type0.IsTypeParameter())
            {
                current = ((TypeParameterSymbol)type0).EffectiveBaseClass(ref useSiteDiagnostics);
            }

            for (; (object)current != null; current = current.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                operators.Clear();
                GetUserDefinedUnaryOperatorsFromType(current, kind, name, operators);
                results.Clear();
                if (CandidateOperators(operators, operand, results, ref useSiteDiagnostics))
                {
                    hadApplicableCandidates = true;
                    break;
                }
            }

            operators.Free();

            return(hadApplicableCandidates);
        }
Exemple #35
0
        private void GetEnumOperations(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorSignature> operators)
        {
            Debug.Assert(operand != null);

            var enumType = operand.Type;

            if ((object)enumType == null)
            {
                return;
            }

            enumType = enumType.StrippedType();
            if (!enumType.IsValidEnumType())
            {
                return;
            }

            var nullableEnum = MakeNullable(enumType);

            switch (kind)
            {
            case UnaryOperatorKind.PostfixIncrement:
            case UnaryOperatorKind.PostfixDecrement:
            case UnaryOperatorKind.PrefixIncrement:
            case UnaryOperatorKind.PrefixDecrement:
            case UnaryOperatorKind.BitwiseComplement:
                operators.Add(new UnaryOperatorSignature(kind | UnaryOperatorKind.Enum, enumType, enumType));
                operators.Add(new UnaryOperatorSignature(kind | UnaryOperatorKind.Lifted | UnaryOperatorKind.Enum, nullableEnum, nullableEnum));
                break;
            }
        }
        public override BoundNode VisitCatchBlock(BoundCatchBlock node)
        {
            if (!_analysis.CatchContainsAwait(node))
            {
                var origCurrentAwaitCatchFrame = _currentAwaitCatchFrame;
                _currentAwaitCatchFrame = null;

                var result = base.VisitCatchBlock(node);
                _currentAwaitCatchFrame = origCurrentAwaitCatchFrame;
                return(result);
            }

            var currentAwaitCatchFrame = _currentAwaitCatchFrame;

            if (currentAwaitCatchFrame == null)
            {
                Debug.Assert(node.Syntax.IsKind(SyntaxKind.CatchClause));
                var tryStatementSyntax = (TryStatementSyntax)node.Syntax.Parent;

                currentAwaitCatchFrame = _currentAwaitCatchFrame = new AwaitCatchFrame(_F, tryStatementSyntax);
            }

            var catchType = node.ExceptionTypeOpt ?? _F.SpecialType(SpecialType.System_Object);
            var catchTemp = _F.SynthesizedLocal(catchType);

            var storePending = _F.AssignmentExpression(
                _F.Local(currentAwaitCatchFrame.pendingCaughtException),
                _F.Convert(currentAwaitCatchFrame.pendingCaughtException.Type,
                           _F.Local(catchTemp)));

            var setPendingCatchNum = _F.Assignment(
                _F.Local(currentAwaitCatchFrame.pendingCatch),
                _F.Literal(currentAwaitCatchFrame.handlers.Count + 1));

            //  catch (ExType exTemp)
            //  {
            //      pendingCaughtException = exTemp;
            //      catchNo = X;
            //  }
            BoundCatchBlock catchAndPend;
            ImmutableArray <LocalSymbol> handlerLocals;

            var filterPrologueOpt = node.ExceptionFilterPrologueOpt;
            var filterOpt         = node.ExceptionFilterOpt;

            if (filterOpt == null)
            {
                Debug.Assert(filterPrologueOpt is null);
                // store pending exception
                // as the first statement in a catch
                catchAndPend = node.Update(
                    ImmutableArray.Create(catchTemp),
                    _F.Local(catchTemp),
                    catchType,
                    exceptionFilterPrologueOpt: filterPrologueOpt,
                    exceptionFilterOpt: null,
                    body: _F.Block(
                        _F.HiddenSequencePoint(),
                        _F.ExpressionStatement(storePending),
                        setPendingCatchNum),
                    isSynthesizedAsyncCatchAll: node.IsSynthesizedAsyncCatchAll);

                // catch locals live on the synthetic catch handler block
                handlerLocals = node.Locals;
            }
            else
            {
                handlerLocals = ImmutableArray <LocalSymbol> .Empty;

                // catch locals move up into hoisted locals
                // since we might need to access them from both the filter and the catch
                foreach (var local in node.Locals)
                {
                    currentAwaitCatchFrame.HoistLocal(local, _F);
                }

                // store pending exception
                // as the first expression in a filter
                var sourceOpt         = node.ExceptionSourceOpt;
                var rewrittenPrologue = (BoundStatementList)this.Visit(filterPrologueOpt);
                var rewrittenFilter   = (BoundExpression)this.Visit(filterOpt);
                var newFilter         = sourceOpt == null?
                                        _F.MakeSequence(
                    storePending,
                    rewrittenFilter) :
                                            _F.MakeSequence(
                                                storePending,
                                                AssignCatchSource((BoundExpression)this.Visit(sourceOpt), currentAwaitCatchFrame),
                                                rewrittenFilter);

                catchAndPend = node.Update(
                    ImmutableArray.Create(catchTemp),
                    _F.Local(catchTemp),
                    catchType,
                    exceptionFilterPrologueOpt: rewrittenPrologue,
                    exceptionFilterOpt: newFilter,
                    body: _F.Block(
                        _F.HiddenSequencePoint(),
                        setPendingCatchNum),
                    isSynthesizedAsyncCatchAll: node.IsSynthesizedAsyncCatchAll);
            }

            var handlerStatements = ArrayBuilder <BoundStatement> .GetInstance();

            handlerStatements.Add(_F.HiddenSequencePoint());

            if (filterOpt == null)
            {
                var sourceOpt = node.ExceptionSourceOpt;
                if (sourceOpt != null)
                {
                    BoundExpression assignSource = AssignCatchSource((BoundExpression)this.Visit(sourceOpt), currentAwaitCatchFrame);
                    handlerStatements.Add(_F.ExpressionStatement(assignSource));
                }
            }

            handlerStatements.Add((BoundStatement)this.Visit(node.Body));

            var handler = _F.Block(
                handlerLocals,
                handlerStatements.ToImmutableAndFree()
                );

            currentAwaitCatchFrame.handlers.Add(handler);

            return(catchAndPend);
        }
Exemple #37
0
        /// <summary>
        /// Populates a list of unary operator results with those from any
        /// witness in scope at the operator site.
        /// </summary>
        /// <param name="kind">
        /// The unary operator kind of the expression.
        /// </param>
        /// <param name="operand">
        /// The operand expression.
        /// </param>
        /// <param name="results">
        /// The results list to populate.
        /// </param>
        /// <param name="useSiteDiagnostics">
        /// The set of diagnostics to populate with any errors.
        /// </param>
        /// <returns>
        /// True if we managed to find candidate operators from the concept
        /// witnesses in scope; false otherwise.
        /// </returns>
        private bool GetUnaryWitnessOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(operand != null);

            string name = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind);

            var operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            foreach (var method in GetWitnessOperators(name, 1, ref useSiteDiagnostics))
            {
                // TODO: nullability
                operators.Add(new UnaryOperatorSignature(UnaryOperatorKind.UserDefined | kind, method.ParameterTypes[0], method.ReturnType, method));
            }

            bool hasCandidates = CandidateOperators(operators, operand, results, ref useSiteDiagnostics);

            operators.Free();
            return(hasCandidates);
        }
Exemple #38
0
            internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder <SynthesizedAttributeData> attributes)
            {
                base.AddSynthesizedAttributes(moduleBuilder, ref attributes);

                AddSynthesizedAttribute(ref attributes, this.DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor));
            }
        public override BoundNode VisitTryStatement(BoundTryStatement node)
        {
            // if node contains no yields, do regular rewrite in the current frame.
            if (!ContainsYields(node))
            {
                _tryNestingLevel++;
                var result = node.Update(
                    (BoundBlock)Visit(node.TryBlock),
                    VisitList(node.CatchBlocks),
                    (BoundBlock)Visit(node.FinallyBlockOpt),
                    node.PreferFaultHandler);

                _tryNestingLevel--;
                return(result);
            }

            Debug.Assert(node.CatchBlocks.IsEmpty, "try with yields must have no catches");
            Debug.Assert(node.FinallyBlockOpt != null, "try with yields must have finally");

            // rewrite TryBlock in a new frame.
            var frame = PushFrame(node);

            _tryNestingLevel++;
            var rewrittenBody = (BoundStatement)this.Visit(node.TryBlock);

            Debug.Assert(!frame.IsRoot());
            Debug.Assert(frame.parent.knownStates.ContainsValue(frame), "parent must be aware about states in the child frame");

            var finallyMethod = frame.handler;
            var origMethod    = F.CurrentFunction;

            // rewrite finally block into a Finally method.
            F.CurrentFunction = finallyMethod;
            var rewrittenHandler = (BoundStatement)this.Visit(node.FinallyBlockOpt);

            _tryNestingLevel--;
            PopFrame();

            // {
            //      this.state = parentFinalizeState;
            //      body;
            //      return;
            // }
            Debug.Assert(frame.parent.finalizeState == _currentFinallyFrame.finalizeState);
            rewrittenHandler = F.Block((object)this.cachedThis != null ?
                                       ImmutableArray.Create(this.cachedThis) :
                                       ImmutableArray <LocalSymbol> .Empty,
                                       F.Assignment(F.Field(F.This(), stateField), F.Literal(frame.parent.finalizeState)),
                                       CacheThisIfNeeded(),
                                       rewrittenHandler,
                                       F.Return()
                                       );

            F.CloseMethod(rewrittenHandler);
            F.CurrentFunction = origMethod;


            var bodyStatements = ArrayBuilder <BoundStatement> .GetInstance();

            // add a call to the handler after the try body.
            //
            // {
            //      this.state = finalizeState;
            //      body;
            //      this.Finally();   // will reset the state to the finally state of the parent.
            // }
            bodyStatements.Add(F.Assignment(F.Field(F.This(), stateField), F.Literal(frame.finalizeState)));
            bodyStatements.Add(rewrittenBody);
            bodyStatements.Add(F.ExpressionStatement(F.Call(F.This(), finallyMethod)));

            // handle proxy labels if have any
            if (frame.proxyLabels != null)
            {
                var dropThrough = F.GenerateLabel("dropThrough");
                bodyStatements.Add(F.Goto(dropThrough));
                var parent = frame.parent;

                foreach (var p in frame.proxyLabels)
                {
                    var proxy       = p.Value;
                    var destination = p.Key;

                    // branch lands here
                    bodyStatements.Add(F.Label(proxy));

                    // finalize current state, proceed to destination.
                    bodyStatements.Add(F.ExpressionStatement(F.Call(F.This(), finallyMethod)));

                    // let the parent forward the branch appropriately
                    var parentProxy = parent.ProxyLabelIfNeeded(destination);
                    bodyStatements.Add(F.Goto(parentProxy));
                }

                bodyStatements.Add(F.Label(dropThrough));
            }

            return(F.Block(bodyStatements.ToImmutableAndFree()));
        }
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder <SynthesizedAttributeData>?attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);

            var compilation = this.DeclaringCompilation;
            var type        = this.TypeWithAnnotations;

            if (type.Type.ContainsDynamic())
            {
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.Type, type.CustomModifiers.Length));
            }

            if (type.Type.ContainsTupleNames())
            {
                AddSynthesizedAttribute(ref attributes,
                                        DeclaringCompilation.SynthesizeTupleNamesAttribute(type.Type));
            }

            if (compilation.ShouldEmitNullableAttributes(this))
            {
                AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableAttributeIfNecessary(this, containingType.GetNullableContextValue(), type));
            }
        }
Exemple #41
0
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder <SynthesizedAttributeData> attributes)
        {
            // Emit [Dynamic] on synthesized parameter symbols when the original parameter was dynamic
            // in order to facilitate debugging.  In the case the necessary attributes are missing
            // this is a no-op.  Emitting an error here, or when the original parameter was bound, would
            // adversely effect the compilation or potentially change overload resolution.
            var compilation = this.DeclaringCompilation;
            var type        = this.TypeWithAnnotations;

            if (type.Type.ContainsDynamic() && compilation.HasDynamicEmitAttributes(BindingDiagnosticBag.Discarded, Location.None) && compilation.CanEmitBoolean())
            {
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.Type, type.CustomModifiers.Length + this.RefCustomModifiers.Length, this.RefKind));
            }

            if (type.Type.ContainsNativeInteger())
            {
                AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNativeIntegerAttribute(this, type.Type));
            }

            if (type.Type.ContainsTupleNames() &&
                compilation.HasTupleNamesAttributes(BindingDiagnosticBag.Discarded, Location.None) &&
                compilation.CanEmitSpecialType(SpecialType.System_String))
            {
                AddSynthesizedAttribute(ref attributes,
                                        compilation.SynthesizeTupleNamesAttribute(type.Type));
            }

            if (compilation.ShouldEmitNullableAttributes(this))
            {
                AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableAttributeIfNecessary(this, GetNullableContextValue(), type));
            }

            if (this.RefKind == RefKind.RefReadOnly)
            {
                AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(this));
            }
        }
Exemple #42
0
        private BoundExpression HoistExpression(
            BoundExpression expr,
            AwaitExpressionSyntax awaitSyntaxOpt,
            int syntaxOffset,
            RefKind refKind,
            ArrayBuilder <BoundExpression> sideEffects,
            ArrayBuilder <StateMachineFieldSymbol> hoistedFields,
            ref bool needsSacrificialEvaluation)
        {
            switch (expr.Kind)
            {
            case BoundKind.ArrayAccess:
            {
                var             array      = (BoundArrayAccess)expr;
                BoundExpression expression = HoistExpression(array.Expression, awaitSyntaxOpt, syntaxOffset, RefKind.None, sideEffects, hoistedFields, ref needsSacrificialEvaluation);
                var             indices    = ArrayBuilder <BoundExpression> .GetInstance();

                foreach (var index in array.Indices)
                {
                    indices.Add(HoistExpression(index, awaitSyntaxOpt, syntaxOffset, RefKind.None, sideEffects, hoistedFields, ref needsSacrificialEvaluation));
                }

                needsSacrificialEvaluation = true;         // need to force array index out of bounds exceptions
                return(array.Update(expression, indices.ToImmutableAndFree(), array.Type));
            }

            case BoundKind.FieldAccess:
            {
                var field = (BoundFieldAccess)expr;
                if (field.FieldSymbol.IsStatic)
                {
                    // the address of a static field, and the value of a readonly static field, is stable
                    if (refKind != RefKind.None || field.FieldSymbol.IsLet)
                    {
                        return(expr);
                    }
                    goto default;
                }

                if (refKind == RefKind.None)
                {
                    goto default;
                }

                var isFieldOfStruct = !field.FieldSymbol.ContainingType.IsReferenceType;

                var receiver = HoistExpression(field.ReceiverOpt, awaitSyntaxOpt, syntaxOffset,
                                               isFieldOfStruct ? refKind : RefKind.None, sideEffects, hoistedFields, ref needsSacrificialEvaluation);
                if (receiver.Kind != BoundKind.ThisReference && !isFieldOfStruct)
                {
                    needsSacrificialEvaluation = true;         // need the null check in field receiver
                }

                return(F.Field(receiver, field.FieldSymbol));
            }

            case BoundKind.ThisReference:
            case BoundKind.BaseReference:
            case BoundKind.DefaultExpression:
                return(expr);

            case BoundKind.Call:
                var call = (BoundCall)expr;
                // NOTE: There are two kinds of 'In' arguments that we may see at this point:
                //       - `RefKindExtensions.StrictIn`     (originally specified with 'In' modifier)
                //       - `RefKind.In`                     (specified with no modifiers and matched an 'In' parameter)
                //
                //       It is allowed to spill ordinary `In` arguments by value if reference-preserving spilling is not possible.
                //       The "strict" ones do not permit implicit copying, so the same situation should result in an error.
                if (refKind != RefKind.None && refKind != RefKind.In)
                {
                    Debug.Assert(call.Method.RefKind != RefKind.None);
                    F.Diagnostics.Add(ErrorCode.ERR_RefReturningCallAndAwait, F.Syntax.Location, call.Method);
                }
                // method call is not referentially transparent, we can only spill the result value.
                refKind = RefKind.None;
                goto default;

            case BoundKind.ConditionalOperator:
                var conditional = (BoundConditionalOperator)expr;
                // NOTE: There are two kinds of 'In' arguments that we may see at this point:
                //       - `RefKindExtensions.StrictIn`     (originally specified with 'In' modifier)
                //       - `RefKind.In`                     (specified with no modifiers and matched an 'In' parameter)
                //
                //       It is allowed to spill ordinary `In` arguments by value if reference-preserving spilling is not possible.
                //       The "strict" ones do not permit implicit copying, so the same situation should result in an error.
                if (refKind != RefKind.None && refKind != RefKind.RefReadOnly)
                {
                    Debug.Assert(conditional.IsRef);
                    F.Diagnostics.Add(ErrorCode.ERR_RefConditionalAndAwait, F.Syntax.Location);
                }
                // conditional expr is not referentially transparent, we can only spill the result value.
                refKind = RefKind.None;
                goto default;

            default:
                if (expr.ConstantValue != null)
                {
                    return(expr);
                }

                if (refKind != RefKind.None)
                {
                    throw ExceptionUtilities.UnexpectedValue(expr.Kind);
                }

                TypeSymbol fieldType = expr.Type;
                StateMachineFieldSymbol hoistedField;
                if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
                {
                    const SynthesizedLocalKind kind = SynthesizedLocalKind.AwaitByRefSpill;

                    Debug.Assert(awaitSyntaxOpt != null);

                    int ordinal = _synthesizedLocalOrdinals.AssignLocalOrdinal(kind, syntaxOffset);
                    var id      = new LocalDebugId(syntaxOffset, ordinal);

                    // Editing await expression is not allowed. Thus all spilled fields will be present in the previous state machine.
                    // However, it may happen that the type changes, in which case we need to allocate a new slot.
                    int slotIndex;
                    if (slotAllocatorOpt == null ||
                        !slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(
                            awaitSyntaxOpt,
                            F.ModuleBuilderOpt.Translate(fieldType, awaitSyntaxOpt, Diagnostics),
                            kind,
                            id,
                            Diagnostics,
                            out slotIndex))
                    {
                        slotIndex = _nextFreeHoistedLocalSlot++;
                    }

                    string fieldName = GeneratedNames.MakeHoistedLocalFieldName(kind, slotIndex);
                    hoistedField = F.StateMachineField(expr.Type, fieldName, new LocalSlotDebugInfo(kind, id), slotIndex);
                }
                else
                {
                    hoistedField = GetOrAllocateReusableHoistedField(fieldType, reused: out _);
                }

                hoistedFields.Add(hoistedField);

                var replacement = F.Field(F.This(), hoistedField);
                sideEffects.Add(F.AssignmentExpression(replacement, expr));
                return(replacement);
            }
        }
Exemple #43
0
        /// <summary>
        /// Translate a statement that declares a given set of locals.  Also allocates and frees hoisted temps as
        /// required for the translation.
        /// </summary>
        /// <param name="locals">The set of locals declared in the original version of this statement</param>
        /// <param name="wrapped">A delegate to return the translation of the body of this statement</param>
        private BoundStatement PossibleIteratorScope(ImmutableArray <LocalSymbol> locals, Func <BoundStatement> wrapped)
        {
            if (locals.IsDefaultOrEmpty)
            {
                return(wrapped());
            }

            var hoistedLocalsWithDebugScopes = ArrayBuilder <StateMachineFieldSymbol> .GetInstance();

            foreach (var local in locals)
            {
                if (!NeedsProxy(local))
                {
                    continue;
                }

                // Ref synthesized variables have proxies that are allocated in VisitAssignmentOperator.
                if (local.RefKind != RefKind.None)
                {
                    Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.Spill);
                    continue;
                }

                Debug.Assert(local.SynthesizedKind.IsLongLived());

                CapturedSymbolReplacement proxy;
                bool reused = false;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    proxy = new CapturedToStateMachineFieldReplacement(GetOrAllocateReusableHoistedField(TypeMap.SubstituteType(local.Type.TypeSymbol).TypeSymbol, out reused, local), isReusable: true);
                    proxies.Add(local, proxy);
                }

                // We need to produce hoisted local scope debug information for user locals as well as
                // lambda display classes, since Dev12 EE uses them to determine which variables are displayed
                // in Locals window.
                if ((local.SynthesizedKind == SynthesizedLocalKind.UserDefined && local.ScopeDesignatorOpt?.Kind() != SyntaxKind.SwitchSection) ||
                    local.SynthesizedKind == SynthesizedLocalKind.LambdaDisplayClass)
                {
                    // NB: This is the case when the local backed by recycled field will not be visible in debugger.
                    //     It may be possible in the future, but for now a backing field can be mapped only to a single local.
                    if (!reused)
                    {
                        hoistedLocalsWithDebugScopes.Add(((CapturedToStateMachineFieldReplacement)proxy).HoistedField);
                    }
                }
            }

            var translatedStatement = wrapped();
            var variableCleanup     = ArrayBuilder <BoundAssignmentOperator> .GetInstance();

            // produce cleanup code for all fields of locals defined by this block
            // as well as all proxies allocated by VisitAssignmentOperator within this block:
            foreach (var local in locals)
            {
                CapturedSymbolReplacement proxy;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    continue;
                }

                var simpleProxy = proxy as CapturedToStateMachineFieldReplacement;
                if (simpleProxy != null)
                {
                    AddVariableCleanup(variableCleanup, simpleProxy.HoistedField);

                    if (proxy.IsReusable)
                    {
                        FreeReusableHoistedField(simpleProxy.HoistedField);
                    }
                }
                else
                {
                    foreach (var field in ((CapturedToExpressionSymbolReplacement)proxy).HoistedFields)
                    {
                        AddVariableCleanup(variableCleanup, field);

                        if (proxy.IsReusable)
                        {
                            FreeReusableHoistedField(field);
                        }
                    }
                }
            }

            if (variableCleanup.Count != 0)
            {
                translatedStatement = F.Block(
                    translatedStatement,
                    F.Block(variableCleanup.SelectAsArray((e, f) => (BoundStatement)f.ExpressionStatement(e), F)));
            }

            variableCleanup.Free();

            // wrap the node in an iterator scope for debugging
            if (hoistedLocalsWithDebugScopes.Count != 0)
            {
                translatedStatement = MakeStateMachineScope(hoistedLocalsWithDebugScopes.ToImmutable(), translatedStatement);
            }

            hoistedLocalsWithDebugScopes.Free();

            return(translatedStatement);
        }
        public override BoundNode VisitTryStatement(BoundTryStatement node)
        {
            var tryStatementSyntax = node.Syntax;

            // If you add a syntax kind to the assertion below, please also ensure
            // that the scenario has been tested with Edit-and-Continue.
            Debug.Assert(
                tryStatementSyntax.IsKind(SyntaxKind.TryStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.ForEachVariableStatement) ||
                tryStatementSyntax.IsKind(SyntaxKind.LocalDeclarationStatement));

            BoundStatement finalizedRegion;
            BoundBlock     rewrittenFinally;

            var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node);

            if (!finallyContainsAwaits)
            {
                finalizedRegion  = RewriteFinalizedRegion(node);
                rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt);

                if (rewrittenFinally == null)
                {
                    return(finalizedRegion);
                }

                var asTry = finalizedRegion as BoundTryStatement;
                if (asTry != null)
                {
                    // since finalized region is a try we can just attach finally to it
                    Debug.Assert(asTry.FinallyBlockOpt == null);
                    return(asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.FinallyLabelOpt, asTry.PreferFaultHandler));
                }
                else
                {
                    // wrap finalizedRegion into a Try with a finally.
                    return(_F.Try((BoundBlock)finalizedRegion, ImmutableArray <BoundCatchBlock> .Empty, rewrittenFinally));
                }
            }

            // rewrite finalized region (try and catches) in the current frame
            var frame = PushFrame(node);

            finalizedRegion  = RewriteFinalizedRegion(node);
            rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt);
            PopFrame();

            var exceptionType         = _F.SpecialType(SpecialType.System_Object);
            var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(exceptionType), SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax);
            var finallyLabel          = _F.GenerateLabel("finallyLabel");
            var pendingBranchVar      = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax);

            var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block());

            var catchAndPendException = _F.Try(
                _F.Block(
                    finalizedRegion,
                    _F.HiddenSequencePoint(),
                    _F.Goto(finallyLabel),
                    PendBranches(frame, pendingBranchVar, finallyLabel)),
                ImmutableArray.Create(catchAll),
                finallyLabel: finallyLabel);

            BoundBlock syntheticFinallyBlock = _F.Block(
                _F.HiddenSequencePoint(),
                _F.Label(finallyLabel),
                rewrittenFinally,
                _F.HiddenSequencePoint(),
                UnpendException(pendingExceptionLocal),
                UnpendBranches(
                    frame,
                    pendingBranchVar,
                    pendingExceptionLocal));

            BoundStatement syntheticFinally = syntheticFinallyBlock;

            if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator)
            {
                // We wrap this block so that it can be processed as a finally block by async-iterator rewriting
                syntheticFinally = _F.ExtractedFinallyBlock(syntheticFinallyBlock);
            }

            var locals = ArrayBuilder <LocalSymbol> .GetInstance();

            var statements = ArrayBuilder <BoundStatement> .GetInstance();

            statements.Add(_F.HiddenSequencePoint());

            locals.Add(pendingExceptionLocal);
            statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type)));
            locals.Add(pendingBranchVar);
            statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type)));

            LocalSymbol returnLocal = frame.returnValue;

            if (returnLocal != null)
            {
                locals.Add(returnLocal);
            }

            statements.Add(catchAndPendException);
            statements.Add(syntheticFinally);

            var completeTry = _F.Block(
                locals.ToImmutableAndFree(),
                statements.ToImmutableAndFree());

            return(completeTry);
        }
Exemple #45
0
        /// <summary>
        /// Determine if "type" inherits from or implements "baseType", ignoring constructed types, and dealing
        /// only with original types.
        /// </summary>
        private static bool InheritsFromOrImplementsIgnoringConstruction(
            this TypeSymbol type,
            NamedTypeSymbol baseType,
            CSharpCompilation compilation,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics,
            ConsList <TypeSymbol> basesBeingResolved = null)
        {
            Debug.Assert(type.IsDefinition);
            Debug.Assert(baseType.IsDefinition);

            PooledHashSet <NamedTypeSymbol> interfacesLookedAt = null;
            ArrayBuilder <NamedTypeSymbol>  baseInterfaces     = null;

            bool baseTypeIsInterface = baseType.IsInterface;

            if (baseTypeIsInterface)
            {
                interfacesLookedAt = PooledHashSet <NamedTypeSymbol> .GetInstance();

                baseInterfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance();
            }

            PooledHashSet <NamedTypeSymbol> visited = null;
            var  current = type;
            bool result  = false;

            while ((object)current != null)
            {
                Debug.Assert(current.IsDefinition);
                if (baseTypeIsInterface == current.IsInterfaceType() &&
                    current == (object)baseType)
                {
                    result = true;
                    break;
                }

                if (baseTypeIsInterface)
                {
                    getBaseInterfaces(current, baseInterfaces, interfacesLookedAt, basesBeingResolved);
                }

                // NOTE(cyrusn): The base type of an 'original' type may not be 'original'. i.e.
                // "class Goo : IBar<int>".  We must map it back to the 'original' when as we walk up
                // the base type hierarchy.
                var next = current.GetNextBaseTypeNoUseSiteDiagnostics(basesBeingResolved, compilation, ref visited);
                if ((object)next == null)
                {
                    current = null;
                }
                else
                {
                    current = (TypeSymbol)next.OriginalDefinition;
                    current.AddUseSiteDiagnostics(ref useSiteDiagnostics);
                }
            }

            visited?.Free();

            if (!result && baseTypeIsInterface)
            {
                Debug.Assert(!result);

                while (baseInterfaces.Count != 0)
                {
                    NamedTypeSymbol currentBase = baseInterfaces.Pop();

                    if (!currentBase.IsInterface)
                    {
                        continue;
                    }

                    Debug.Assert(currentBase.IsDefinition);
                    if (currentBase == (object)baseType)
                    {
                        result = true;
                        break;
                    }

                    getBaseInterfaces(currentBase, baseInterfaces, interfacesLookedAt, basesBeingResolved);
                }

                if (!result)
                {
                    foreach (var candidate in interfacesLookedAt)
                    {
                        candidate.AddUseSiteDiagnostics(ref useSiteDiagnostics);
                    }
                }
            }

            interfacesLookedAt?.Free();
            baseInterfaces?.Free();
            return(result);
Exemple #46
0
 public override void AddPreviousLocals(ArrayBuilder <Cci.ILocalDefinition> builder)
 {
     builder.AddRange(_locals);
 }
        private BoundStatement UnpendBranches(
            AwaitFinallyFrame frame,
            SynthesizedLocal pendingBranchVar,
            SynthesizedLocal pendingException)
        {
            var parent = frame.ParentOpt;

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;

            // skip 0 - it means we took no explicit branches
            int i     = 1;
            var cases = ArrayBuilder <SyntheticBoundNodeFactory.SyntheticSwitchSection> .GetInstance();

            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var target        = proxiedLabels[i - 1];
                    var parentProxy   = parent.ProxyLabelIfNeeded(target);
                    var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy));
                    cases.Add(caseStatement);
                }
            }

            if (frame.returnProxyLabel != null)
            {
                BoundLocal pendingValue = null;
                if (frame.returnValue != null)
                {
                    pendingValue = _F.Local(frame.returnValue);
                }

                SynthesizedLocal returnValue;
                BoundStatement   unpendReturn;

                var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentFunction, pendingValue, out returnValue);

                if (returnLabel == null)
                {
                    unpendReturn = new BoundReturnStatement(_F.Syntax, RefKind.None, pendingValue);
                }
                else
                {
                    if (pendingValue == null)
                    {
                        unpendReturn = _F.Goto(returnLabel);
                    }
                    else
                    {
                        unpendReturn = _F.Block(
                            _F.Assignment(
                                _F.Local(returnValue),
                                pendingValue),
                            _F.Goto(returnLabel));
                    }
                }

                var caseStatement = _F.SwitchSection(i, unpendReturn);
                cases.Add(caseStatement);
            }

            return(_F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree()));
        }
            private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsupportedOperation)
            {
                if (hasUnsupportedOperation)
                {
                    return;
                }

                if (symbolEndContext.Symbol.GetAttributes().Any(a => a.AttributeClass == _structLayoutAttributeType))
                {
                    // Bail out for types with 'StructLayoutAttribute' as the ordering of the members is critical,
                    // and removal of unused members might break semantics.
                    return;
                }

                // Report diagnostics for unused candidate members.
                var first = true;
                PooledHashSet <ISymbol> symbolsReferencedInDocComments    = null;
                ArrayBuilder <string>   debuggerDisplayAttributeArguments = null;

                try
                {
                    var entryPoint = symbolEndContext.Compilation.GetEntryPoint(symbolEndContext.CancellationToken);

                    var namedType = (INamedTypeSymbol)symbolEndContext.Symbol;
                    foreach (var member in namedType.GetMembers())
                    {
                        if (SymbolEqualityComparer.Default.Equals(entryPoint, member))
                        {
                            continue;
                        }

                        // Check if the underlying member is neither read nor a readable reference to the member is taken.
                        // If so, we flag the member as either unused (never written) or unread (written but not read).
                        if (TryRemove(member, out var valueUsageInfo) &&
                            !valueUsageInfo.IsReadFrom())
                        {
                            Debug.Assert(IsCandidateSymbol(member));
                            Debug.Assert(!member.IsImplicitlyDeclared);

                            if (first)
                            {
                                // Bail out if there are syntax errors in any of the declarations of the containing type.
                                // Note that we check this only for the first time that we report an unused or unread member for the containing type.
                                if (HasSyntaxErrors(namedType, symbolEndContext.CancellationToken))
                                {
                                    return;
                                }

                                // Compute the set of candidate symbols referenced in all the documentation comments within the named type declarations.
                                // This set is computed once and used for all the iterations of the loop.
                                symbolsReferencedInDocComments = GetCandidateSymbolsReferencedInDocComments(namedType, symbolEndContext.Compilation, symbolEndContext.CancellationToken);

                                // Compute the set of string arguments to DebuggerDisplay attributes applied to any symbol within the named type declaration.
                                // These strings may have an embedded reference to the symbol.
                                // This set is computed once and used for all the iterations of the loop.
                                debuggerDisplayAttributeArguments = GetDebuggerDisplayAttributeArguments(namedType);

                                first = false;
                            }

                            // Simple heuristic for members referenced in DebuggerDisplayAttribute's string argument:
                            // bail out if any of the DebuggerDisplay string arguments contains the member name.
                            // In future, we can consider improving this heuristic to parse the embedded expression
                            // and resolve symbol references.
                            if (debuggerDisplayAttributeArguments.Any(arg => arg.Contains(member.Name)))
                            {
                                continue;
                            }

                            // Report IDE0051 or IDE0052 based on whether the underlying member has any Write/WritableRef/NonReadWriteRef references or not.
                            var rule = !valueUsageInfo.IsWrittenTo() && !valueUsageInfo.IsNameOnly() && !symbolsReferencedInDocComments.Contains(member)
                                ? s_removeUnusedMembersRule
                                : s_removeUnreadMembersRule;

                            // Do not flag write-only properties that are not read.
                            // Write-only properties are assumed to have side effects
                            // visible through other means than a property getter.
                            if (rule == s_removeUnreadMembersRule &&
                                member is IPropertySymbol property &&
                                property.IsWriteOnly)
                            {
                                continue;
                            }

                            // Most of the members should have a single location, except for partial methods.
                            // We report the diagnostic on the first location of the member.
                            var diagnostic = DiagnosticHelper.CreateWithMessage(
                                rule,
                                member.Locations[0],
                                rule.GetEffectiveSeverity(symbolEndContext.Compilation.Options),
                                additionalLocations: null,
                                properties: null,
                                GetMessage(rule, member));
                            symbolEndContext.ReportDiagnostic(diagnostic);
                        }
                    }
                }
                finally
                {
                    symbolsReferencedInDocComments?.Free();
                    debuggerDisplayAttributeArguments?.Free();
                }

                return;
            }
Exemple #49
0
 internal static bool TryGetTupleFieldValues(this DkmClrValue tuple, int cardinality, ArrayBuilder <string> values, DkmInspectionContext inspectionContext)
 {
     while (true)
     {
         var type = tuple.Type.GetLmrType();
         int n    = Math.Min(cardinality, TupleFieldRestPosition - 1);
         for (int index = 0; index < n; index++)
         {
             var fieldName = GetTupleFieldName(index);
             var fieldInfo = type.GetTupleField(fieldName);
             if (fieldInfo == null)
             {
                 return(false);
             }
             var value = tuple.GetFieldValue(fieldName, inspectionContext);
             var str   = value.GetValueString(inspectionContext, Formatter.NoFormatSpecifiers);
             values.Add(str);
         }
         cardinality -= n;
         if (cardinality == 0)
         {
             return(true);
         }
         var restInfo = type.GetTupleField(TypeHelpers.TupleFieldRestName);
         if (restInfo == null)
         {
             return(false);
         }
         tuple = tuple.GetFieldValue(TupleFieldRestName, inspectionContext);
     }
 }
Exemple #50
0
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder <SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);

            var type = this.Type;

            if (type.TypeSymbol.ContainsDynamic())
            {
                var compilation = this.DeclaringCompilation;
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.TypeSymbol, type.CustomModifiers.Length));
            }

            if (type.TypeSymbol.ContainsTupleNames())
            {
                AddSynthesizedAttribute(ref attributes,
                                        DeclaringCompilation.SynthesizeTupleNamesAttribute(type.TypeSymbol));
            }

            AddSynthesizedNonNullTypesAttributeForMember(ref attributes);

            if (type.ContainsNullableReferenceTypes())
            {
                AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableAttribute(this, type));
            }
        }
Exemple #51
0
        internal static void AppendTypeMembers(
            this Type type,
            ArrayBuilder <MemberAndDeclarationInfo> includedMembers,
            Predicate <MemberInfo> predicate,
            Type declaredType,
            DkmClrAppDomain appDomain,
            bool includeInherited,
            bool hideNonPublic)
        {
            Debug.Assert(!type.IsInterface);

            var memberLocation         = DeclarationInfo.FromSubTypeOfDeclaredType;
            var previousDeclarationMap = includeInherited ? new Dictionary <string, DeclarationInfo>() : null;

            int inheritanceLevel = 0;

            while (!type.IsObject())
            {
                if (type.Equals(declaredType))
                {
                    Debug.Assert(memberLocation == DeclarationInfo.FromSubTypeOfDeclaredType);
                    memberLocation = DeclarationInfo.FromDeclaredTypeOrBase;
                }

                // Get the state from DebuggerBrowsableAttributes for the members of the current type.
                var browsableState = DkmClrType.Create(appDomain, type).GetDebuggerBrowsableAttributeState();

                // Hide non-public members if hideNonPublic is specified (intended to reflect the
                // DkmInspectionContext's DkmEvaluationFlags), and the type is from an assembly
                // with no symbols.
                var hideNonPublicBehavior = DeclarationInfo.None;
                if (hideNonPublic)
                {
                    var moduleInstance = appDomain.FindClrModuleInstance(type.Module.ModuleVersionId);
                    if (moduleInstance == null || moduleInstance.Module == null)
                    {
                        // Synthetic module or no symbols loaded.
                        hideNonPublicBehavior = DeclarationInfo.HideNonPublic;
                    }
                }

                foreach (var member in type.GetMembers(MemberBindingFlags))
                {
                    if (!predicate(member))
                    {
                        continue;
                    }

                    var memberName = member.Name;
                    // This represents information about the immediately preceding (more derived)
                    // declaration with the same name as the current member.
                    var previousDeclaration   = DeclarationInfo.None;
                    var memberNameAlreadySeen = false;
                    if (includeInherited)
                    {
                        memberNameAlreadySeen = previousDeclarationMap.TryGetValue(memberName, out previousDeclaration);
                        if (memberNameAlreadySeen)
                        {
                            // There was a name conflict, so we'll need to include the declaring
                            // type of the member to disambiguate.
                            previousDeclaration |= DeclarationInfo.IncludeTypeInMemberName;
                        }

                        // Update previous member with name hiding (casting) and declared location information for next time.
                        previousDeclarationMap[memberName] =
                            (previousDeclaration & ~(DeclarationInfo.RequiresExplicitCast |
                                                     DeclarationInfo.FromSubTypeOfDeclaredType)) |
                            member.AccessingBaseMemberWithSameNameRequiresExplicitCast() |
                            memberLocation;
                    }

                    Debug.Assert(memberNameAlreadySeen != (previousDeclaration == DeclarationInfo.None));

                    // Decide whether to include this member in the list of members to display.
                    if (!memberNameAlreadySeen || previousDeclaration.IsSet(DeclarationInfo.RequiresExplicitCast))
                    {
                        DkmClrDebuggerBrowsableAttributeState?browsableStateValue = null;
                        if (browsableState != null)
                        {
                            DkmClrDebuggerBrowsableAttributeState value;
                            if (browsableState.TryGetValue(memberName, out value))
                            {
                                browsableStateValue = value;
                            }
                        }

                        if (memberLocation.IsSet(DeclarationInfo.FromSubTypeOfDeclaredType))
                        {
                            // If the current type is a sub-type of the declared type, then
                            // we always need to insert a cast to access the member
                            previousDeclaration |= DeclarationInfo.RequiresExplicitCast;
                        }
                        else if (previousDeclaration.IsSet(DeclarationInfo.FromSubTypeOfDeclaredType))
                        {
                            // If the immediately preceding member (less derived) was
                            // declared on a sub-type of the declared type, then we'll
                            // ignore the casting bit.  Accessing a member through the
                            // declared type is the same as casting to that type, so
                            // the cast would be redundant.
                            previousDeclaration &= ~DeclarationInfo.RequiresExplicitCast;
                        }

                        previousDeclaration |= hideNonPublicBehavior;

                        includedMembers.Add(new MemberAndDeclarationInfo(member, browsableStateValue, previousDeclaration, inheritanceLevel));
                    }
                }

                if (!includeInherited)
                {
                    break;
                }

                type = type.BaseType;
                inheritanceLevel++;
            }

            includedMembers.Sort(MemberAndDeclarationInfo.Comparer);
        }
        public override DictionaryAnalysisData <AnalysisEntity, TValue> Merge(DictionaryAnalysisData <AnalysisEntity, TValue> map1, DictionaryAnalysisData <AnalysisEntity, TValue> map2)
        {
            AssertValidAnalysisData(map1);
            AssertValidAnalysisData(map2);

            var resultMap = new DictionaryAnalysisData <AnalysisEntity, TValue>();

            using var newKeys = PooledHashSet <AnalysisEntity> .GetInstance();

            using var valuesToMergeBuilder = ArrayBuilder <TValue> .GetInstance(5);

            var map2LookupIgnoringInstanceLocation = map2.Keys.Where(IsAnalysisEntityForFieldOrProperty)
                                                     .ToLookup(entity => entity.EqualsIgnoringInstanceLocationId);

            foreach (var entry1 in map1)
            {
                AnalysisEntity key1   = entry1.Key;
                TValue         value1 = entry1.Value;

                if (map2LookupIgnoringInstanceLocation.Count > 0 && IsAnalysisEntityForFieldOrProperty(key1))
                {
                    var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId];
                    if (!equivalentKeys2.Any())
                    {
                        TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1);
                        Debug.Assert(!map2.ContainsKey(key1));
                        Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0);
                        AddNewEntryToResultMap(key1, mergedValue);
                        continue;
                    }

                    foreach (AnalysisEntity key2 in equivalentKeys2)
                    {
                        // Confirm that key2 and key1 are indeed EqualsIgnoringInstanceLocation
                        // This ensures that we handle hash code clashes of EqualsIgnoringInstanceLocationId.
                        if (!key1.EqualsIgnoringInstanceLocation(key2))
                        {
                            continue;
                        }

                        TValue value2 = map2[key2];

                        valuesToMergeBuilder.Clear();
                        valuesToMergeBuilder.Add(value1);
                        valuesToMergeBuilder.Add(value2);

                        if (key1.InstanceLocation.Equals(key2.InstanceLocation))
                        {
                            var mergedValue = GetMergedValue(valuesToMergeBuilder);
                            AddNewEntryToResultMap(key1, mergedValue);
                        }
                        else
                        {
                            if (key1.SymbolOpt == null || !Equals(key1.SymbolOpt, key2.SymbolOpt))
                            {
                                // PERF: Do not add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities.
                                continue;
                            }

                            AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2);

                            var isExistingKeyInInput  = false;
                            var isExistingKeyInResult = false;
                            if (resultMap.TryGetValue(mergedKey, out var existingValue))
                            {
                                valuesToMergeBuilder.Add(existingValue);
                                isExistingKeyInResult = true;
                            }

                            if (map1.TryGetValue(mergedKey, out existingValue))
                            {
                                valuesToMergeBuilder.Add(existingValue);
                                isExistingKeyInInput = true;
                            }

                            if (map2.TryGetValue(mergedKey, out existingValue))
                            {
                                valuesToMergeBuilder.Add(existingValue);
                                isExistingKeyInInput = true;
                            }

                            var isCandidateToBeSkipped = !isExistingKeyInInput && !isExistingKeyInResult;
                            if (isCandidateToBeSkipped && CanSkipNewEntity(mergedKey))
                            {
                                // PERF: Do not add a new key-value pair to the resultMap if the key is not reachable from tracked entities and PointsTo values.
                                continue;
                            }

                            var mergedValue = GetMergedValue(valuesToMergeBuilder);

                            Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0);
                            Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0);

                            if (isCandidateToBeSkipped && CanSkipNewEntry(mergedKey, mergedValue))
                            {
                                // PERF: Do not add a new key-value pair to the resultMap if the value can be skipped.
                                continue;
                            }

                            if (!isExistingKeyInInput)
                            {
                                newKeys.Add(mergedKey);
                            }


                            AddNewEntryToResultMap(mergedKey, mergedValue, isNewKey: !isExistingKeyInInput);
                        }
                    }
                }
                else if (map2.TryGetValue(key1, out var value2))
                {
                    TValue mergedValue = ValueDomain.Merge(value1, value2);
                    Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0);
                    Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0);
                    AddNewEntryToResultMap(key1, mergedValue);
                    continue;
                }

                if (!resultMap.ContainsKey(key1))
                {
                    TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1);
                    Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0);
                    AddNewEntryToResultMap(key1, mergedValue);
                }
            }

            foreach (var kvp in map2)
            {
                var key2   = kvp.Key;
                var value2 = kvp.Value;
                if (!resultMap.ContainsKey(key2))
                {
                    TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2);
                    Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0);
                    AddNewEntryToResultMap(key2, mergedValue);
                }
            }

            foreach (var newKey in newKeys)
            {
                Debug.Assert(!map1.ContainsKey(newKey));
                Debug.Assert(!map2.ContainsKey(newKey));
                var value = resultMap[newKey];
                if (ReferenceEquals(value, GetDefaultValue(newKey)))
                {
                    resultMap.Remove(newKey);
                }
                else
                {
                    OnNewMergedValue(value);
                }
            }

            Debug.Assert(Compare(map1, resultMap) <= 0);
            Debug.Assert(Compare(map2, resultMap) <= 0);
            AssertValidAnalysisData(resultMap);

            return(resultMap);
Exemple #53
0
        internal ImmutableArray <TypeParameterConstraintClause> BindTypeParameterConstraintClauses(
            Symbol containingSymbol,
            ImmutableArray <TypeParameterSymbol> typeParameters,
            TypeParameterListSyntax typeParameterList,
            SyntaxList <TypeParameterConstraintClauseSyntax> clauses,
            ref IReadOnlyDictionary <TypeParameterSymbol, bool> isValueTypeOverride,
            DiagnosticBag diagnostics,
            bool isForOverride = false)
        {
            Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause));
            RoslynDebug.Assert((object)containingSymbol != null);
            Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method));
            Debug.Assert(typeParameters.Length > 0);
            Debug.Assert(clauses.Count > 0);

            int n = typeParameters.Length;

            // Create a map from type parameter name to ordinal.
            // No need to report duplicate names since duplicates
            // are reported when the type parameters are bound.
            var names = new Dictionary <string, int>(n, StringOrdinalComparer.Instance);

            foreach (var typeParameter in typeParameters)
            {
                var name = typeParameter.Name;
                if (!names.ContainsKey(name))
                {
                    names.Add(name, names.Count);
                }
            }

            // An array of constraint clauses, one for each type parameter, indexed by ordinal.
            var results = ArrayBuilder <TypeParameterConstraintClause?> .GetInstance(n, fillWithValue : null);

            var syntaxNodes = ArrayBuilder <ArrayBuilder <TypeConstraintSyntax>?> .GetInstance(n, fillWithValue : null);

            // Bind each clause and add to the results.
            foreach (var clause in clauses)
            {
                var name = clause.Name.Identifier.ValueText;
                RoslynDebug.Assert(name is object);
                int ordinal;
                if (names.TryGetValue(name, out ordinal))
                {
                    Debug.Assert(ordinal >= 0);
                    Debug.Assert(ordinal < n);

                    (TypeParameterConstraintClause constraintClause, ArrayBuilder <TypeConstraintSyntax>?typeConstraintNodes) = this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, diagnostics);
                    if (results[ordinal] == null)
                    {
                        results[ordinal]     = constraintClause;
                        syntaxNodes[ordinal] = typeConstraintNodes;
                    }
                    else
                    {
                        // "A constraint clause has already been specified for type parameter '{0}'. ..."
                        diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name);
                        typeConstraintNodes?.Free();
                    }
                }
                else
                {
                    // Unrecognized type parameter. Don't bother binding the constraints
                    // (the ": I<U>" in "where U : I<U>") since that will lead to additional
                    // errors ("type or namespace 'U' could not be found") if the type
                    // parameter is referenced in the constraints.

                    // "'{1}' does not define type parameter '{0}'"
                    diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom());
                }
            }

            // Add default values for type parameters without constraint clauses.
            for (int i = 0; i < n; i++)
            {
                if (results[i] == null)
                {
                    results[i] = GetDefaultTypeParameterConstraintClause(typeParameterList.Parameters[i], isForOverride);
                }
            }

            TypeParameterConstraintClause.AdjustConstraintTypes(containingSymbol, typeParameters, results, ref isValueTypeOverride);

            RemoveInvalidConstraints(typeParameters, results !, syntaxNodes, diagnostics);

            foreach (var typeConstraintsSyntaxes in syntaxNodes)
            {
                typeConstraintsSyntaxes?.Free();
            }

            syntaxNodes.Free();

            return(results.ToImmutableAndFree() !);
        }
        /// <remarks>
        /// NOTE: Keep this method in sync with AnalyzeImplicitUserDefinedConversion.
        /// </remarks>
        protected UserDefinedConversionResult AnalyzeImplicitUserDefinedConversionForV6SwitchGoverningType(TypeSymbol source, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // SPEC:    The governing type of a switch statement is established by the switch expression.
            // SPEC:    1) If the type of the switch expression is sbyte, byte, short, ushort, int, uint,
            // SPEC:       long, ulong, bool, char, string, or an enum-type, or if it is the nullable type
            // SPEC:       corresponding to one of these types, then that is the governing type of the switch statement.
            // SPEC:    2) Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the
            // SPEC:       type of the switch expression to one of the following possible governing types:
            // SPEC:       sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or, a nullable type
            // SPEC:       corresponding to one of those types

            // NOTE:    This method implements part (2) above, it should be called only if (1) is false for source type.
            Debug.Assert((object)source != null);
            Debug.Assert(!source.IsValidV6SwitchGoverningType());

            // NOTE: For (2) we use an approach similar to native compiler's approach, but call into the common code for analyzing user defined implicit conversions.
            // NOTE:    (a) Compute the set of types D from which user-defined conversion operators should be considered by considering only the source type.
            // NOTE:    (b) Instead of computing applicable user defined implicit conversions U from the source type to a specific target type,
            // NOTE:        we compute these from the source type to ANY target type.
            // NOTE:    (c) From the conversions in U, select the most specific of them that targets a valid switch governing type

            // SPEC VIOLATION: Because we use the same strategy for computing the most specific conversion, as the Dev10 compiler did (in fact
            // SPEC VIOLATION: we share the code), we inherit any spec deviances in that analysis. Specifically, the analysis only considers
            // SPEC VIOLATION: which conversion has the least amount of lifting, where a conversion may be considered to be in unlifted form,
            // SPEC VIOLATION: half-lifted form (only the argument type or return type is lifted) or fully lifted form. The most specific computation
            // SPEC VIOLATION: looks for a unique conversion that is least lifted. The spec, on the other hand, requires that the conversion
            // SPEC VIOLATION: be *unique*, not merely most use the least amount of lifting among the applicable conversions.

            // SPEC VIOLATION: This introduces a SPEC VIOLATION for the following tests in the native compiler:

            // NOTE:    // See test SwitchTests.CS0166_AggregateTypeWithMultipleImplicitConversions_07
            // NOTE:    struct Conv
            // NOTE:    {
            // NOTE:        public static implicit operator int (Conv C) { return 1; }
            // NOTE:        public static implicit operator int (Conv? C2) { return 0; }
            // NOTE:        public static int Main()
            // NOTE:        {
            // NOTE:            Conv? D = new Conv();
            // NOTE:            switch(D)
            // NOTE:            {   ...

            // SPEC VIOLATION: Native compiler allows the above code to compile
            // SPEC VIOLATION: even though there are two user-defined implicit conversions:
            // SPEC VIOLATION: 1) To int type (applicable in normal form): public static implicit operator int (Conv? C2)
            // SPEC VIOLATION: 2) To int? type (applicable in lifted form): public static implicit operator int (Conv C)

            // NOTE:    // See also test SwitchTests.TODO
            // NOTE:    struct Conv
            // NOTE:    {
            // NOTE:        public static implicit operator int? (Conv C) { return 1; }
            // NOTE:        public static implicit operator string (Conv? C2) { return 0; }
            // NOTE:        public static int Main()
            // NOTE:        {
            // NOTE:            Conv? D = new Conv();
            // NOTE:            switch(D)
            // NOTE:            {   ...

            // SPEC VIOLATION: Native compiler allows the above code to compile too
            // SPEC VIOLATION: even though there are two user-defined implicit conversions:
            // SPEC VIOLATION: 1) To string type (applicable in normal form): public static implicit operator string (Conv? C2)
            // SPEC VIOLATION: 2) To int? type (applicable in half-lifted form): public static implicit operator int? (Conv C)

            // SPEC VIOLATION: This occurs because the native compiler compares the applicable conversions to find one with the least amount
            // SPEC VIOLATION: of lifting, ignoring whether the return types are the same or not.
            // SPEC VIOLATION: We do the same to maintain compatibility with the native compiler.

            // (a) Compute the set of types D from which user-defined conversion operators should be considered by considering only the source type.
            var d = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            ComputeUserDefinedImplicitConversionTypeSet(source, t: null, d: d, useSiteDiagnostics: ref useSiteDiagnostics);

            // (b) Instead of computing applicable user defined implicit conversions U from the source type to a specific target type,
            //     we compute these from the source type to ANY target type. We will filter out those that are valid switch governing
            //     types later.
            var ubuild = ArrayBuilder <UserDefinedConversionAnalysis> .GetInstance();

            ComputeApplicableUserDefinedImplicitConversionSet(null, source, target: null, d: d, u: ubuild, useSiteDiagnostics: ref useSiteDiagnostics, allowAnyTarget: true);
            d.Free();
            ImmutableArray <UserDefinedConversionAnalysis> u = ubuild.ToImmutableAndFree();

            // (c) Find that conversion with the least amount of lifting
            int?best = MostSpecificConversionOperator(conv => conv.ToType.IsValidV6SwitchGoverningType(isTargetTypeOfUserDefinedOp: true), u);

            if (best != null)
            {
                return(UserDefinedConversionResult.Valid(u, best.Value));
            }

            return(UserDefinedConversionResult.NoApplicableOperators(u));
        }
Exemple #55
0
        private (TypeParameterConstraintClause, ArrayBuilder <TypeConstraintSyntax>?) BindTypeParameterConstraints(TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, DiagnosticBag diagnostics)
        {
            var constraints = TypeParameterConstraintKind.None;
            ArrayBuilder <TypeWithAnnotations>? constraintTypes = null;
            ArrayBuilder <TypeConstraintSyntax>?syntaxBuilder   = null;
            SeparatedSyntaxList <TypeParameterConstraintSyntax> constraintsSyntax = constraintClauseSyntax.Constraints;

            Debug.Assert(!InExecutableBinder); // Cannot eagerly report diagnostics handled by LazyMissingNonNullTypesContextDiagnosticInfo
            bool hasTypeLikeConstraint           = false;
            bool reportedOverrideWithConstraints = false;

            for (int i = 0, n = constraintsSyntax.Count; i < n; i++)
            {
                var syntax = constraintsSyntax[i];
                switch (syntax.Kind())
                {
                case SyntaxKind.ClassConstraint:
                    hasTypeLikeConstraint = true;

                    if (i != 0)
                    {
                        if (!reportedOverrideWithConstraints)
                        {
                            reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
                        }

                        if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
                        {
                            continue;
                        }
                    }

                    var         constraintSyntax = (ClassOrStructConstraintSyntax)syntax;
                    SyntaxToken questionToken    = constraintSyntax.QuestionToken;
                    if (questionToken.IsKind(SyntaxKind.QuestionToken))
                    {
                        constraints |= TypeParameterConstraintKind.NullableReferenceType;

                        if (isForOverride)
                        {
                            reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics);
                        }
                        else
                        {
                            LazyMissingNonNullTypesContextDiagnosticInfo.ReportNullableReferenceTypesIfNeeded(AreNullableAnnotationsEnabled(questionToken), questionToken.GetLocation(), diagnostics);
                        }
                    }
                    else if (isForOverride || AreNullableAnnotationsEnabled(constraintSyntax.ClassOrStructKeyword))
                    {
                        constraints |= TypeParameterConstraintKind.NotNullableReferenceType;
                    }
                    else
                    {
                        constraints |= TypeParameterConstraintKind.ReferenceType;
                    }

                    continue;

                case SyntaxKind.StructConstraint:
                    hasTypeLikeConstraint = true;

                    if (i != 0)
                    {
                        if (!reportedOverrideWithConstraints)
                        {
                            reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
                        }

                        if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
                        {
                            continue;
                        }
                    }

                    constraints |= TypeParameterConstraintKind.ValueType;
                    continue;

                case SyntaxKind.ConstructorConstraint:
                    if (isForOverride)
                    {
                        reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics);
                        continue;
                    }

                    if ((constraints & TypeParameterConstraintKind.ValueType) != 0)
                    {
                        diagnostics.Add(ErrorCode.ERR_NewBoundWithVal, syntax.GetFirstToken().GetLocation());
                    }
                    if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0)
                    {
                        diagnostics.Add(ErrorCode.ERR_NewBoundWithUnmanaged, syntax.GetFirstToken().GetLocation());
                    }

                    if (i != n - 1)
                    {
                        diagnostics.Add(ErrorCode.ERR_NewBoundMustBeLast, syntax.GetFirstToken().GetLocation());
                    }

                    constraints |= TypeParameterConstraintKind.Constructor;
                    continue;

                case SyntaxKind.DefaultConstraint:
                    if (!isForOverride)
                    {
                        diagnostics.Add(ErrorCode.ERR_DefaultConstraintOverrideOnly, syntax.GetLocation());
                    }

                    if (i != 0)
                    {
                        if (!reportedOverrideWithConstraints)
                        {
                            reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
                        }

                        if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
                        {
                            continue;
                        }
                    }

                    constraints |= TypeParameterConstraintKind.Default;
                    continue;

                case SyntaxKind.TypeConstraint:
                    if (isForOverride)
                    {
                        reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics);
                    }
                    else
                    {
                        hasTypeLikeConstraint = true;

                        if (constraintTypes == null)
                        {
                            constraintTypes = ArrayBuilder <TypeWithAnnotations> .GetInstance();

                            syntaxBuilder = ArrayBuilder <TypeConstraintSyntax> .GetInstance();
                        }

                        var typeConstraintSyntax = (TypeConstraintSyntax)syntax;
                        var typeSyntax           = typeConstraintSyntax.Type;

                        var type = BindTypeOrConstraintKeyword(typeSyntax, diagnostics, out ConstraintContextualKeyword keyword);

                        switch (keyword)
                        {
                        case ConstraintContextualKeyword.Unmanaged:
                            if (i != 0)
                            {
                                reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics);
                                continue;
                            }

                            // This should produce diagnostics if the types are missing
                            GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType, diagnostics, typeSyntax);
                            GetSpecialType(SpecialType.System_ValueType, diagnostics, typeSyntax);

                            constraints |= TypeParameterConstraintKind.Unmanaged;
                            continue;

                        case ConstraintContextualKeyword.NotNull:
                            if (i != 0)
                            {
                                reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics);
                            }

                            constraints |= TypeParameterConstraintKind.NotNull;
                            continue;

                        case ConstraintContextualKeyword.None:
                            break;

                        default:
                            throw ExceptionUtilities.UnexpectedValue(keyword);
                        }

                        constraintTypes.Add(type);
                        syntaxBuilder !.Add(typeConstraintSyntax);
                    }
                    continue;

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

            if (!isForOverride && !hasTypeLikeConstraint && !AreNullableAnnotationsEnabled(typeParameterSyntax.Identifier))
            {
                constraints |= TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType;
            }

            Debug.Assert(!isForOverride ||
                         (constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType));

            return(TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray <TypeWithAnnotations> .Empty), syntaxBuilder);
Exemple #56
0
        private static ImmutableArray <CodeFix> GetConfigurations(Project project, IEnumerable <Diagnostic> diagnostics, CancellationToken cancellationToken)
        {
            var result = ArrayBuilder <CodeFix> .GetInstance();

            foreach (var diagnostic in diagnostics)
            {
                // First get all the relevant code style options for the diagnostic.
                var codeStyleOptions = ConfigurationUpdater.GetCodeStyleOptionsForDiagnostic(diagnostic, project);
                if (codeStyleOptions.IsEmpty)
                {
                    continue;
                }

                // For each code style option, create a top level code action with nested code actions for every valid option value.
                // For example, if the option value is CodeStyleOption<bool>, we will have two nested actions, one for 'true' setting and one
                // for 'false' setting. If the option value is CodeStyleOption<SomeEnum>, we will have a nested action for each enum field.
                using var _ = ArrayBuilder <CodeAction> .GetInstance(out var nestedActions);

                var optionSet          = project.Solution.Workspace.Options;
                var hasMultipleOptions = codeStyleOptions.Length > 1;
                foreach (var(optionKey, codeStyleOption, editorConfigLocation, perLanguageOption) in codeStyleOptions.OrderBy(t => t.optionKey.Option.Name))
                {
                    var topLevelAction = GetCodeActionForCodeStyleOption(optionKey, codeStyleOption, editorConfigLocation, diagnostic, perLanguageOption, optionSet, hasMultipleOptions);
                    if (topLevelAction != null)
                    {
                        nestedActions.Add(topLevelAction);
                    }
                }

                if (nestedActions.Count != 0)
                {
                    // Wrap actions by another level if the diagnostic ID has multiple associated code style options to reduce clutter.
                    var resultCodeAction = nestedActions.Count > 1
                        ? new TopLevelConfigureCodeStyleOptionCodeAction(diagnostic, nestedActions.ToImmutable())
                        : nestedActions.Single();

                    result.Add(new CodeFix(project, resultCodeAction, diagnostic));
                }
            }

            return(result.ToImmutableAndFree());

            // Local functions
            TopLevelConfigureCodeStyleOptionCodeAction GetCodeActionForCodeStyleOption(
                OptionKey optionKey,
                ICodeStyleOption codeStyleOption,
                IEditorConfigStorageLocation2 editorConfigLocation,
                Diagnostic diagnostic,
                bool isPerLanguage,
                OptionSet optionSet,
                bool hasMultipleOptions)
            {
                // Add a code action for every valid value of the given code style option.
                // We only support light-bulb configuration of code style options with boolean or enum values.

                using var _ = ArrayBuilder <CodeAction> .GetInstance(out var nestedActions);

                var    severity   = codeStyleOption.Notification.ToEditorConfigString();
                string optionName = null;

                if (codeStyleOption.Value is bool)
                {
                    foreach (var boolValue in s_boolValues)
                    {
                        AddCodeActionWithOptionValue(codeStyleOption, boolValue);
                    }
                }
                else if (codeStyleOption.Value?.GetType() is Type t && t.IsEnum)
                {
                    foreach (var enumValue in Enum.GetValues(t))
                    {
                        AddCodeActionWithOptionValue(codeStyleOption, enumValue);
                    }
                }

                if (nestedActions.Count > 0)
                {
                    // If this is not a unique code style option for the diagnostic, use the optionName as the code action title.
                    // In that case, we will already have a containing top level action for the diagnostic.
                    // Otherwise, use the diagnostic information in the title.
                    return(hasMultipleOptions
                        ? new TopLevelConfigureCodeStyleOptionCodeAction(optionName, nestedActions.ToImmutable())
                        : new TopLevelConfigureCodeStyleOptionCodeAction(diagnostic, nestedActions.ToImmutable()));
                }

                return(null);

                // Local functions
                void AddCodeActionWithOptionValue(ICodeStyleOption codeStyleOption, object newValue)
                {
                    // Create a new code style option value with the newValue
                    var configuredCodeStyleOption = codeStyleOption.WithValue(newValue);

                    // Try to get the parsed editorconfig string representation of the new code style option value
                    if (ConfigurationUpdater.TryGetEditorConfigStringParts(configuredCodeStyleOption, editorConfigLocation, optionSet, out var parts))
                    {
                        // We expect all code style values for same code style option to have the same editorconfig option name.
                        Debug.Assert(optionName == null || optionName == parts.optionName);
                        optionName ??= parts.optionName;

                        // Add code action to configure the optionValue.
                        nestedActions.Add(
                            new SolutionChangeAction(
                                parts.optionValue,
                                solution => ConfigurationUpdater.ConfigureCodeStyleOptionAsync(parts.optionName, parts.optionValue, diagnostic, isPerLanguage, project, cancellationToken)));
                    }
                }
            }
        }
Exemple #57
0
        private ImmutableArray <ParameterSymbol> MakeParameters(
            CSharpCompilation compilation,
            UnboundLambda unboundLambda,
            ImmutableArray <TypeWithAnnotations> parameterTypes,
            ImmutableArray <RefKind> parameterRefKinds
            )
        {
            Debug.Assert(parameterTypes.Length == parameterRefKinds.Length);

            if (!unboundLambda.HasSignature || unboundLambda.ParameterCount == 0)
            {
                // The parameters may be omitted in source, but they are still present on the symbol.
                return(parameterTypes.SelectAsArray(
                           (type, ordinal, arg) =>
                           SynthesizedParameterSymbol.Create(
                               arg.owner,
                               type,
                               ordinal,
                               arg.refKinds[ordinal],
                               GeneratedNames.LambdaCopyParameterName(ordinal)
                               ), // Make sure nothing binds to this.
                           (owner: this, refKinds: parameterRefKinds)
                           ));
            }

            var builder = ArrayBuilder <ParameterSymbol> .GetInstance(unboundLambda.ParameterCount);

            var hasExplicitlyTypedParameterList = unboundLambda.HasExplicitlyTypedParameterList;
            var numDelegateParameters           = parameterTypes.Length;

            for (int p = 0; p < unboundLambda.ParameterCount; ++p)
            {
                // If there are no types given in the lambda then used the delegate type.
                // If the lambda is typed then the types probably match the delegate types;
                // if they do not, use the lambda types for binding. Either way, if we
                // can, then we use the lambda types. (Whatever you do, do not use the names
                // in the delegate parameters; they are not in scope!)

                TypeWithAnnotations type;
                RefKind             refKind;
                if (hasExplicitlyTypedParameterList)
                {
                    type    = unboundLambda.ParameterTypeWithAnnotations(p);
                    refKind = unboundLambda.RefKind(p);
                }
                else if (p < numDelegateParameters)
                {
                    type    = parameterTypes[p];
                    refKind = parameterRefKinds[p];
                }
                else
                {
                    type = TypeWithAnnotations.Create(
                        new ExtendedErrorTypeSymbol(
                            compilation,
                            name: string.Empty,
                            arity: 0,
                            errorInfo: null
                            )
                        );
                    refKind = RefKind.None;
                }

                var name      = unboundLambda.ParameterName(p);
                var location  = unboundLambda.ParameterLocation(p);
                var locations =
                    location == null
                        ? ImmutableArray <Location> .Empty
                        : ImmutableArray.Create <Location>(location);

                var parameter = new SourceSimpleParameterSymbol(
                    owner: this,
                    type,
                    ordinal: p,
                    refKind,
                    name,
                    unboundLambda.ParameterIsDiscard(p),
                    locations
                    );

                builder.Add(parameter);
            }

            var result = builder.ToImmutableAndFree();

            return(result);
        }
        internal sealed override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder <SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(compilationState, ref attributes);

            if (_debuggerHidden)
            {
                var compilation = this.DeclaringCompilation;
                AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor));
            }

            if (this.ReturnType.ContainsDynamic())
            {
                var compilation = this.DeclaringCompilation;
                AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(this.ReturnType, this.ReturnTypeCustomModifiers.Length));
            }
        }
            private void AddDebuggerDisplayAttributeArguments(INamedTypeSymbol namedTypeSymbol, ArrayBuilder <string> builder)
            {
                AddDebuggerDisplayAttributeArgumentsCore(namedTypeSymbol, builder);

                foreach (var member in namedTypeSymbol.GetMembers())
                {
                    switch (member)
                    {
                    case INamedTypeSymbol nestedType:
                        AddDebuggerDisplayAttributeArguments(nestedType, builder);
                        break;

                    case IPropertySymbol _:
                    case IFieldSymbol _:
                        AddDebuggerDisplayAttributeArgumentsCore(member, builder);
                        break;
                    }
                }
            }
        /// <remarks>
        /// NOTE: Keep this method in sync with <see cref="AnalyzeImplicitUserDefinedConversionForV6SwitchGoverningType"/>.
        /// </remarks>
        private UserDefinedConversionResult AnalyzeImplicitUserDefinedConversions(
            BoundExpression sourceExpression,
            TypeSymbol source,
            TypeSymbol target,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(sourceExpression != null || (object)source != null);
            Debug.Assert((object)target != null);

            // User-defined conversions that involve generics can be quite strange. There
            // are two basic problems: first, that generic user-defined conversions can be
            // "shadowed" by built-in conversions, and second, that generic user-defined
            // conversions can make conversions that would never have been legal user-defined
            // conversions if declared non-generically. I call this latter kind of conversion
            // a "suspicious" conversion.
            //
            // The shadowed conversions are easily dealt with:
            //
            // SPEC: If a predefined implicit conversion exists from a type S to type T,
            // SPEC: all user-defined conversions, implicit or explicit, are ignored.
            // SPEC: If a predefined explicit conversion exists from a type S to type T,
            // SPEC: any user-defined explicit conversion from S to T are ignored.
            //
            // The rule above can come into play in cases like:
            //
            // sealed class C<T> { public static implicit operator T(C<T> c) { ... } }
            // C<object> c = whatever;
            // object o = c;
            //
            // The built-in implicit conversion from C<object> to object must shadow
            // the user-defined implicit conversion.
            //
            // The caller of this method checks for user-defined conversions *after*
            // predefined implicit conversions, so we already know that if we got here,
            // there was no predefined implicit conversion.
            //
            // Note that a user-defined *implicit* conversion may win over a built-in
            // *explicit* conversion by the rule given above. That is, if we created
            // an implicit conversion from T to C<T>, then the user-defined implicit
            // conversion from object to C<object> could be valid, even though that
            // would be "replacing" a built-in explicit conversion with a user-defined
            // implicit conversion. This is one of the "suspicious" conversions,
            // as it would not be legal to declare a user-defined conversion from
            // object in a non-generic type.
            //
            // The way the native compiler handles suspicious conversions involving
            // interfaces is neither sensible nor in line with the rules in the
            // specification. It is not clear at this time whether we should be exactly
            // matching the native compiler, the specification, or neither, in Roslyn.

            // Spec (6.4.4 User-defined implicit conversions)
            //   A user-defined implicit conversion from an expression E to type T is processed as follows:

            // SPEC: Find the set of types D from which user-defined conversion operators...
            var d = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            ComputeUserDefinedImplicitConversionTypeSet(source, target, d, ref useSiteDiagnostics);

            // SPEC: Find the set of applicable user-defined and lifted conversion operators, U...
            var ubuild = ArrayBuilder <UserDefinedConversionAnalysis> .GetInstance();

            ComputeApplicableUserDefinedImplicitConversionSet(sourceExpression, source, target, d, ubuild, ref useSiteDiagnostics);
            d.Free();
            ImmutableArray <UserDefinedConversionAnalysis> u = ubuild.ToImmutableAndFree();

            // SPEC: If U is empty, the conversion is undefined and a compile-time error occurs.
            if (u.Length == 0)
            {
                return(UserDefinedConversionResult.NoApplicableOperators(u));
            }

            // SPEC: Find the most specific source type SX of the operators in U...
            TypeSymbol sx = MostSpecificSourceTypeForImplicitUserDefinedConversion(u, source, ref useSiteDiagnostics);

            if ((object)sx == null)
            {
                return(UserDefinedConversionResult.NoBestSourceType(u));
            }

            // SPEC: Find the most specific target type TX of the operators in U...
            TypeSymbol tx = MostSpecificTargetTypeForImplicitUserDefinedConversion(u, target, ref useSiteDiagnostics);

            if ((object)tx == null)
            {
                return(UserDefinedConversionResult.NoBestTargetType(u));
            }

            int?best = MostSpecificConversionOperator(sx, tx, u);

            if (best == null)
            {
                return(UserDefinedConversionResult.Ambiguous(u));
            }

            return(UserDefinedConversionResult.Valid(u, best.Value));
        }