internal SourceMemberFieldSymbol( SourceMemberContainerTypeSymbol containingType, VariableDeclaratorSyntax declarator, DeclarationModifiers modifiers, bool modifierErrors, DiagnosticBag diagnostics) : base(containingType, declarator.Identifier.ValueText, declarator.GetReference(), declarator.Identifier.GetLocation()) { this.modifiers = modifiers; this.CheckAccessibility(diagnostics); var location = Location; if (modifierErrors) { // skip the following checks } else if (containingType.IsSealed && (DeclaredAccessibility == Accessibility.Protected || DeclaredAccessibility == Accessibility.ProtectedOrInternal)) { diagnostics.Add(AccessCheck.GetProtectedMemberInSealedTypeError(containingType), location, this); } else if (IsVolatile && IsReadOnly) { diagnostics.Add(ErrorCode.ERR_VolatileAndReadonly, location, this); } else if (containingType.IsStatic && !IsStatic) { diagnostics.Add(ErrorCode.ERR_InstanceMemberInStaticClass, location, this); } // TODO: Consider checking presence of core type System.Runtime.CompilerServices.IsVolatile // if there is a volatile modifier. Perhaps an appropriate error should be reported if the // type isn’t available. }
internal static DeclarationModifiers CheckModifiers( DeclarationModifiers modifiers, DeclarationModifiers allowedModifiers, Location errorLocation, DiagnosticBag diagnostics, out bool modifierErrors) { modifierErrors = false; DeclarationModifiers errorModifiers = modifiers & ~allowedModifiers; DeclarationModifiers result = modifiers & allowedModifiers; while (errorModifiers != DeclarationModifiers.None) { DeclarationModifiers oneError = errorModifiers & ~(errorModifiers - 1); Debug.Assert(oneError != DeclarationModifiers.None); errorModifiers = errorModifiers & ~oneError; switch (oneError) { case DeclarationModifiers.Partial: diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyMethods, errorLocation); break; default: diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, ConvertSingleModifierToSyntaxText(oneError)); break; } modifierErrors = true; } bool isMethod = (allowedModifiers & (DeclarationModifiers.Partial | DeclarationModifiers.Virtual)) == (DeclarationModifiers.Partial | DeclarationModifiers.Virtual); if (isMethod && ((result & (DeclarationModifiers.Partial | DeclarationModifiers.Private)) == (DeclarationModifiers.Partial | DeclarationModifiers.Private))) { diagnostics.Add(ErrorCode.ERR_PartialMethodInvalidModifier, errorLocation); } return result; }
protected override void MethodChecks(DiagnosticBag diagnostics) { var syntax = (ConstructorDeclarationSyntax)syntaxReference.GetSyntax(); var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntaxReference.SyntaxTree); // NOTE: if we asked for the binder for the body of the constructor, we'd risk a stack overflow because // we might still be constructing the member list of the containing type. However, getting the binder // for the parameters should be safe. var bodyBinder = binderFactory.GetBinder(syntax.ParameterList).WithContainingMemberOrLambda(this); SyntaxToken arglistToken; this.lazyParameters = ParameterHelpers.MakeParameters(bodyBinder, this, syntax.ParameterList, true, out arglistToken, diagnostics); this.lazyIsVararg = (arglistToken.CSharpKind() == SyntaxKind.ArgListKeyword); this.lazyReturnType = bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax); if (MethodKind == MethodKind.StaticConstructor && (lazyParameters.Length != 0)) { diagnostics.Add(ErrorCode.ERR_StaticConstParam, Locations[0], this); } this.CheckEffectiveAccessibility(lazyReturnType, lazyParameters, diagnostics); if (this.lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || this.lazyParameters.Length > 0 && this.lazyParameters[this.lazyParameters.Length - 1].IsParams)) { diagnostics.Add(ErrorCode.ERR_BadVarargs, Locations[0]); } }
private SourceConstructorSymbol( SourceMemberContainerTypeSymbol containingType, Location location, ConstructorDeclarationSyntax syntax, MethodKind methodKind, DiagnosticBag diagnostics) : base(containingType, syntax.GetReference(), syntax.Body.GetReferenceOrNull(), ImmutableArray.Create(location)) { bool modifierErrors; var declarationModifiers = this.MakeModifiers(syntax.Modifiers, methodKind, location, diagnostics, out modifierErrors); this.flags = MakeFlags(methodKind, declarationModifiers, returnsVoid: true, isExtensionMethod: false); var bodyOpt = syntax.Body; if (bodyOpt != null) { if (IsExtern) { diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this); } } var info = ModifierUtils.CheckAccessibility(this.DeclarationModifiers); if (info != null) { diagnostics.Add(info, location); } if (!modifierErrors) { this.CheckModifiers(methodKind, location, diagnostics); } }
private void TypeChecks(TypeSymbol type, BaseFieldDeclarationSyntax fieldSyntax, VariableDeclaratorSyntax declarator, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.Location, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, fieldSyntax.Declaration.Type.Location); } else if (type.IsRestrictedType()) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, fieldSyntax.Declaration.Type.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in fieldSyntax.Modifiers) { if (modifier.CSharpKind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.CSharpKind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else { if (ContainingType.TypeKind == TypeKind.Struct && !IsStatic && !IsConst) { var initializerOpt = declarator.Initializer; if (initializerOpt != null) { // '{0}': cannot have instance field initializers in structs diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, this.Location, this); } } if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.Location, this, type); } } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.Location, this, type); } diagnostics.Add(this.Location, useSiteDiagnostics); }
public void DiagnosticBag() { DiagnosticBag bag1 = new DiagnosticBag(); bag1.Add(CreateDiagnostic(4)); bag1.Add(CreateDiagnostic(7)); Assert.False(bag1.IsEmpty); Assert.Equal(2, bag1.Count()); Assert.NotNull(bag1.ToString()); bool found4 = false, found7 = false; foreach (Diagnostic d in bag1) { if (d.Code == 4) { Assert.False(found4); found4 = true; } else if (d.Code == 7) { Assert.False(found7); found7 = true; } else Assert.True(false); } DiagnosticBag bag2 = new DiagnosticBag(); bag1.Add(bag2); Assert.False(bag1.IsEmpty); Assert.Equal(2, bag1.Count()); found4 = false; found7 = false; foreach (Diagnostic d in bag1) { if (d.Code == 4) { Assert.False(found4); found4 = true; } else if (d.Code == 7) { Assert.False(found7); found7 = true; } else Assert.True(false); } DiagnosticBag bag3 = new DiagnosticBag(); bag3.Add(CreateDiagnostic(3)); bag3.Add(CreateDiagnostic(2)); bag3.Add(CreateDiagnostic(1)); bag1.Add(bag3); Assert.False(bag1.IsEmpty); Assert.Equal(5, bag1.Count()); }
/// <summary> /// This is a clone of the Dev10 logic for reporting query errors. /// </summary> internal void ReportQueryLookupFailed( CSharpSyntaxNode queryClause, BoundExpression instanceArgument, string name, ImmutableArray<Symbol> symbols, DiagnosticBag diagnostics) { FromClauseSyntax fromClause = null; for (CSharpSyntaxNode node = queryClause; ; node = node.Parent) { var e = node as QueryExpressionSyntax; if (e != null) { fromClause = e.FromClause; break; } } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (instanceArgument.Type.IsDynamic()) { // CS1979: Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed diagnostics.Add( new DiagnosticInfoWithSymbols(ErrorCode.ERR_BadDynamicQuery, SpecializedCollections.EmptyObjects, symbols), new SourceLocation(queryClause)); } else if (ImplementsStandardQueryInterface(instanceArgument.Type, name, ref useSiteDiagnostics)) { // Could not find an implementation of the query pattern for source type '{0}'. '{1}' not found. Are you missing a reference to 'System.Core.dll' or a using directive for 'System.Linq'? diagnostics.Add(new DiagnosticInfoWithSymbols( ErrorCode.ERR_QueryNoProviderStandard, new object[] { instanceArgument.Type, name }, symbols), new SourceLocation(fromClause != null ? fromClause.Expression : queryClause)); } else if (fromClause != null && fromClause.Type == null && HasCastToQueryProvider(instanceArgument.Type, ref useSiteDiagnostics)) { // Could not find an implementation of the query pattern for source type '{0}'. '{1}' not found. Consider explicitly specifying the type of the range variable '{2}'. diagnostics.Add(new DiagnosticInfoWithSymbols( ErrorCode.ERR_QueryNoProviderCastable, new object[] { instanceArgument.Type, name, fromClause.Identifier.ValueText }, symbols), new SourceLocation(fromClause.Expression)); } else { // Could not find an implementation of the query pattern for source type '{0}'. '{1}' not found. diagnostics.Add(new DiagnosticInfoWithSymbols( ErrorCode.ERR_QueryNoProvider, new object[] { instanceArgument.Type, name }, symbols), new SourceLocation(fromClause != null ? fromClause.Expression : queryClause)); } diagnostics.Add(queryClause, useSiteDiagnostics); }
/// <summary> /// The flow analysis pass. This pass reports required diagnostics for unreachable /// statements and uninitialized variables (through the call to FlowAnalysisWalker.Analyze), /// and inserts a final return statement if the end of a void-returning method is reachable. /// </summary> /// <param name="method">the method to be analyzed</param> /// <param name="block">the method's body</param> /// <param name="diagnostics">the receiver of the reported diagnostics</param> /// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns> public static BoundBlock Rewrite( MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics) { var compilation = method.DeclaringCompilation; if (method.ReturnsVoid || (object)method.IteratorElementType != null || (method.IsAsync && compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) == method.ReturnType)) { if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics)) { // we don't analyze synthesized void methods. var sourceMethod = method as SourceMethodSymbol; block = AppendImplicitReturn(block, method, (object)sourceMethod != null ? sourceMethod.BlockSyntax : null); } } else if (Analyze(compilation, method, block, diagnostics)) { // If the method is a lambda expression being converted to a non-void delegate type // and the end point is reachable then suppress the error here; a special error // will be reported by the lambda binder. Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction); // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return block; }
internal void Add(DiagnosticInfo?info, Location location) { if (info is object) { DiagnosticBag?.Add(info, location); } }
/// <summary> /// Determine the effective base type, effective interface set, and set of type /// parameters (excluding cycles) from the type parameter constraints. Conflicts /// within the constraints and constraint types are returned as diagnostics. /// 'inherited' should be true if the type parameters are from an overridden /// generic method. In those cases, additional constraint checks are applied. /// </summary> public static TypeParameterBounds ResolveBounds( this TypeParameterSymbol typeParameter, AssemblySymbol corLibrary, ConsList<TypeParameterSymbol> inProgress, ImmutableArray<TypeSymbol> constraintTypes, bool inherited, CSharpCompilation currentCompilation, DiagnosticBag diagnostics) { var diagnosticsBuilder = ArrayBuilder<TypeParameterDiagnosticInfo>.GetInstance(); ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; var bounds = typeParameter.ResolveBounds(corLibrary, inProgress, constraintTypes, inherited, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); if (useSiteDiagnosticsBuilder != null) { diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder); } foreach (var pair in diagnosticsBuilder) { diagnostics.Add(new CSDiagnostic(pair.DiagnosticInfo, pair.TypeParameter.Locations[0])); } diagnosticsBuilder.Free(); return bounds; }
// NOTE: Specifically not overriding IsIndirectlyInIterator. internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics) { if (node != null) { diagnostics.Add(ErrorCode.ERR_YieldInAnonMeth, node.YieldKeyword.GetLocation()); } return CreateErrorType(); }
private void AddDelegateMembers( ArrayBuilder<Symbol> symbols, DelegateDeclarationSyntax syntax, BinderFactory binderFactory, DiagnosticBag diagnostics) { var bodyBinder = binderFactory.GetBinder(syntax.ParameterList); // A delegate has the following members: (see CLI spec 13.6) // (1) a method named Invoke with the specified signature var invoke = new DelegateInvokeMethodImplementation(this, syntax, bodyBinder, diagnostics); invoke.CheckMethodVarianceSafety(diagnostics); symbols.Add(invoke); // (2) a constructor with argument types (object, System.IntPtr) symbols.Add(new DelegateConstructor(this, syntax, bodyBinder)); var delegateBinder = new DelegateBinder(bodyBinder, this, invoke); // (3) BeginInvoke symbols.Add(new DelegateBeginInvokeMethod(this, syntax, delegateBinder, diagnostics)); // and (4) EndInvoke methods symbols.Add(new DelegateEndInvokeMethod(this, syntax, delegateBinder, diagnostics)); if (this.DeclaredAccessibility <= Accessibility.Private) { return; } if (!this.IsNoMoreVisibleThan(invoke.ReturnType)) { // Inconsistent accessibility: return type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateReturn, Locations[0], this, invoke.ReturnType); } foreach (var parameter in invoke.Parameters) { if (!parameter.Type.IsAtLeastAsVisibleAs(this)) { // Inconsistent accessibility: parameter type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateParam, Locations[0], this, parameter.Type); } } }
protected SourceEnumConstantSymbol(SourceMemberContainerTypeSymbol containingEnum, EnumMemberDeclarationSyntax syntax, DiagnosticBag diagnostics) : base(containingEnum, syntax.Identifier.ValueText, syntax.GetReference(), syntax.Identifier.GetLocation()) { if (this.Name == WellKnownMemberNames.EnumBackingFieldName) { diagnostics.Add(ErrorCode.ERR_ReservedEnumerator, this.Location, WellKnownMemberNames.EnumBackingFieldName); } }
internal override CSDiagnosticInfo NotFound(Location location, string name, DiagnosticBag diagnostics) { return diagnostics.Add( ReferenceEquals(qualifier, Compilation.GlobalNamespace) ? ErrorCode.ERR_GlobalSingleTypeNameNotFound : qualifier.IsNamespace ? ErrorCode.ERR_DottedTypeNameNotFoundInNS : ErrorCode.ERR_DottedTypeNameNotFoundInAgg, location, name, qualifier.GetFullName()); }
/// <summary> /// The flow analysis pass. This pass reports required diagnostics for unreachable /// statements and uninitialized variables (through the call to FlowAnalysisWalker.Analyze), /// and inserts a final return statement if the end of a void-returning method is reachable. /// </summary> /// <param name="method">the method to be analyzed</param> /// <param name="block">the method's body</param> /// <param name="diagnostics">the receiver of the reported diagnostics</param> /// <param name="hasTrailingExpression">indicates whether this Script had a trailing expression</param> /// <param name="originalBodyNested">the original method body is the last statement in the block</param> /// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns> public static BoundBlock Rewrite( MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics, bool hasTrailingExpression, bool originalBodyNested) { #if DEBUG // We should only see a trailingExpression if we're in a Script initializer. Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer); var initialDiagnosticCount = diagnostics.ToReadOnly().Length; #endif var compilation = method.DeclaringCompilation; if (method.ReturnsVoid || method.IsIterator || (method.IsAsync && compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) == method.ReturnType)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || Analyze(compilation, method, block, diagnostics)) { block = AppendImplicitReturn(block, method, (CSharpSyntaxNode)(method as SourceMethodSymbol)?.BodySyntax, originalBodyNested); } } else if (Analyze(compilation, method, block, diagnostics)) { // If the method is a lambda expression being converted to a non-void delegate type // and the end point is reachable then suppress the error here; a special error // will be reported by the lambda binder. Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction); // Add implicit "return default(T)" if this is a submission that does not have a trailing expression. var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType; if (!hasTrailingExpression && ((object)submissionResultType != null)) { Debug.Assert(submissionResultType.SpecialType != SpecialType.System_Void); var trailingExpression = new BoundDefaultOperator(method.GetNonNullSyntaxNode(), submissionResultType); var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, trailingExpression)); block = new BoundBlock(block.Syntax, ImmutableArray<LocalSymbol>.Empty, newStatements) { WasCompilerGenerated = true }; #if DEBUG // It should not be necessary to repeat analysis after adding this node, because adding a trailing // return in cases where one was missing should never produce different Diagnostics. var flowAnalysisDiagnostics = DiagnosticBag.GetInstance(); Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics)); Debug.Assert(flowAnalysisDiagnostics.ToReadOnly().SequenceEqual(diagnostics.ToReadOnly().Skip(initialDiagnosticCount))); flowAnalysisDiagnostics.Free(); #endif } // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. else if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return block; }
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics) { if (diagnostics != null && _value.IsBad) { diagnostics.Add(ErrorCode.ERR_BadPdbData, Location.None, Name); } return _value; }
protected BoundExpression CreateConversion( BoundExpression source, TypeSymbol destination, DiagnosticBag diagnostics) { HashSet<DiagnosticInfo> useSiteDiagnostics = null; var conversion = Conversions.ClassifyConversionFromExpression(source, destination, ref useSiteDiagnostics); diagnostics.Add(source.Syntax, useSiteDiagnostics); return CreateConversion(source.Syntax, source, conversion, isCast: false, destination: destination, diagnostics: diagnostics); }
/// <returns>True if a diagnostic was reported, or would have been reported if not for /// the suppress flag.</returns> private bool ReportUnsafeIfNotAllowed(Location location, TypeSymbol sizeOfTypeOpt, DiagnosticBag diagnostics) { var diagnosticInfo = GetUnsafeDiagnosticInfo(sizeOfTypeOpt); if (diagnosticInfo == null || this.Flags.Includes(BinderFlags.SuppressUnsafeDiagnostics)) { return false; } diagnostics.Add(new CSDiagnostic(diagnosticInfo, location)); return true; }
/// <summary> /// Traverses the symbol table checking for CLS compliance. /// </summary> /// <param name="compilation">Compilation that owns the symbol table.</param> /// <param name="diagnostics">Will be supplemented with documentation comment diagnostics.</param> /// <param name="cancellationToken">To stop traversing the symbol table early.</param> /// <param name="filterTree">Only report diagnostics from this syntax tree, if non-null.</param> /// <param name="filterSpanWithinTree">If <paramref name="filterTree"/> and <paramref name="filterSpanWithinTree"/> is non-null, report diagnostics within this span in the <paramref name="filterTree"/>.</param> public static void CheckCompliance(CSharpCompilation compilation, DiagnosticBag diagnostics, CancellationToken cancellationToken, SyntaxTree filterTree = null, TextSpan? filterSpanWithinTree = null) { var queue = new ConcurrentQueue<Diagnostic>(); var checker = new ClsComplianceChecker(compilation, filterTree, filterSpanWithinTree, queue, cancellationToken); checker.Visit(compilation.Assembly); foreach (Diagnostic diag in queue) { diagnostics.Add(diag); } }
internal SourceDestructorSymbol( SourceMemberContainerTypeSymbol containingType, DestructorDeclarationSyntax syntax, DiagnosticBag diagnostics) : base(containingType, syntax.GetReference(), syntax.Body?.GetReference() ?? syntax.ExpressionBody?.GetReference() , syntax.Identifier.GetLocation()) { const MethodKind methodKind = MethodKind.Destructor; Location location = this.Locations[0]; bool modifierErrors; var declarationModifiers = MakeModifiers(syntax.Modifiers, location, diagnostics, out modifierErrors); this.MakeFlags(methodKind, declarationModifiers, returnsVoid: true, isExtensionMethod: false); bool hasBlockBody = syntax.Body != null; _isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null; if (hasBlockBody || _isExpressionBodied) { if (IsExtern) { diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this); } } if (!modifierErrors && bodySyntaxReferenceOpt == null && !IsExtern) { diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this); } Debug.Assert(syntax.ParameterList.Parameters.Count == 0); if (containingType.IsStatic) { diagnostics.Add(ErrorCode.ERR_DestructorInStaticClass, location, this); } else if (!containingType.IsReferenceType) { diagnostics.Add(ErrorCode.ERR_OnlyClassesCanContainDestructors, location, this); } }
private SourceConstructorSymbol( SourceMemberContainerTypeSymbol containingType, Location location, ConstructorDeclarationSyntax syntax, MethodKind methodKind, DiagnosticBag diagnostics) : base(containingType, syntax.GetReference(), syntax.Body?.GetReference() ?? syntax.ExpressionBody?.GetReference(), ImmutableArray.Create(location)) { bool modifierErrors; var declarationModifiers = this.MakeModifiers(syntax.Modifiers, methodKind, location, diagnostics, out modifierErrors); this.MakeFlags(methodKind, declarationModifiers, returnsVoid: true, isExtensionMethod: false); bool hasBlockBody = syntax.Body != null; _isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null; if (IsExtern) { if (methodKind == MethodKind.Constructor && syntax.Initializer != null) { diagnostics.Add(ErrorCode.ERR_ExternHasConstructorInitializer, location, this); } if (hasBlockBody || _isExpressionBodied) { diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this); } } var info = ModifierUtils.CheckAccessibility(this.DeclarationModifiers); if (info != null) { diagnostics.Add(info, location); } if (!modifierErrors) { this.CheckModifiers(methodKind, location, diagnostics); } }
// Returns deterministically ordered list of variables that ought to be hoisted. public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics) { var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables); walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct) { // It is possible that the enclosing method only *writes* to the enclosing struct, but in that // case it should be considered captured anyway so that we have a proxy for it to write to. walker.CaptureVariable(method.ThisParameter, node.Syntax); } var variablesToHoist = walker._variablesToHoist; var lazyDisallowedCaptures = walker._lazyDisallowedCaptures; var allVariables = walker.variableBySlot; walker.Free(); if (lazyDisallowedCaptures != null) { foreach (var kvp in lazyDisallowedCaptures) { var variable = kvp.Key; var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type; foreach (CSharpSyntaxNode syntax in kvp.Value) { // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type); } } } if (compilation.Options.OptimizationLevel != OptimizationLevel.Release) { Debug.Assert(variablesToHoist.Count == 0); // In debug build we hoist all locals and parameters: variablesToHoist.AddRange(from v in allVariables where v.Symbol != null && HoistInDebugBuild(v.Symbol) select v.Symbol); } return variablesToHoist; }
private static void ReportErrorOnSpecialMember(Symbol symbol, SpecialMember member, DiagnosticBag diagnostics, ref bool hasError) { if ((object)symbol == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(member); diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, NoLocation.Singleton, ((SpecialType)memberDescriptor.DeclaringTypeId).GetMetadataName(), memberDescriptor.Name); hasError = true; } else { ReportErrorOnSymbol(symbol, diagnostics, ref hasError); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = this.GetNonNullSyntaxNode(); SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this, syntax, compilationState, diagnostics); factory.CurrentMethod = this; ArrayBuilder<BoundStatement> body = ArrayBuilder<BoundStatement>.GetInstance(); // Initialize the payload root for each kind of dynamic analysis instrumentation. // A payload root is an array of arrays of per-method instrumentation payloads. // For each kind of instrumentation: // // payloadRoot = new T[MaximumMethodDefIndex + 1][]; // // where T is the type of the payload at each instrumentation point, and MaximumMethodDefIndex is the // index portion of the greatest method definition token in the compilation. This guarantees that any // method can use the index portion of its own method definition token as an index into the payload array. try { foreach (KeyValuePair<int, InstrumentationPayloadRootField> payloadRoot in ContainingPrivateImplementationDetailsType.GetInstrumentationPayloadRoots()) { int analysisKind = payloadRoot.Key; ArrayTypeSymbol payloadArrayType = (ArrayTypeSymbol)payloadRoot.Value.Type; BoundStatement payloadInitialization = factory.Assignment( factory.InstrumentationPayloadRoot(analysisKind, payloadArrayType), factory.Array(payloadArrayType.ElementType, factory.Binary(BinaryOperatorKind.Addition, factory.SpecialType(SpecialType.System_Int32), factory.MaximumMethodDefIndex(), factory.Literal(1)))); body.Add(payloadInitialization); } // Initialize the module version ID (MVID) field. Dynamic instrumentation requires the MVID of the executing module, and this field makes that accessible. // MVID = Guid.Parse(ModuleVersionIdString); body.Add( factory.Assignment( factory.ModuleVersionId(), factory.StaticCall( WellKnownMember.System_Guid__Parse, factory.ModuleVersionIdString()))); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember missing) { diagnostics.Add(missing.Diagnostic); } BoundStatement returnStatement = factory.Return(); body.Add(returnStatement); factory.CloseMethod(factory.Block(body.ToImmutableAndFree())); }
public override Stream CreateStream(DiagnosticBag diagnostics) { Debug.Assert(_streamToDispose == null); try { return _streamToDispose = _compiler.FileOpen(_filePath, PortableShim.FileMode.Create, PortableShim.FileAccess.ReadWrite, PortableShim.FileShare.None); } catch (Exception e) { var messageProvider = _compiler.MessageProvider; diagnostics.Add(messageProvider.CreateDiagnostic(messageProvider.ERR_CantOpenFileWrite, Location.None, _filePath, e.Message)); return null; } }
private static void ReportErrorOnWellKnownMember(Symbol symbol, WellKnownMember member, DiagnosticBag diagnostics, ref bool hasError) { if ((object)symbol == null) { MemberDescriptor memberDescriptor = WellKnownMembers.GetDescriptor(member); diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, NoLocation.Singleton, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name); hasError = true; } else { ReportErrorOnSymbol(symbol, diagnostics, ref hasError); ReportErrorOnSymbol(symbol.ContainingType, diagnostics, ref hasError); } }
private ImmutableArray<Symbol> BindTypeCref(TypeCrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { NamespaceOrTypeSymbol result = BindNamespaceOrTypeSymbolInCref(syntax.Type); // NOTE: we don't have to worry about the case where a non-error type is constructed // with erroneous type arguments, because only MemberCrefs have type arguments - // all other crefs only have type parameters. if (result.Kind == SymbolKind.ErrorType) { diagnostics.Add(ErrorCode.WRN_BadXMLRef, syntax.Location, syntax.ToFullString()); } // We'll never have more than one type, but it is conceivable that result could // be an ExtendedErrorTypeSymbol with multiple candidates. ambiguityWinner = null; return ImmutableArray.Create<Symbol>(result); }
internal TypeParameterSymbol MakeSymbol(int ordinal, IList<TypeParameterBuilder> builders, DiagnosticBag diagnostics) { var syntaxNode = (TypeParameterSyntax)this.syntaxRef.GetSyntax(); var result = new SourceTypeParameterSymbol( this.owner, syntaxNode.Identifier.ValueText, ordinal, syntaxNode.VarianceKeyword.VarianceKindFromToken(), ToLocations(builders), ToSyntaxRefs(builders)); if (result.Name == result.ContainingSymbol.Name) { diagnostics.Add(ErrorCode.ERR_TypeVariableSameAsParent, result.Locations[0], result.Name); } return result; }
private AsyncRewriter( BoundStatement body, MethodSymbol method, AsyncStateMachine stateMachineClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineClass, compilationState, diagnostics) { try { constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineClass.TypeMap, out this.asyncMethodBuilderMemberCollection); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); constructedSuccessfully = false; } }
internal SynthesizedSubmissionConstructor(NamedTypeSymbol containingType, DiagnosticBag diagnostics) : base(containingType) { Debug.Assert(containingType.TypeKind == TypeKind.Submission); Debug.Assert(diagnostics != null); var compilation = containingType.DeclaringCompilation; var submissionArrayType = compilation.CreateArrayTypeSymbol(compilation.GetSpecialType(SpecialType.System_Object)); var useSiteError = submissionArrayType.GetUseSiteDiagnostic(); if (useSiteError != null) { diagnostics.Add(useSiteError, NoLocation.Singleton); } _parameters = ImmutableArray.Create<ParameterSymbol>( new SynthesizedParameterSymbol(this, submissionArrayType, 0, RefKind.None, "submissionArray")); }
protected void TypeChecks(TypeSymbol type, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.ErrorLocation, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax.Location); } else if (type.IsRestrictedType()) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in ModifiersTokenList) { if (modifier.Kind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.Kind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.ErrorLocation, this, type); } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.ErrorLocation, this, type); } diagnostics.Add(this.ErrorLocation, useSiteDiagnostics); }
internal BoundExpression BindQuery(QueryExpressionSyntax node, DiagnosticBag diagnostics) { var fromClause = node.FromClause; var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, diagnostics); // If the from expression is of the type dynamic we can't infer the types for any lambdas that occur in the query. // Only if there are none we could bind the query but we report an error regardless since such queries are not useful. if (boundFromExpression.HasDynamicType()) { diagnostics.Add(ErrorCode.ERR_BadDynamicQuery, fromClause.Expression.Location); boundFromExpression = BadExpression(fromClause.Expression, boundFromExpression); } else { boundFromExpression = BindToNaturalType(boundFromExpression, diagnostics); } QueryTranslationState state = new QueryTranslationState(); state.fromExpression = MakeMemberAccessValue(boundFromExpression, diagnostics); var x = state.rangeVariable = state.AddRangeVariable(this, fromClause.Identifier, diagnostics); for (int i = node.Body.Clauses.Count - 1; i >= 0; i--) { state.clauses.Push(node.Body.Clauses[i]); } state.selectOrGroup = node.Body.SelectOrGroup; // A from clause that explicitly specifies a range variable type // from T x in e // is translated into // from x in ( e ) . Cast < T > ( ) BoundExpression?cast = null; if (fromClause.Type != null) { var typeRestriction = BindTypeArgument(fromClause.Type, diagnostics); cast = MakeQueryInvocation(fromClause, state.fromExpression, "Cast", fromClause.Type, typeRestriction, diagnostics); state.fromExpression = cast; } state.fromExpression = MakeQueryClause(fromClause, state.fromExpression, x, castInvocation: cast); BoundExpression result = BindQueryInternal1(state, diagnostics); for (QueryContinuationSyntax?continuation = node.Body.Continuation; continuation != null; continuation = continuation.Body.Continuation) { // A query expression with a continuation // from ... into x ... // is translated into // from x in ( from ... ) ... state.Clear(); state.fromExpression = result; x = state.rangeVariable = state.AddRangeVariable(this, continuation.Identifier, diagnostics); Debug.Assert(state.clauses.IsEmpty()); var clauses = continuation.Body.Clauses; for (int i = clauses.Count - 1; i >= 0; i--) { state.clauses.Push(clauses[i]); } state.selectOrGroup = continuation.Body.SelectOrGroup; result = BindQueryInternal1(state, diagnostics); result = MakeQueryClause(continuation.Body, result, x); result = MakeQueryClause(continuation, result, x); } state.Free(); return(MakeQueryClause(node, result)); }
/// <summary> /// Matches all methods that can be overriden (non-static, public or protected, abstract or virtual) /// within this type sub-tree (this type, its base and interfaces) /// with its override. /// Methods without an override are either abstract or a ghost stup has to be synthesized. /// </summary> /// <param name="diagnostics"></param> internal OverrideInfo[] ResolveOverrides(DiagnosticBag diagnostics) { if (_lazyOverrides != null) { // already resolved return(_lazyOverrides); } // inherit abstracts from base type // ignoring System.Object (we don't override its methods from PHP) var overrides = new List <OverrideInfo>(); if (BaseType != null && BaseType.SpecialType != SpecialType.System_Object) { overrides.AddRange(BaseType.ResolveOverrides(diagnostics)); } // collect this type declared methods including synthesized methods var methods = this.GetMembers().OfType <MethodSymbol>(); var methodslookup = methods.Where(OverrideHelper.CanOverride).ToLookup(m => m.RoutineName, StringComparer.OrdinalIgnoreCase); // resolve overrides of inherited members for (int i = 0; i < overrides.Count; i++) { var m = overrides[i]; if (m.HasOverride == false) { // update override info of the inherited member overrides[i] = new OverrideInfo(m.Method, OverrideHelper.ResolveMethodImplementation(m.Method, methodslookup[m.RoutineName])); } else { // clear the interface flag of inherited override info m.ImplementsInterface = false; overrides[i] = m; } } // resolve overrides of interface methods foreach (var iface in Interfaces) { // skip interfaces implemented by base type or other interfaces, // we don't want to add redundant override entries: if ((BaseType != null && BaseType.ImplementsInterface(iface)) || Interfaces.Any(x => x != iface && x.ImplementsInterface(iface))) { // iface is already handled within overrides => skip // note: iface can be ignored in metadata at all actually continue; } var iface_abstracts = iface.ResolveOverrides(diagnostics); foreach (var m in iface_abstracts) { if (BaseType != null && m.Method.ContainingType != iface && BaseType.ImplementsInterface(m.Method.ContainingType)) { // iface {m.Method.ContainingType} already handled within overrides => skip continue; } // ignore interface method that is already implemented: if (overrides.Any(o => OverrideHelper.SignaturesMatch(o.Method, m.Method))) { continue; } // add interface member, // resolve its override overrides.Add(new OverrideInfo(m.Method, this.IsInterface ? null : OverrideHelper.ResolveMethodImplementation(m.Method, this)) { ImplementsInterface = true }); } } // add overrideable routines from this type foreach (var m in methods) { if (m.IsOverrideable()) { overrides.Add(new OverrideInfo(m)); } } // report unresolved abstracts if (!this.IsAbstract && !this.IsInterface && this is SourceTypeSymbol srct) { foreach (var m in overrides) { if (m.IsUnresolvedAbstract) { // Class '{0}' doesn't implement abstract method {1}::{2}() diagnostics.Add(DiagnosticBagExtensions.ParserDiagnostic(srct.ContainingFile.SyntaxTree, srct.Syntax.HeadingSpan, Devsense.PHP.Errors.Errors.AbstractMethodNotImplemented, srct.FullName.ToString(), ((IPhpTypeSymbol)m.Method.ContainingType).FullName.ToString(), m.RoutineName)); } } } // cache & return return(_lazyOverrides = overrides.ToArray()); }
private ConstantValue DecodeDefaultParameterValueAttribute(CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt) { Debug.Assert(!diagnose || diagnosticsOpt != null); if (HasDefaultArgumentSyntax) { // error CS1745: Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueUsedWithAttributes, node.Name.Location); } return(ConstantValue.Bad); } // BREAK: In dev10, DefaultParameterValueAttribute could not be applied to System.Type or array parameters. // When this was attempted, dev10 produced CS1909, ERR_DefaultValueBadParamType. Roslyn takes a different // approach: instead of looking at the parameter type, we look at the argument type. There's nothing wrong // with providing a default value for a System.Type or array parameter, as long as the default parameter // is not a System.Type or an array (i.e. null is fine). Since we are no longer interested in the type of // the parameter, all occurrences of CS1909 have been replaced with CS1910, ERR_DefaultValueBadValueType, // to indicate that the argument type, rather than the parameter type, is the source of the problem. Debug.Assert(attribute.CommonConstructorArguments.Length == 1); // the type of the value is the type of the expression in the attribute: var arg = attribute.CommonConstructorArguments[0]; SpecialType specialType = arg.Kind == TypedConstantKind.Enum ? ((INamedTypeSymbol)arg.Type).EnumUnderlyingType.SpecialType : arg.Type.SpecialType; var compilation = this.DeclaringCompilation; var constantValueDiscriminator = ConstantValue.GetDiscriminator(specialType); HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (constantValueDiscriminator == ConstantValueTypeDiscriminator.Bad) { if (arg.Kind != TypedConstantKind.Array && arg.Value == null) { if (this.Type.IsReferenceType) { constantValueDiscriminator = ConstantValueTypeDiscriminator.Null; } else { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); } return(ConstantValue.Bad); } } else { // error CS1910: Argument of type '{0}' is not applicable for the DefaultParameterValue attribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueBadValueType, node.Name.Location, arg.Type); } return(ConstantValue.Bad); } } else if (!compilation.Conversions.ClassifyConversion((TypeSymbol)arg.Type, this.Type, ref useSiteDiagnostics).Kind.IsImplicitConversion()) { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return(ConstantValue.Bad); } if (diagnose) { diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return(ConstantValue.Create(arg.Value, constantValueDiscriminator)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), token.GetLocation())); }
/// <summary> /// Given a list of viable lookup results (based on the name, arity, and containing symbol), /// attempt to select one. /// </summary> private ImmutableArray <Symbol> ProcessCrefMemberLookupResults( ImmutableArray <Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax typeArgumentListSyntax, BaseCrefParameterListSyntax parameterListSyntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { Debug.Assert(!symbols.IsEmpty); if (parameterListSyntax == null) { return(ProcessParameterlessCrefMemberLookupResults(symbols, arity, memberSyntax, typeArgumentListSyntax, out ambiguityWinner, diagnostics)); } ArrayBuilder <Symbol> candidates = ArrayBuilder <Symbol> .GetInstance(); GetCrefOverloadResolutionCandidates(symbols, arity, typeArgumentListSyntax, candidates); ImmutableArray <ParameterSymbol> parameterSymbols = BindCrefParameters(parameterListSyntax, diagnostics); ImmutableArray <Symbol> results = PerformCrefOverloadResolution(candidates, parameterSymbols, arity, memberSyntax, out ambiguityWinner, diagnostics); candidates.Free(); // NOTE: This diagnostic is just a hint that might help fix a broken cref, so don't do // any work unless there are no viable candidates. if (results.Length == 0) { for (int i = 0; i < parameterSymbols.Length; i++) { if (ContainsNestedTypeOfUnconstructedGenericType(parameterSymbols[i].Type)) { // This warning is new in Roslyn, because our better-defined semantics for // cref lookup disallow some things that were possible in dev12. // // Consider the following code: // // public class C<T> // { // public class Inner { } // // public void M(Inner i) { } // // /// <see cref="M"/> // /// <see cref="C{T}.M"/> // /// <see cref="C{Q}.M"/> // /// <see cref="C{Q}.M(C{Q}.Inner)"/> // /// <see cref="C{Q}.M(Inner)"/> // WRN_UnqualifiedNestedTypeInCref // public void N() { } // } // // Dev12 binds all of the crefs as "M:C`1.M(C{`0}.Inner)". // Roslyn accepts all but the last. The issue is that the context for performing // the lookup is not C<Q>, but C<T>. Consequently, Inner binds to C<T>.Inner and // then overload resolution fails because C<T>.Inner does not match C<Q>.Inner, // the parameter type of C<Q>.M. Since we could not agree that the old behavior // was desirable (other than for backwards compatibility) and since mimicking it // would have been expensive, we settled on introducing a new warning that at // least hints to the user how then can work around the issue (i.e. by qualifying // Inner as C{Q}.Inner). Additional details are available in DevDiv #743425. // // CONSIDER: We could actually put the qualified form in the warning message, // but that would probably just make it more frustrating (i.e. if the compiler // knows exactly what I mean, why do I have to type it). // // NOTE: This is not a great location (whole parameter instead of problematic type), // but it's better than nothing. diagnostics.Add(ErrorCode.WRN_UnqualifiedNestedTypeInCref, parameterListSyntax.Parameters[i].Location); break; } } } return(results); }
public static BoundBlock Rewrite( MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics, bool hasTrailingExpression, bool originalBodyNested) { #if DEBUG // We should only see a trailingExpression if we're in a Script initializer. Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer); var initialDiagnosticCount = diagnostics.ToReadOnly().Length; #endif var compilation = method.DeclaringCompilation; if (method.ReturnsVoid || method.IsIterator || method.IsAsyncReturningTask(compilation)) { // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || Analyze(compilation, method, block, diagnostics)) { block = AppendImplicitReturn(block, method, originalBodyNested); } } else if (Analyze(compilation, method, block, diagnostics)) { // If the method is a lambda expression being converted to a non-void delegate type // and the end point is reachable then suppress the error here; a special error // will be reported by the lambda binder. Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction); // Add implicit "return default(T)" if this is a submission that does not have a trailing expression. var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType; if (!hasTrailingExpression && ((object)submissionResultType != null)) { Debug.Assert(!submissionResultType.IsVoidType()); var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType); var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression)); block = new BoundBlock(block.Syntax, ImmutableArray <LocalSymbol> .Empty, newStatements) { WasCompilerGenerated = true }; #if DEBUG // It should not be necessary to repeat analysis after adding this node, because adding a trailing // return in cases where one was missing should never produce different Diagnostics. IEnumerable <Diagnostic> GetErrorsOnly(IEnumerable <Diagnostic> diags) => diags.Where(d => d.Severity == DiagnosticSeverity.Error); var flowAnalysisDiagnostics = DiagnosticBag.GetInstance(); Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics)); // Ignore warnings since flow analysis reports nullability mismatches. Debug.Assert(GetErrorsOnly(flowAnalysisDiagnostics.ToReadOnly()).SequenceEqual(GetErrorsOnly(diagnostics.ToReadOnly().Skip(initialDiagnosticCount)))); flowAnalysisDiagnostics.Free(); #endif } // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. else if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return(block); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), location)); }
protected override void MethodChecks(DiagnosticBag diagnostics) { var binder = this.DeclaringCompilation. GetBinderFactory(syntaxReference.SyntaxTree).GetBinder(ReturnTypeSyntax); SyntaxToken arglistToken; var signatureBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); this.lazyParameters = ParameterHelpers.MakeParameters( signatureBinder, this, ParameterListSyntax, true, out arglistToken, diagnostics); if (arglistToken.CSharpKind() == SyntaxKind.ArgListKeyword) { // This is a parse-time error in the native compiler; it is a semantic analysis error in Roslyn. // error CS1669: __arglist is not valid in this context diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, new SourceLocation(arglistToken)); // Regardless of whether __arglist appears in the source code, we do not mark // the operator method as being a varargs method. } this.lazyReturnType = signatureBinder.BindType(ReturnTypeSyntax, diagnostics); if (this.lazyReturnType.IsRestrictedType()) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, ReturnTypeSyntax.Location, this.lazyReturnType); } if (this.lazyReturnType.IsStatic) { // '{0}': static types cannot be used as return types diagnostics.Add(ErrorCode.ERR_ReturnTypeIsStaticClass, ReturnTypeSyntax.Location, this.lazyReturnType); } this.flags |= MakeFlags( MethodKind, DeclarationModifiers, this.lazyReturnType.SpecialType == SpecialType.System_Void, IsExtensionMethod); // If we have an operator in an interface or static class then we already // have reported that fact as an error. No need to cascade the error further. if (this.ContainingType.IsInterfaceType() || this.ContainingType.IsStatic) { return; } // SPEC: All types referenced in an operator declaration must be at least as accessible // SPEC: as the operator itself. CheckEffectiveAccessibility(lazyReturnType, lazyParameters, diagnostics); CheckValueParameters(diagnostics); CheckOperatorSignatures(diagnostics); }
internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, SyntaxNode syntax) { diagnostics.Add(new CSDiagnostic(info, syntax.Location)); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { ImmutableArray <LocalSymbol> declaredLocalsArray; var body = _generateMethodBody(this, diagnostics, out declaredLocalsArray, out _lazyResultProperties); var compilation = compilationState.Compilation; _lazyReturnType = TypeWithAnnotations.Create(CalculateReturnType(compilation, body)); // Can't do this until the return type has been computed. TypeParameterChecker.Check(this, _allTypeParameters); if (diagnostics.HasAnyErrors()) { return; } DiagnosticsPass.IssueDiagnostics(compilation, body, diagnostics, this); if (diagnostics.HasAnyErrors()) { return; } // Check for use-site diagnostics (e.g. missing types in the signature). DiagnosticInfo useSiteDiagnosticInfo = null; this.CalculateUseSiteDiagnostic(ref useSiteDiagnosticInfo); if (useSiteDiagnosticInfo != null && useSiteDiagnosticInfo.Severity == DiagnosticSeverity.Error) { diagnostics.Add(useSiteDiagnosticInfo, this.Locations[0]); return; } try { var declaredLocals = PooledHashSet <LocalSymbol> .GetInstance(); try { // Rewrite local declaration statement. body = (BoundStatement)LocalDeclarationRewriter.Rewrite( compilation, _container, declaredLocals, body, declaredLocalsArray, diagnostics); // Verify local declaration names. foreach (var local in declaredLocals) { Debug.Assert(local.Locations.Length > 0); var name = local.Name; if (name.StartsWith("$", StringComparison.Ordinal)) { diagnostics.Add(ErrorCode.ERR_UnexpectedCharacter, local.Locations[0], name[0]); return; } } // Rewrite references to placeholder "locals". body = (BoundStatement)PlaceholderLocalRewriter.Rewrite(compilation, _container, declaredLocals, body, diagnostics); if (diagnostics.HasAnyErrors()) { return; } } finally { declaredLocals.Free(); } var syntax = body.Syntax; var statementsBuilder = ArrayBuilder <BoundStatement> .GetInstance(); statementsBuilder.Add(body); // Insert an implicit return statement if necessary. if (body.Kind != BoundKind.ReturnStatement) { statementsBuilder.Add(new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null)); } var localsSet = PooledHashSet <LocalSymbol> .GetInstance(); try { var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.LocalsForBinding) { Debug.Assert(!localsSet.Contains(local)); localsBuilder.Add(local); localsSet.Add(local); } foreach (var local in this.Locals) { if (localsSet.Add(local)) { localsBuilder.Add(local); } } body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true }; Debug.Assert(!diagnostics.HasAnyErrors()); Debug.Assert(!body.HasErrors); bool sawLambdas; bool sawLocalFunctions; bool sawAwaitInExceptionHandler; ImmutableArray <SourceSpan> dynamicAnalysisSpans = ImmutableArray <SourceSpan> .Empty; body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, previousSubmissionFields: null, allowOmissionOfConditionalCalls: false, instrumentForDynamicAnalysis: false, debugDocumentProvider: null, dynamicAnalysisSpans: ref dynamicAnalysisSpans, diagnostics: diagnostics, sawLambdas: out sawLambdas, sawLocalFunctions: out sawLocalFunctions, sawAwaitInExceptionHandler: out sawAwaitInExceptionHandler); Debug.Assert(!sawAwaitInExceptionHandler); Debug.Assert(dynamicAnalysisSpans.Length == 0); if (body.HasErrors) { return; } // Variables may have been captured by lambdas in the original method // or in the expression, and we need to preserve the existing values of // those variables in the expression. This requires rewriting the variables // in the expression based on the closure classes from both the original // method and the expression, and generating a preamble that copies // values into the expression closure classes. // // Consider the original method: // static void M() // { // int x, y, z; // ... // F(() => x + y); // } // and the expression in the EE: "F(() => x + z)". // // The expression is first rewritten using the closure class and local <1> // from the original method: F(() => <1>.x + z) // Then lambda rewriting introduces a new closure class that includes // the locals <1> and z, and a corresponding local <2>: F(() => <2>.<1>.x + <2>.z) // And a preamble is added to initialize the fields of <2>: // <2> = new <>c__DisplayClass0(); // <2>.<1> = <1>; // <2>.z = z; // Rewrite "this" and "base" references to parameter in this method. // Rewrite variables within body to reference existing display classes. body = (BoundStatement)CapturedVariableRewriter.Rewrite( this.GenerateThisReference, compilation.Conversions, _displayClassVariables, body, diagnostics); if (body.HasErrors) { Debug.Assert(false, "Please add a test case capturing whatever caused this assert."); return; } if (diagnostics.HasAnyErrors()) { return; } if (sawLambdas || sawLocalFunctions) { var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); body = LambdaRewriter.Rewrite( loweredBody: body, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, substitutedSourceMethod: this.SubstitutedSourceMethod.OriginalDefinition, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, compilationState: compilationState, diagnostics: diagnostics, assignLocals: localsSet); // we don't need this information: closureDebugInfoBuilder.Free(); lambdaDebugInfoBuilder.Free(); } } finally { localsSet.Free(); } // Insert locals from the original method, // followed by any new locals. var block = (BoundBlock)body; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.Locals) { Debug.Assert(!(local is EELocalSymbol) || (((EELocalSymbol)local).Ordinal == localBuilder.Count)); localBuilder.Add(local); } foreach (var local in block.Locals) { if (local is EELocalSymbol oldLocal) { Debug.Assert(localBuilder[oldLocal.Ordinal] == oldLocal); continue; } localBuilder.Add(local); } body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); } catch (BoundTreeVisitor.CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, Location location) { diagnostics.Add(new CSDiagnostic(info, location)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), syntax.Location)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), syntax.Location)); }
private void CheckUserDefinedConversionSignature(DiagnosticBag diagnostics) { if (this.ReturnsVoid) { // CS0590: User-defined operators cannot return void diagnostics.Add(ErrorCode.ERR_OperatorCantReturnVoid, this.Locations[0]); } // SPEC: For a given source type S and target type T, if S or T are // SPEC: nullable types let S0 and T0 refer to their underlying types, // SPEC: otherise, S0 and T0 are equal to S and T, respectively. var source = this.ParameterTypes[0]; var target = this.ReturnType; var source0 = source.StrippedType(); var target0 = target.StrippedType(); // SPEC: A class or struct is permitted to declare a conversion from S to T // SPEC: only if all the following are true: // SPEC: Neither S0 nor T0 is an interface type. if (source0.IsInterfaceType() || target0.IsInterfaceType()) { // CS0552: '{0}': user-defined conversions to or from an interface are not allowed diagnostics.Add(ErrorCode.ERR_ConversionWithInterface, this.Locations[0], this); return; } // SPEC: Either S0 or T0 is the class or struct type in which the operator // SPEC: declaration takes place. if (source0 != this.ContainingType && target0 != this.ContainingType && // allow conversion between T and Nullable<T> in declaration of Nullable<T> source != this.ContainingType && target != this.ContainingType) { // CS0556: User-defined conversion must convert to or from the enclosing type diagnostics.Add(ErrorCode.ERR_ConversionNotInvolvingContainedType, this.Locations[0]); return; } // SPEC: * S0 and T0 are different types: if ((ContainingType.SpecialType == SpecialType.System_Nullable_T) ? source == target : source0 == target0) { // CS0555: User-defined operator cannot take an object of the enclosing type // and convert to an object of the enclosing type diagnostics.Add(ErrorCode.ERR_IdentityConversion, this.Locations[0]); return; } // Those are the easy ones. Now we come to: // SPEC: // Exluding user-defined conversions, a conversion does not exist from // S to T or T to S. For the purposes of these rules, any type parameters // associated with S or T are considered to be unique types that have // no inheritance relationship with other types, and any constraints on // those type parameters are ignored. // A counter-intuative consequence of this rule is that: // // class X<U> where U : X<U> // { // public implicit operator X<U>(U u) { return u; } // } // // is *legal*, even though there is *already* an implicit conversion // from U to X<U> because U is constrained to have such a conversion. // // In discussing the implications of this rule, let's call the // containing type (which may be a class or struct) "C". S and T // are the source and target types. // // If we have made it this far in the error analysis we already know that // exactly one of S and T is C or C? -- if two or zero were, then we'd // have already reported ERR_ConversionNotInvolvingContainedType or // ERR_IdentityConversion and returned. // // WOLOG for the purposes of this discussion let's assume that S is // the one that is C or C?, and that T is the one that is neither C nor C?. // // So the question is: under what circumstances could T-to-S or S-to-T, // be a valid conversion, by the definition of valid above? // // Let's consider what kinds of types T could be. T cannot be an interface // because we've already reported an error and returned if it is. If T is // a delegate, array, enum, pointer, struct or nullable type then there // is no built-in conversion from T to the user-declared class/struct // C, or to C?. If T is a type parameter, then by assumption the type // parameter has no constraints, and therefore is not convertible to // C or C?. // // That leaves T to be a class. We already know that T is not C, (or C?, // since T is a class) and therefore there is no identity conversion from T to S. // // Suppose S is C and C is a class. Then the only way that there can be a // conversion between T and S is if T is a base class of S or S is a base class of T. // // Suppose S is C and C is a struct. Then the only way that there can be a // conversion between T and S is if T is a base class of S. (And T would // have to be System.Object or System.ValueType.) // // Suppose S is C? and C is a struct. Then the only way that there can be a // conversion between T and S is again, if T is a base class of S. // // Summing up: // // WOLOG, we assume that T is not C or C?, and S is C or C?. The conversion is // illegal only if T is a class, and either T is a base class of S, or S is a // base class of T. if (source.IsDynamic() || target.IsDynamic()) { // '{0}': user-defined conversions to or from the dynamic type are not allowed diagnostics.Add(ErrorCode.ERR_BadDynamicConversion, this.Locations[0], this); return; } TypeSymbol same; TypeSymbol different; if (source0 == this.ContainingType) { same = source; different = target; } else { same = target; different = source; } if (different.IsClassType()) { // different is a class type: Debug.Assert(!different.IsTypeParameter()); // "same" is the containing class, so it can't be a type parameter Debug.Assert(!same.IsTypeParameter()); HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (same.IsDerivedFrom(different, ignoreDynamic: false, useSiteDiagnostics: ref useSiteDiagnostics)) // tomat: ignoreDynamic should be true, but we don't want to introduce breaking change. See bug 605326. { // '{0}': user-defined conversions to or from a base class are not allowed diagnostics.Add(ErrorCode.ERR_ConversionWithBase, this.Locations[0], this); } else if (different.IsDerivedFrom(same, ignoreDynamic: false, useSiteDiagnostics: ref useSiteDiagnostics)) // tomat: ignoreDynamic should be true, but we don't want to introduce breaking change. See bug 605326. { // '{0}': user-defined conversions to or from a derived class are not allowed diagnostics.Add(ErrorCode.ERR_ConversionWithDerived, this.Locations[0], this); } diagnostics.Add(this.Locations[0], useSiteDiagnostics); } }
internal static void Add(this DiagnosticBag diagnostics, DiagnosticInfo info, Location location) { var diag = new CSDiagnostic(info, location); diagnostics.Add(diag); }
protected SourceUserDefinedOperatorSymbolBase( MethodKind methodKind, string name, SourceMemberContainerTypeSymbol containingType, Location location, SyntaxReference syntaxReference, SyntaxReference bodySyntaxReference, SyntaxTokenList modifiersSyntax, DiagnosticBag diagnostics, bool isExpressionBodied) : base(containingType, syntaxReference, bodySyntaxReference, location) { this.name = name; this.isExpressionBodied = isExpressionBodied; var defaultAccess = DeclarationModifiers.Private; var allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.Static | DeclarationModifiers.Extern | DeclarationModifiers.Unsafe; bool modifierErrors; var declarationModifiers = ModifierUtils.MakeAndCheckNontypeMemberModifiers( modifiersSyntax, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); this.CheckUnsafeModifier(declarationModifiers, diagnostics); // We will bind the formal parameters and the return type lazily. For now, // assume that the return type is non-void; when we do the lazy initialization // of the parameters and return type we will update the flag if necessary. this.flags = MakeFlags(methodKind, declarationModifiers, returnsVoid: false, isExtensionMethod: false); if (this.ContainingType.IsInterface) { // If we have an operator in an interface, we already have reported that fact as // an error. No need to cascade the error further. return; } if (this.ContainingType.IsStatic) { // Similarly if we're in a static class, though we have not reported it yet. // CS0715: '{0}': static classes cannot contain user-defined operators diagnostics.Add(ErrorCode.ERR_OperatorInStaticClass, location, this); return; } // SPEC: An operator declaration must include both a public and a // SPEC: static modifier if (this.DeclaredAccessibility != Accessibility.Public || !this.IsStatic) { // CS0558: User-defined operator '...' must be declared static and public diagnostics.Add(ErrorCode.ERR_OperatorsMustBeStatic, this.Locations[0], this); } // SPEC: Because an external operator provides no actual implementation, // SPEC: its operator body consists of a semicolon. For expression-bodied // SPEC: operators, the body is an expression. For all other operators, // SPEC: the operator body consists of a block... if (bodySyntaxReference != null && IsExtern) { diagnostics.Add(ErrorCode.ERR_ExternHasBody, location, this); } else if (bodySyntaxReference == null && !IsExtern && !IsAbstract && !IsPartial) { // Do not report that the body is missing if the operator is marked as // partial or abstract; we will already have given an error for that so // there's no need to "cascade" the error. diagnostics.Add(ErrorCode.ERR_ConcreteMissingBody, location, this); } // SPEC: It is an error for the same modifier to appear multiple times in an // SPEC: operator declaration. var info = ModifierUtils.CheckAccessibility(this.DeclarationModifiers); if (info != null) { diagnostics.Add(info, location); } }
internal VariableSlotAllocator?TryCreateVariableSlotAllocator( EmitBaseline baseline, Compilation compilation, IMethodSymbolInternal method, IMethodSymbolInternal topLevelMethod, DiagnosticBag diagnostics ) { // Top-level methods are always included in the semantic edit list. Lambda methods are not. if (!mappedMethods.TryGetValue(topLevelMethod, out var mappedMethod)) { return(null); } // TODO (bug https://github.com/dotnet/roslyn/issues/2504): // Handle cases when the previous method doesn't exist. if ( !TryGetMethodHandle( baseline, (Cci.IMethodDefinition)method.GetCciAdapter(), out var previousHandle ) ) { // Unrecognized method. Must have been added in the current compilation. return(null); } ImmutableArray <EncLocalInfo> previousLocals; IReadOnlyDictionary <EncHoistedLocalInfo, int>? hoistedLocalMap = null; IReadOnlyDictionary <Cci.ITypeReference, int>? awaiterMap = null; IReadOnlyDictionary <int, KeyValuePair <DebugId, int> >?lambdaMap = null; IReadOnlyDictionary <int, DebugId>?closureMap = null; int hoistedLocalSlotCount = 0; int awaiterSlotCount = 0; string? stateMachineTypeName = null; SymbolMatcher symbolMap; int methodIndex = MetadataTokens.GetRowNumber(previousHandle); DebugId methodId; // Check if method has changed previously. If so, we already have a map. if ( baseline.AddedOrChangedMethods.TryGetValue( methodIndex, out var addedOrChangedMethod ) ) { methodId = addedOrChangedMethod.MethodId; MakeLambdaAndClosureMaps( addedOrChangedMethod.LambdaDebugInfo, addedOrChangedMethod.ClosureDebugInfo, out lambdaMap, out closureMap ); if (addedOrChangedMethod.StateMachineTypeName != null) { // method is async/iterator kickoff method GetStateMachineFieldMapFromPreviousCompilation( addedOrChangedMethod.StateMachineHoistedLocalSlotsOpt, addedOrChangedMethod.StateMachineAwaiterSlotsOpt, out hoistedLocalMap, out awaiterMap ); hoistedLocalSlotCount = addedOrChangedMethod.StateMachineHoistedLocalSlotsOpt.Length; awaiterSlotCount = addedOrChangedMethod.StateMachineAwaiterSlotsOpt.Length; // Kickoff method has no interesting locals on its own. // We use the EnC method debug information for hoisted locals. previousLocals = ImmutableArray <EncLocalInfo> .Empty; stateMachineTypeName = addedOrChangedMethod.StateMachineTypeName; } else { previousLocals = addedOrChangedMethod.Locals; } // All types that AddedOrChangedMethodInfo refers to have been mapped to the previous generation. // Therefore we don't need to fall back to metadata if we don't find the type reference, like we do in DefinitionMap.MapReference. symbolMap = MapToPreviousSymbolMatcher; } else { // Method has not changed since initial generation. Generate a map // using the local names provided with the initial metadata. EditAndContinueMethodDebugInformation debugInfo; StandaloneSignatureHandle localSignature; try { debugInfo = baseline.DebugInformationProvider(previousHandle); localSignature = baseline.LocalSignatureProvider(previousHandle); } catch (Exception e) when(e is InvalidDataException || e is IOException) { diagnostics.Add( MessageProvider.CreateDiagnostic( MessageProvider.ERR_InvalidDebugInfo, method.Locations.First(), method, MetadataTokens.GetToken(previousHandle), method.ContainingAssembly ) ); return(null); } methodId = new DebugId(debugInfo.MethodOrdinal, 0); if (!debugInfo.Lambdas.IsDefaultOrEmpty) { MakeLambdaAndClosureMaps( debugInfo.Lambdas, debugInfo.Closures, out lambdaMap, out closureMap ); } ITypeSymbolInternal?stateMachineType = TryGetStateMachineType(previousHandle); if (stateMachineType != null) { // method is async/iterator kickoff method var localSlotDebugInfo = debugInfo.LocalSlots.NullToEmpty(); GetStateMachineFieldMapFromMetadata( stateMachineType, localSlotDebugInfo, out hoistedLocalMap, out awaiterMap, out awaiterSlotCount ); hoistedLocalSlotCount = localSlotDebugInfo.Length; // Kickoff method has no interesting locals on its own. // We use the EnC method debug information for hoisted locals. previousLocals = ImmutableArray <EncLocalInfo> .Empty; stateMachineTypeName = stateMachineType.Name; } else { // If the current method is async/iterator then either the previous method wasn't declared as async/iterator and it's updated to be one, // or it was but is not marked by the corresponding state machine attribute because it was missing in the compilation. // In the later case we need to report an error since we don't known how to map to the previous state machine. // The IDE already checked that the attribute type is present in the base compilation, but didn't validate that it is well-formed. // We don't have the base compilation to directly query for the attribute, only the source compilation. // But since constructor signatures can't be updated during EnC we can just check the current compilation. if (method.IsAsync) { if ( compilation.CommonGetWellKnownTypeMember( WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor ) == null ) { ReportMissingStateMachineAttribute( diagnostics, method, AttributeDescription.AsyncStateMachineAttribute.FullName ); return(null); } } else if (method.IsIterator) { if ( compilation.CommonGetWellKnownTypeMember( WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor ) == null ) { ReportMissingStateMachineAttribute( diagnostics, method, AttributeDescription.IteratorStateMachineAttribute.FullName ); return(null); } } try { previousLocals = localSignature.IsNil ? ImmutableArray <EncLocalInfo> .Empty : GetLocalSlotMapFromMetadata(localSignature, debugInfo); } catch (Exception e) when(e is UnsupportedSignatureContent || e is BadImageFormatException || e is IOException ) { diagnostics.Add( MessageProvider.CreateDiagnostic( MessageProvider.ERR_InvalidDebugInfo, method.Locations.First(), method, MetadataTokens.GetToken(localSignature), method.ContainingAssembly ) ); return(null); } } symbolMap = MapToMetadataSymbolMatcher; } return(new EncVariableSlotAllocator( symbolMap, mappedMethod.SyntaxMap, mappedMethod.PreviousMethod, methodId, previousLocals, lambdaMap, closureMap, stateMachineTypeName, hoistedLocalSlotCount, hoistedLocalMap, awaiterSlotCount, awaiterMap, GetLambdaSyntaxFacts() )); }
/// <summary> /// At this point, we have a list of viable symbols and no parameter list with which to perform /// overload resolution. We'll just return the first symbol, giving a diagnostic if there are /// others. /// Caveat: If there are multiple candidates and only one is from source, then the source symbol /// wins and no diagnostic is reported. /// </summary> private ImmutableArray <Symbol> ProcessParameterlessCrefMemberLookupResults( ImmutableArray <Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax typeArgumentListSyntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { // If the syntax indicates arity zero, then we match methods of any arity. // However, if there are both generic and non-generic methods, then the // generic methods should be ignored. if (symbols.Length > 1 && arity == 0) { bool hasNonGenericMethod = false; bool hasGenericMethod = false; foreach (Symbol s in symbols) { if (s.Kind != SymbolKind.Method) { continue; } if (((MethodSymbol)s).Arity == 0) { hasNonGenericMethod = true; } else { hasGenericMethod = true; } if (hasGenericMethod && hasNonGenericMethod) { break; //Nothing else to be learned. } } if (hasNonGenericMethod && hasGenericMethod) { symbols = symbols.WhereAsArray(s => s.Kind != SymbolKind.Method || ((MethodSymbol)s).Arity == 0); } } Debug.Assert(!symbols.IsEmpty); Symbol symbol = symbols[0]; // If there's ambiguity, prefer source symbols. // Logic is similar to ResultSymbol, but separate because the error handling is totally different. if (symbols.Length > 1) { // Size is known, but IndexOfSymbolFromCurrentCompilation expects a builder. ArrayBuilder <Symbol> unwrappedSymbols = ArrayBuilder <Symbol> .GetInstance(symbols.Length); foreach (Symbol wrapped in symbols) { unwrappedSymbols.Add(UnwrapAliasNoDiagnostics(wrapped)); } BestSymbolInfo secondBest; BestSymbolInfo best = GetBestSymbolInfo(unwrappedSymbols, out secondBest); Debug.Assert(!best.IsNone); Debug.Assert(!secondBest.IsNone); unwrappedSymbols.Free(); int symbolIndex = 0; if (best.IsFromCompilation) { symbolIndex = best.Index; symbol = symbols[symbolIndex]; // NOTE: symbols, not unwrappedSymbols. } if (symbol.Kind == SymbolKind.TypeParameter) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString()); } else if (secondBest.IsFromCompilation == best.IsFromCompilation) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); int otherIndex = symbolIndex == 0 ? 1 : 0; diagnostics.Add(ErrorCode.WRN_AmbiguousXMLReference, crefSyntax.Location, crefSyntax.ToString(), symbol, symbols[otherIndex]); ambiguityWinner = ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol); return(symbols.SelectAsArray(sym => ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, sym))); } } else if (symbol.Kind == SymbolKind.TypeParameter) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString()); } ambiguityWinner = null; return(ImmutableArray.Create <Symbol>(ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol))); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), location)); }
/// <summary> /// Recursively builds a Conversion object with Kind=Deconstruction including information about any necessary /// Deconstruct method and any element-wise conversion. /// /// Note that the variables may either be plain or nested variables. /// The variables may be updated with inferred types if they didn't have types initially. /// Returns false if there was an error. /// </summary> private bool MakeDeconstructionConversion( TypeSymbol type, SyntaxNode syntax, SyntaxNode rightSyntax, DiagnosticBag diagnostics, ArrayBuilder <DeconstructionVariable> variables, out Conversion conversion) { Debug.Assert(type != null); ImmutableArray <TypeSymbol> tupleOrDeconstructedTypes; conversion = Conversion.Deconstruction; // Figure out the deconstruct method (if one is required) and determine the types we get from the RHS at this level var deconstructInfo = default(DeconstructionInfo); if (type.IsTupleType) { // tuple literal such as `(1, 2)`, `(null, null)`, `(x.P, y.M())` tupleOrDeconstructedTypes = type.TupleElementTypes; SetInferredTypes(variables, tupleOrDeconstructedTypes, diagnostics); if (variables.Count != tupleOrDeconstructedTypes.Length) { Error(diagnostics, ErrorCode.ERR_DeconstructWrongCardinality, syntax, tupleOrDeconstructedTypes.Length, variables.Count); return(false); } } else { ImmutableArray <BoundDeconstructValuePlaceholder> outPlaceholders; var inputPlaceholder = new BoundDeconstructValuePlaceholder(syntax, type); var deconstructInvocation = MakeDeconstructInvocationExpression(variables.Count, inputPlaceholder, rightSyntax, diagnostics, out outPlaceholders); if (deconstructInvocation.HasAnyErrors) { return(false); } deconstructInfo = new DeconstructionInfo(deconstructInvocation, inputPlaceholder, outPlaceholders); tupleOrDeconstructedTypes = outPlaceholders.SelectAsArray(p => p.Type); SetInferredTypes(variables, tupleOrDeconstructedTypes, diagnostics); } // Figure out whether those types will need conversions, including further deconstructions bool hasErrors = false; int count = variables.Count; var nestedConversions = ArrayBuilder <Conversion> .GetInstance(count); for (int i = 0; i < count; i++) { var variable = variables[i]; Conversion nestedConversion; if (variable.HasNestedVariables) { var elementSyntax = syntax.Kind() == SyntaxKind.TupleExpression ? ((TupleExpressionSyntax)syntax).Arguments[i] : syntax; hasErrors |= !MakeDeconstructionConversion(tupleOrDeconstructedTypes[i], syntax, rightSyntax, diagnostics, variable.NestedVariables, out nestedConversion); } else { var single = variable.Single; HashSet <DiagnosticInfo> useSiteDiagnostics = null; nestedConversion = this.Conversions.ClassifyConversionFromType(tupleOrDeconstructedTypes[i], single.Type, ref useSiteDiagnostics); diagnostics.Add(single.Syntax, useSiteDiagnostics); if (!nestedConversion.IsImplicit) { hasErrors = true; GenerateImplicitConversionError(diagnostics, Compilation, single.Syntax, nestedConversion, tupleOrDeconstructedTypes[i], single.Type); } } nestedConversions.Add(nestedConversion); } conversion = new Conversion(ConversionKind.Deconstruction, deconstructInfo, nestedConversions.ToImmutableAndFree()); return(!hasErrors); }
private void Error(ErrorCode code, BoundNode node, params object[] args) { diagnostics.Add(code, node.Syntax.Location, args); }
public LocalFunctionSymbol( Binder binder, Symbol containingSymbol, LocalFunctionStatementSyntax syntax) : base(syntax.GetReference()) { _containingSymbol = containingSymbol; _declarationDiagnostics = new DiagnosticBag(); _declarationModifiers = DeclarationModifiers.Private | syntax.Modifiers.ToDeclarationModifiers(diagnostics: _declarationDiagnostics); if (SyntaxFacts.HasYieldOperations(syntax.Body)) { _lazyIteratorElementType = TypeWithAnnotations.Boxed.Sentinel; } this.CheckUnsafeModifier(_declarationModifiers, _declarationDiagnostics); ScopeBinder = binder; binder = binder.WithUnsafeRegionIfNecessary(syntax.Modifiers); if (syntax.TypeParameterList != null) { binder = new WithMethodTypeParametersBinder(this, binder); _typeParameters = MakeTypeParameters(_declarationDiagnostics); } else { _typeParameters = ImmutableArray <SourceMethodTypeParameterSymbol> .Empty; ReportErrorIfHasConstraints(syntax.ConstraintClauses, _declarationDiagnostics); } if (IsExtensionMethod) { _declarationDiagnostics.Add(ErrorCode.ERR_BadExtensionAgg, Locations[0]); } foreach (var param in syntax.ParameterList.Parameters) { ReportAttributesDisallowed(param.AttributeLists, _declarationDiagnostics); } if (syntax.ReturnType.Kind() == SyntaxKind.RefType) { var returnType = (RefTypeSyntax)syntax.ReturnType; if (returnType.ReadOnlyKeyword.Kind() == SyntaxKind.ReadOnlyKeyword) { _refKind = RefKind.RefReadOnly; } else { _refKind = RefKind.Ref; } } else { _refKind = RefKind.None; } _binder = binder; }
private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpressionSyntax node, DiagnosticBag diagnostics) { // prepare var initializers = node.Initializers; int fieldCount = initializers.Count; bool hasError = false; // bind field initializers BoundExpression[] boundExpressions = new BoundExpression[fieldCount]; AnonymousTypeField[] fields = new AnonymousTypeField[fieldCount]; CSharpSyntaxNode[] fieldSyntaxNodes = new CSharpSyntaxNode[fieldCount]; // WARNING: Note that SemanticModel.GetDeclaredSymbol for field initializer node relies on // the fact that the order of properties in anonymous type template corresponds // 1-to-1 to the appropriate filed initializer syntax nodes; This means such // correspondence must be preserved all the time including erroneous scenarios // set of names already used var uniqueFieldNames = PooledHashSet <string> .GetInstance(); for (int i = 0; i < fieldCount; i++) { AnonymousObjectMemberDeclaratorSyntax fieldInitializer = initializers[i]; NameEqualsSyntax nameEquals = fieldInitializer.NameEquals; ExpressionSyntax expression = fieldInitializer.Expression; SyntaxToken nameToken = default(SyntaxToken); if (nameEquals != null) { nameToken = nameEquals.Name.Identifier; } else { if (!IsAnonymousTypeMemberExpression(expression)) { hasError = true; diagnostics.Add(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, expression.GetLocation()); } nameToken = expression.ExtractAnonymousTypeMemberName(); } hasError |= expression.HasErrors; boundExpressions[i] = this.BindValue(expression, diagnostics, BindValueKind.RValue); // check the name to be unique string fieldName = null; if (nameToken.Kind() == SyntaxKind.IdentifierToken) { fieldName = nameToken.ValueText; if (!uniqueFieldNames.Add(fieldName)) { // name duplication Error(diagnostics, ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, fieldInitializer); hasError = true; fieldName = null; } } else { // there is something wrong with field's name hasError = true; } // calculate the expression's type and report errors if needed TypeSymbol fieldType = GetAnonymousTypeFieldType(boundExpressions[i], fieldInitializer, diagnostics, ref hasError); // build anonymous type field descriptor fieldSyntaxNodes[i] = (nameToken.Kind() == SyntaxKind.IdentifierToken) ? (CSharpSyntaxNode)nameToken.Parent : fieldInitializer; // https://github.com/dotnet/roslyn/issues/24018: Initial binding should set NullableAnnotation.Unknown NullableAnnotation nullableAnnotation; switch (((CSharpParseOptions)node.SyntaxTree?.Options)?.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes)) { case true: nullableAnnotation = fieldType.IsReferenceType ? NullableAnnotation.Annotated : NullableAnnotation.NotAnnotated; break; case false: nullableAnnotation = NullableAnnotation.NotAnnotated; break; default: nullableAnnotation = NullableAnnotation.Unknown; break; } fields[i] = new AnonymousTypeField( fieldName == null ? "$" + i.ToString() : fieldName, fieldSyntaxNodes[i].Location, TypeSymbolWithAnnotations.Create(fieldType, nullableAnnotation)); // NOTE: ERR_InvalidAnonymousTypeMemberDeclarator (CS0746) would be generated by parser if needed } uniqueFieldNames.Free(); // Create anonymous type AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager; AnonymousTypeDescriptor descriptor = new AnonymousTypeDescriptor(fields.AsImmutableOrNull(), node.NewKeyword.GetLocation()); NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(descriptor); // declarators - bound nodes created for providing semantic info // on anonymous type fields having explicitly specified name ArrayBuilder <BoundAnonymousPropertyDeclaration> declarators = ArrayBuilder <BoundAnonymousPropertyDeclaration> .GetInstance(); for (int i = 0; i < fieldCount; i++) { NameEqualsSyntax explicitName = initializers[i].NameEquals; if (explicitName != null) { AnonymousTypeField field = fields[i]; if (field.Name != null) { // get property symbol and create a bound property declaration node foreach (var symbol in anonymousType.GetMembers(field.Name)) { if (symbol.Kind == SymbolKind.Property) { declarators.Add(new BoundAnonymousPropertyDeclaration(fieldSyntaxNodes[i], (PropertySymbol)symbol, field.Type.TypeSymbol)); break; } } } } } // check if anonymous object creation is allowed in this context if (!this.IsAnonymousTypesAllowed()) { Error(diagnostics, ErrorCode.ERR_AnonymousTypeNotAvailable, node.NewKeyword); hasError = true; } // Finally create a bound node return(new BoundAnonymousObjectCreationExpression( node, anonymousType.InstanceConstructors[0], boundExpressions.AsImmutableOrNull(), declarators.ToImmutableAndFree(), anonymousType, hasError)); }
private static Symbol FindExplicitlyImplementedMember( Symbol implementingMember, TypeSymbol explicitInterfaceType, string interfaceMemberName, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifierSyntax, DiagnosticBag diagnostics) { if ((object)explicitInterfaceType == null) { return(null); } var memberLocation = implementingMember.Locations[0]; var containingType = implementingMember.ContainingType; var containingTypeKind = containingType.TypeKind; if (containingTypeKind != TypeKind.Class && containingTypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, memberLocation, implementingMember); return(null); } if (!explicitInterfaceType.IsInterfaceType()) { //we'd like to highlight just the type part of the name var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name; var location = new SourceLocation(explicitInterfaceSyntax); diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationNotInterface, location, explicitInterfaceType); return(null); } var explicitInterfaceNamedType = (NamedTypeSymbol)explicitInterfaceType; // 13.4.1: "For an explicit interface member implementation to be valid, the class or struct must name an // interface in its base class list that contains a member ..." MultiDictionary <NamedTypeSymbol, NamedTypeSymbol> .ValueSet set = containingType.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics[explicitInterfaceNamedType]; int setCount = set.Count; if (setCount == 0 || !set.Contains(explicitInterfaceNamedType)) { //we'd like to highlight just the type part of the name var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name; var location = new SourceLocation(explicitInterfaceSyntax); if (setCount > 0 && set.Contains(explicitInterfaceNamedType, TypeSymbol.EqualsIgnoringNullableComparer)) { diagnostics.Add(ErrorCode.WRN_NullabilityMismatchInExplicitlyImplementedInterface, location); } else { diagnostics.Add(ErrorCode.ERR_ClassDoesntImplementInterface, location, implementingMember, explicitInterfaceNamedType); } //do a lookup anyway } var hasParamsParam = implementingMember.HasParamsParameter(); // Setting this flag to true does not imply that an interface member has been successfully implemented. // It just indicates that a corresponding interface member has been found (there may still be errors). var foundMatchingMember = false; Symbol implementedMember = null; foreach (Symbol interfaceMember in explicitInterfaceNamedType.GetMembers(interfaceMemberName)) { // At this point, we know that explicitInterfaceNamedType is an interface, so candidate must be public // and, therefore, accessible. So we don't need to check that. // However, metadata interface members can be static - we ignore them, as does Dev10. if (interfaceMember.Kind != implementingMember.Kind || interfaceMember.IsStatic) { continue; } if (MemberSignatureComparer.ExplicitImplementationLookupComparer.Equals(implementingMember, interfaceMember)) { foundMatchingMember = true; // Cannot implement accessor directly unless // the accessor is from an indexed property. if (interfaceMember.IsAccessor() && !((MethodSymbol)interfaceMember).IsIndexedPropertyAccessor()) { diagnostics.Add(ErrorCode.ERR_ExplicitMethodImplAccessor, memberLocation, implementingMember, interfaceMember); } else { if (interfaceMember.MustCallMethodsDirectly()) { diagnostics.Add(ErrorCode.ERR_BogusExplicitImpl, memberLocation, implementingMember, interfaceMember); } else if (hasParamsParam && !interfaceMember.HasParamsParameter()) { // Note: no error for !hasParamsParam && interfaceMethod.HasParamsParameter() // Still counts as an implementation. diagnostics.Add(ErrorCode.ERR_ExplicitImplParams, memberLocation, implementingMember, interfaceMember); } implementedMember = interfaceMember; break; } } } if (!foundMatchingMember) { // CONSIDER: we may wish to suppress this error in the event that another error // has been reported about the signature. diagnostics.Add(ErrorCode.ERR_InterfaceMemberNotFound, memberLocation, implementingMember); } return(implementedMember); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), token.GetLocation())); }
internal void Add(SlothDiagnostic diagnostic) { DiagnosticBag?.Add(diagnostic); }
private static void Error(DiagnosticBag diagnostics, SyntaxNode syntaxOpt, DiagnosticInfo info) { diagnostics.Add(new CSDiagnostic(info, syntaxOpt == null ? NoLocation.Singleton : syntaxOpt.Location)); }