/// <summary> /// Parse expression. Returns null if there are any errors. /// </summary> internal static ExpressionSyntax ParseExpression( this string expr, DiagnosticBag diagnostics, bool allowFormatSpecifiers, out ReadOnlyCollection<string> formatSpecifiers) { // Remove trailing semi-colon if any. This is to support copy/paste // of (simple cases of) RHS of assignment in Watch window, not to // allow arbitrary syntax after the semi-colon, not even comments. if (RemoveSemicolonIfAny(ref expr)) { // Format specifiers are not expected before a semi-colon. allowFormatSpecifiers = false; } var syntax = ParseDebuggerExpression(expr, consumeFullText: !allowFormatSpecifiers); diagnostics.AddRange(syntax.GetDiagnostics()); formatSpecifiers = null; if (allowFormatSpecifiers) { var builder = ArrayBuilder<string>.GetInstance(); if (ParseFormatSpecifiers(builder, expr, syntax.FullWidth, diagnostics) && (builder.Count > 0)) { formatSpecifiers = new ReadOnlyCollection<string>(builder.ToArray()); } builder.Free(); } return diagnostics.HasAnyErrors() ? null : syntax; }
public override Stream CreateStream(DiagnosticBag diagnostics) { Debug.Assert(_streamToDispose == null); try { try { return OpenFileStream(); } catch (IOException e) { // Other process is reading the file preventing us to write to it. // We attempt to rename and delete the file in case the reader opened it with FileShare.Delete flag that // allows the file to be deleted by other processes. // // Note that if the file is marked "readonly" or the current user doesn't have sufficient privileges // the exception thrown is UnauthorizedAccessException, not IOException, so we won't attempt to delete the file. try { const int eWin32SharingViolation = unchecked((int)0x80070020); if (PathUtilities.IsUnixLikePlatform) { // Unix & Mac are simple: just delete the file in the directory. // The memory mapped content remains available for the reader. PortableShim.File.Delete(_filePath); } else if (e.HResult == eWin32SharingViolation) { // On Windows File.Delete only marks the file for deletion, but doens't remove it from the directory. var newFilePath = Path.Combine(Path.GetDirectoryName(_filePath), Guid.NewGuid().ToString() + "_" + Path.GetFileName(_filePath)); // Try to rename the existing file. This fails unless the file is open with FileShare.Delete. PortableShim.File.Move(_filePath, newFilePath); // hide the renamed file: PortableShim.File.SetAttributes(newFilePath, PortableShim.FileAttributes.Hidden); // Mark the renamed file for deletion, so that it's deleted as soon as the current reader is finished reading it PortableShim.File.Delete(newFilePath); } } catch { // report the original exception ReportOpenFileDiagnostic(diagnostics, e); return null; } return OpenFileStream(); } } catch (Exception e) { ReportOpenFileDiagnostic(diagnostics, e); return null; } }
/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return body; } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return body; } return rewriter.Rewrite(); }
internal static ExpressionSyntax ParseAssignment( this string target, string expr, DiagnosticBag diagnostics) { var text = SourceText.From(expr); var expression = SyntaxHelpers.ParseDebuggerExpressionInternal(text, consumeFullText: true); // We're creating a SyntaxTree for just the RHS so that the Diagnostic spans for parse errors // will be correct (with respect to the original input text). If we ever expose a SemanticModel // for debugger expressions, we should use this SyntaxTree. var syntaxTree = expression.CreateSyntaxTree(text); diagnostics.AddRange(syntaxTree.GetDiagnostics()); if (diagnostics.HasAnyErrors()) { return null; } // Any Diagnostic spans produced in binding will be offset by the length of the "target" expression text. // If we want to support live squiggles in debugger windows, SemanticModel, etc, we'll want to address this. var targetSyntax = SyntaxHelpers.ParseDebuggerExpressionInternal(SourceText.From(target), consumeFullText: true); Debug.Assert(!targetSyntax.GetDiagnostics().Any(), "The target of an assignment should never contain Diagnostics if we're being allowed to assign to it in the debugger."); var assignment = InternalSyntax.SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, targetSyntax, InternalSyntax.SyntaxFactory.Token(SyntaxKind.EqualsToken), expression); return assignment.MakeDebuggerExpression(SourceText.From(assignment.ToString())); }
internal override BoundExpression GetValue(BoundPseudoVariable variable, DiagnosticBag diagnostics) { var method = GetIntrinsicMethod(_compilation, ExpressionCompilerConstants.GetVariableValueMethodName); var local = variable.LocalSymbol; var expr = InvokeGetMethod(method, variable.Syntax, local.Name); return ConvertToLocalType(_compilation, expr, local.Type, diagnostics); }
/// <summary> /// Rewrite an iterator method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo) { TypeSymbol elementType = method.IteratorElementType; if ((object)elementType == null) { return body; } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType); } var iteratorClass = new IteratorStateMachine(method, isEnumerable, elementType, compilationState); return new IteratorRewriter(body, method, isEnumerable, iteratorClass, compilationState, diagnostics, generateDebugInfo).Rewrite(); }
private void EnsureSwitchGoverningExpressionAndDiagnosticsBound() { var switchGoverningDiagnostics = new DiagnosticBag(); var boundSwitchExpression = BindSwitchExpression(SwitchSyntax.Expression, switchGoverningDiagnostics); _switchGoverningDiagnostics = switchGoverningDiagnostics; Interlocked.CompareExchange(ref _switchGoverningExpression, boundSwitchExpression, null); }
private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics) { BoundStatement initializer; if (node.Declaration != null) { Debug.Assert(node.Initializers.Count == 0); if (node.Declaration.IsDeconstructionDeclaration) { initializer = originalBinder.BindDeconstructionDeclaration(node.Declaration, node.Declaration, diagnostics); } else { ImmutableArray<BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused); } } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } var condition = (node.Condition != null) ? originalBinder.BindBooleanExpression(node.Condition, diagnostics) : null; var increment = originalBinder.BindStatementExpressionList(node.Incrementors, diagnostics); var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return new BoundForStatement(node, this.Locals, initializer, condition, increment, body, this.BreakLabel, this.ContinueLabel); }
/// <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; }
private ImmutableArray<Symbol> BindQualifiedCref(QualifiedCrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { // NOTE: we won't check whether container is an error type - we'll just let BindMemberCref fail // and report a blanket diagnostic. NamespaceOrTypeSymbol container = BindNamespaceOrTypeSymbolInCref(syntax.Container); return BindMemberCref(syntax.Member, container, out ambiguityWinner, diagnostics); }
public void ImplicitlyTypedArrayLocal() { var compilation = CreateCompilationWithMscorlib(@" class M {} class C { public void F() { var a = new[] { new M() }; } } "); compilation.VerifyDiagnostics(); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("F").Single(); var diagnostics = new DiagnosticBag(); var block = Compiler.BindMethodBody(method, diagnostics); var locDecl =(BoundLocalDeclaration)block.Statements.Single(); var localA = (ArrayTypeSymbol)locDecl.DeclaredType.Display; var typeM = compilation.GlobalNamespace.GetMember<TypeSymbol>("M"); Assert.Equal(typeM, localA.ElementType); }
public static SourcePropertyAccessorSymbol CreateAccessorSymbol( NamedTypeSymbol containingType, SourcePropertySymbol property, DeclarationModifiers propertyModifiers, string propertyName, ArrowExpressionClauseSyntax syntax, PropertySymbol explicitlyImplementedPropertyOpt, string aliasQualifierOpt, DiagnosticBag diagnostics) { string name; ImmutableArray<MethodSymbol> explicitInterfaceImplementations; GetNameAndExplicitInterfaceImplementations( explicitlyImplementedPropertyOpt, propertyName, property.IsCompilationOutputWinMdObj(), aliasQualifierOpt, isGetMethod: true, name: out name, explicitInterfaceImplementations: out explicitInterfaceImplementations); return new SourcePropertyAccessorSymbol( containingType, name, property, propertyModifiers, explicitInterfaceImplementations, syntax.Expression.GetLocation(), syntax, diagnostics); }
internal ImmutableArray<Symbol> BindCref(CrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { ImmutableArray<Symbol> symbols = BindCrefInternal(syntax, out ambiguityWinner, diagnostics); Debug.Assert(!symbols.IsDefault, "Prefer empty to null."); Debug.Assert((symbols.Length > 1) == ((object)ambiguityWinner != null), "ambiguityWinner should be set iff more than one symbol is returned."); return symbols; }
internal static NamespaceSymbol BuildSymbol( this MergedNamespaceDeclaration declaration, NamespaceOrTypeSymbol parent, DiagnosticBag diagnostics) { return new SourceNamespaceSymbol(parent, declaration, diagnostics); }
protected override ReadOnlyArray<ParameterSymbol> MakeParameters( Binder binder, DelegateDeclarationSyntax syntax, out bool isExtensionMethod, out bool isVararg, DiagnosticBag diagnostics, CancellationToken cancellationToken) { isExtensionMethod = false; isVararg = false; var delegateBinder = binder as DelegateBinder; var parameters = ArrayBuilder<ParameterSymbol>.GetInstance(); int ordinal = 0; foreach (var p in delegateBinder.invoke.Parameters) { cancellationToken.ThrowIfCancellationRequested(); if (p.RefKind != RefKind.None) { parameters.Add(new SynthesizedParameterSymbol(this, p.Type, ordinal++, p.RefKind, p.Name)); } } parameters.Add(new SynthesizedParameterSymbol(this, binder.GetSpecialType(SpecialType.System_IAsyncResult, diagnostics, syntax), ordinal++, RefKind.None, "result")); return parameters.ToReadOnlyAndFree(); }
internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitializerMethod initializerMethod, DiagnosticBag diagnostics) { var containingType = initializerMethod.ContainingType; var compilation = containingType.DeclaringCompilation; if (compilation.IsSubmission) { var submissionArrayType = compilation.CreateArrayTypeSymbol(compilation.GetSpecialType(SpecialType.System_Object)); ReportUseSiteDiagnostics(submissionArrayType, diagnostics); return new SubmissionEntryPoint( containingType, initializerMethod.ReturnType, submissionArrayType); } else { var taskType = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task); #if DEBUG HashSet<DiagnosticInfo> useSiteDiagnostics = null; Debug.Assert(taskType.IsErrorType() || initializerMethod.ReturnType.IsDerivedFrom(taskType, ignoreDynamic: true, useSiteDiagnostics: ref useSiteDiagnostics)); #endif ReportUseSiteDiagnostics(taskType, diagnostics); var getAwaiterMethod = taskType.IsErrorType() ? null : GetRequiredMethod(taskType, WellKnownMemberNames.GetAwaiter, diagnostics); var getResultMethod = ((object)getAwaiterMethod == null) ? null : GetRequiredMethod(getAwaiterMethod.ReturnType, WellKnownMemberNames.GetResult, diagnostics); return new ScriptEntryPoint( containingType, compilation.GetSpecialType(SpecialType.System_Void), getAwaiterMethod, getResultMethod); } }
internal AsyncMethodToStateMachineRewriter( MethodSymbol method, int methodOrdinal, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, IReadOnlySet<Symbol> hoistedVariables, IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, DiagnosticBag diagnostics) : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false) { _method = method; _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; _asyncMethodBuilderField = builder; _exprReturnLabel = F.GenerateLabel("exprReturn"); _exitLabel = F.GenerateLabel("exitLabel"); _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue) : null; _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal); _awaiterFields = new Dictionary<TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicComparer); _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0; }
/// <summary> /// Traverses the symbol table processing XML documentation comments and optionally writing them to /// a provided stream. /// </summary> /// <param name="compilation">Compilation that owns the symbol table.</param> /// <param name="assemblyName">Assembly name override, if specified. Otherwise the <see cref="ISymbol.Name"/> of the source assembly is used.</param> /// <param name="xmlDocStream">Stream to which XML will be written, if specified.</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 filterSpanWithinTree is non-null, report diagnostics within this span in the <paramref name="filterTree"/>.</param> public static void WriteDocumentationCommentXml(CSharpCompilation compilation, string assemblyName, Stream xmlDocStream, DiagnosticBag diagnostics, CancellationToken cancellationToken, SyntaxTree filterTree = null, TextSpan? filterSpanWithinTree = null) { StreamWriter writer = null; if (xmlDocStream != null && xmlDocStream.CanWrite) { writer = new StreamWriter( stream: xmlDocStream, encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false), bufferSize: 0x400, // Default. leaveOpen: true); // Don't close caller's stream. } using (writer) { var compiler = new DocumentationCommentCompiler(assemblyName ?? compilation.SourceAssembly.Name, compilation, writer, filterTree, filterSpanWithinTree, processIncludes: true, isForSingleSymbol: false, diagnostics: diagnostics, cancellationToken: cancellationToken); compiler.Visit(compilation.SourceAssembly.GlobalNamespace); Debug.Assert(compiler._indentDepth == 0); } if (filterTree != null) { // Will respect the DocumentationMode. UnprocessedDocumentationCommentFinder.ReportUnprocessed(filterTree, filterSpanWithinTree, diagnostics, cancellationToken); } else { foreach (SyntaxTree tree in compilation.SyntaxTrees) { // Will respect the DocumentationMode. UnprocessedDocumentationCommentFinder.ReportUnprocessed(tree, null, diagnostics, cancellationToken); } } }
public void EmbedAllMembersOfImplementedInterface(CSharpSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { Debug.Assert(UnderlyingNamedType.IsInterfaceType()); if (embeddedAllMembersOfImplementedInterface) { return; } embeddedAllMembersOfImplementedInterface = true; // Embed all members foreach (MethodSymbol m in UnderlyingNamedType.GetMethodsToEmit()) { if ((object)m != null) { TypeManager.EmbedMethod(this, m, syntaxNodeOpt, diagnostics); } } // We also should embed properties and events, but we don't need to do this explicitly here // because accessors embed them automatically. // Do the same for implemented interfaces. foreach (NamedTypeSymbol @interface in UnderlyingNamedType.GetInterfacesToEmit()) { TypeManager.ModuleBeingBuilt.Translate(@interface, syntaxNodeOpt, diagnostics, fromImplements: true); } }
protected override void MethodChecks(DiagnosticBag diagnostics) { var syntax = GetSyntax(); var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntax.SyntaxTree); ParameterListSyntax parameterList = syntax.ParameterList; // 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(parameterList).WithContainingMemberOrLambda(this); SyntaxToken arglistToken; _lazyParameters = ParameterHelpers.MakeParameters(bodyBinder, this, parameterList, true, out arglistToken, diagnostics); _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword); _lazyReturnType = bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax); var location = this.Locations[0]; if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0)) { diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this); } this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams)) { diagnostics.Add(ErrorCode.ERR_BadVarargs, location); } }
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 override BoundStatement BindLockStatementParts(DiagnosticBag diagnostics) { // Allow method groups during binding and then rule them out when we check that the expression has // a reference type. ExpressionSyntax exprSyntax = syntax.Expression; BoundExpression expr = expressionHandler.GetExpression(diagnostics); TypeSymbol exprType = expr.Type; bool hasErrors = false; if ((object)exprType == null) { if (expr.ConstantValue != ConstantValue.Null) // Dev10 allows the null literal. { Error(diagnostics, ErrorCode.ERR_LockNeedsReference, exprSyntax, expr.Display); hasErrors = true; } } else if (!exprType.IsReferenceType) { Error(diagnostics, ErrorCode.ERR_LockNeedsReference, exprSyntax, exprType); hasErrors = true; } BoundStatement stmt = BindPossibleEmbeddedStatement(syntax.Statement, diagnostics); return new BoundLockStatement(syntax, expr, stmt, hasErrors); }
protected override BoundExpression BindRangeVariable(SimpleNameSyntax node, RangeVariableSymbol qv, DiagnosticBag diagnostics) { Debug.Assert(!qv.IsTransparent); BoundExpression translation; ImmutableArray<string> path; if (_rangeVariableMap.TryGetValue(qv, out path)) { if (path.IsEmpty) { // the range variable maps directly to a use of the parameter of that name var value = base.parameterMap[qv.Name]; Debug.Assert(value.Count == 1); translation = new BoundParameter(node, value.Single()) { WasCompilerGenerated = true }; } else { // if the query variable map for this variable is non empty, we always start with the current // lambda's first parameter, which is a transparent identifier. Debug.Assert(base.lambdaSymbol.Parameters[0].Name.StartsWith(transparentIdentifierPrefix)); translation = new BoundParameter(node, base.lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true }; for (int i = path.Length - 1; i >= 0; i--) { var nextField = path[i]; translation = SelectField(node, translation, nextField, diagnostics); translation.WasCompilerGenerated = true; } } return new BoundRangeVariable(node, qv, translation, translation.Type); } return base.BindRangeVariable(node, qv, diagnostics); }
internal void TestOverloadResolutionWithDiff(string source, MetadataReference[] additionalRefs = null) { // The mechanism of this test is: we build the bound tree for the code passed in and then extract // from it the nodes that describe the method symbols. We then compare the description of // the symbols given to the comment that follows the call. var mscorlibRef = new MetadataImageReference(ProprietaryTestResources.NetFX.v4_0_30316_17626.mscorlib.AsImmutableOrNull(), display: "mscorlib"); var references = new[] { mscorlibRef }.Concat(additionalRefs ?? SpecializedCollections.EmptyArray<MetadataReference>()); var compilation = CreateCompilation(source, references, TestOptions.ReleaseDll); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var diagnostics = new DiagnosticBag(); var block = MethodCompiler.BindMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics); var tree = BoundTreeDumperNodeProducer.MakeTree(block); var results = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value) .Where(x => x.Text == "method" && x.Value != null) .Select(x => x.Value) .ToArray()); // var r = string.Join("\n", tree.PreorderTraversal().Select(edge => edge.Value).ToArray(); var expected = string.Join("\n", source .Split(new[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries) .Where(x => x.Contains("//-")) .Select(x => x.Substring(x.IndexOf("//-") + 3)) .ToArray()); AssertEx.Equal(expected, results); }
private void ReportInferenceFailure(DiagnosticBag diagnostics) { var designation = (SingleVariableDesignationSyntax)this.Syntax; Binder.Error( diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, designation.Identifier, designation.Identifier.ValueText); }
internal AsyncMethodToClassRewriter( MethodSymbol method, AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection, SyntheticBoundNodeFactory F, FieldSymbol state, FieldSymbol builder, HashSet<Symbol> variablesCaptured, Dictionary<Symbol, CapturedSymbolReplacement> initialProxies, DiagnosticBag diagnostics, bool generateDebugInfo) : base(F, method, state, variablesCaptured, initialProxies, diagnostics, useFinalizerBookkeeping: false, generateDebugInfo: generateDebugInfo) { this.method = method; this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; this.asyncMethodBuilderField = builder; this.exprReturnLabel = F.GenerateLabel("exprReturn"); this.exitLabel = F.GenerateLabel("exitLabel"); this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation) ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName()) : null; this.dynamicFactory = new LoweredDynamicOperationFactory(F); }
internal SynthesizedInteractiveInitializerMethod(SourceMemberContainerTypeSymbol containingType, DiagnosticBag diagnostics) { Debug.Assert(containingType.IsScriptClass); _containingType = containingType; CalculateReturnType(containingType.DeclaringCompilation, diagnostics, out _resultType, out _returnType); }
private BoundExpression SelectField(SimpleNameSyntax node, BoundExpression receiver, string name, DiagnosticBag diagnostics) { var receiverType = receiver.Type as NamedTypeSymbol; if ((object)receiverType == null || !receiverType.IsAnonymousType) { // We only construct transparent query variables using anonymous types, so if we're trying to navigate through // some other type, we must have some hinky query API where the types don't match up as expected. // We should report this as an error of some sort. // TODO: DevDiv #737822 - reword error message and add test. var info = new CSDiagnosticInfo(ErrorCode.ERR_UnsupportedTransparentIdentifierAccess, name, receiver.ExpressionSymbol ?? receiverType); Error(diagnostics, info, node); return new BoundBadExpression( node, LookupResultKind.Empty, ImmutableArray.Create<Symbol>(receiver.ExpressionSymbol), ImmutableArray.Create<BoundNode>(receiver), new ExtendedErrorTypeSymbol(this.Compilation, "", 0, info)); } LookupResult lookupResult = LookupResult.GetInstance(); LookupOptions options = LookupOptions.MustBeInstance; HashSet<DiagnosticInfo> useSiteDiagnostics = null; LookupMembersWithFallback(lookupResult, receiver.Type, name, 0, ref useSiteDiagnostics, basesBeingResolved: null, options: options); diagnostics.Add(node, useSiteDiagnostics); var result = BindMemberOfType(node, node, name, 0, receiver, default(SeparatedSyntaxList<TypeSyntax>), default(ImmutableArray<TypeSymbol>), lookupResult, BoundMethodGroupFlags.None, diagnostics); result.WasCompilerGenerated = true; lookupResult.Free(); return result; }
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; }
/// <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; }
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) { _name = name; _isExpressionBodied = isExpressionBodied; // @t-mawind (is this a good idea?) var defaultAccess = (ContainingType.IsInstance || ContainingType.IsConcept) ? DeclarationModifiers.Public : 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); if (ContainingType.IsConcept) { // @t-mawind Is there any easier way of doing this? declarationModifiers |= DeclarationModifiers.Abstract; } // 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.MakeFlags(methodKind, declarationModifiers, returnsVoid: false, isExtensionMethod: false); if (this.ContainingType.IsInterface && !this.ContainingType.IsConcept) { // 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; } // @t-mawind // If we're in a concept instance, then operators must be public and // _non_ -static. if (ContainingType.IsInstance || ContainingType.IsConcept) { if (DeclaredAccessibility != Accessibility.Public || IsStatic) { // CS4038: User-defined concept operator '...' must be declared non-static and public. diagnostics.Add(ErrorCode.ERR_ConceptOperatorsMustBeNonStatic, Locations[0], this); } } else { // 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); } }
private ImmutableArray <Symbol> BindIndexerMemberCref(IndexerMemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { const int arity = 0; ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, WellKnownMemberNames.Indexer, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } // Since only indexers are named WellKnownMemberNames.Indexer. Debug.Assert(sortedSymbols.All(SymbolExtensions.IsIndexer)); // NOTE: guaranteed to be a property, because only indexers are considered. return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: null, parameterListSyntax: syntax.Parameters, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
private ImmutableArray <Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { SimpleNameSyntax nameSyntax = syntax.Name as SimpleNameSyntax; int arity; string memberName; if (nameSyntax != null) { arity = nameSyntax.Arity; memberName = nameSyntax.Identifier.ValueText; } else { // If the name isn't a SimpleNameSyntax, then we must have a type name followed by a parameter list. // Thus, we're looking for a constructor. Debug.Assert((object)containerOpt == null); // Could be an error type, but we'll just lookup fail below. containerOpt = BindNamespaceOrTypeSymbolInCref(syntax.Name); arity = 0; memberName = WellKnownMemberNames.InstanceConstructorName; } if (string.IsNullOrEmpty(memberName)) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: arity == 0 ? null : ((GenericNameSyntax)nameSyntax).TypeArgumentList, parameterListSyntax: syntax.Parameters, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
internal ImmutableArray <Symbol> BindCref(CrefSyntax syntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { ImmutableArray <Symbol> symbols = BindCrefInternal(syntax, out ambiguityWinner, diagnostics); Debug.Assert(!symbols.IsDefault, "Prefer empty to null."); Debug.Assert((symbols.Length > 1) == ((object)ambiguityWinner != null), "ambiguityWinner should be set iff more than one symbol is returned."); return(symbols); }
private ImmutableArray <Symbol> BindMemberCref(MemberCrefSyntax syntax, NamespaceOrTypeSymbol containerOpt, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { if ((object)containerOpt != null && containerOpt.Kind == SymbolKind.TypeParameter) { // As in normal lookup (see CreateErrorIfLookupOnTypeParameter), you can't dot into a type parameter // (though you can dot into an expression of type parameter type). CrefSyntax crefSyntax = GetRootCrefSyntax(syntax); var noTrivia = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null); diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString()); ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } ImmutableArray <Symbol> result; switch (syntax.Kind()) { case SyntaxKind.NameMemberCref: result = BindNameMemberCref((NameMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.IndexerMemberCref: result = BindIndexerMemberCref((IndexerMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.OperatorMemberCref: result = BindOperatorMemberCref((OperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.ConversionOperatorMemberCref: result = BindConversionOperatorMemberCref((ConversionOperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; default: throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); } if (!result.Any()) { CrefSyntax crefSyntax = GetRootCrefSyntax(syntax); var noTrivia = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null); diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString()); } return(result); }
internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics) { // Check constraints on return type and parameters. Note: Dev10 uses the // method name location for any such errors. We'll do the same for return // type errors but for parameter errors, we'll use the parameter location. this.ReturnType.CheckAllConstraints(conversions, this.Locations[0], diagnostics); foreach (var parameter in this.Parameters) { parameter.Type.CheckAllConstraints(conversions, parameter.Locations[0], diagnostics); } }
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: otherwise, 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.TupleUnderlyingTypeOrSelf() != this.ContainingType && target.TupleUnderlyingTypeOrSelf() != 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: // Excluding 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-intuitive 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, ignoreDynamicAndTupleNames: 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, ignoreDynamicAndTupleNames: 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); } }
protected sealed override TAttributeData PortAttributeIfNeedTo(TAttributeData attrData, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { // Note, when porting attributes, we are not using constructors from original symbol. // The constructors might be missing (for example, in metadata case) and doing lookup // will ensure that we report appropriate errors. if (TypeManager.IsTargetAttribute(UnderlyingMethod, attrData, AttributeDescription.LCIDConversionAttribute)) { if (attrData.CommonConstructorArguments.Length == 1) { return(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_LCIDConversionAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); } } return(null); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), location)); }
internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData) { Debug.Assert(!boundAttributes.IsDefault); Debug.Assert(!allAttributeSyntaxNodes.IsDefault); Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length); Debug.Assert(_lazyCustomAttributesBag != null); Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed); Debug.Assert(symbolPart == AttributeLocation.None); var data = (CommonFieldWellKnownAttributeData)decodedData; int?fieldOffset = data != null ? data.Offset : null; if (fieldOffset.HasValue) { if (this.ContainingType.Layout.Kind != LayoutKind.Explicit) { Debug.Assert(boundAttributes.Any()); // error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) int i = boundAttributes.IndexOfAttribute(this, AttributeDescription.FieldOffsetAttribute); diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadStruct, allAttributeSyntaxNodes[i].Name.Location); } } else if (!this.IsStatic && !this.IsConst) { if (this.ContainingType.Layout.Kind == LayoutKind.Explicit) { // error CS0625: '<field>': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute diagnostics.Add(ErrorCode.ERR_MissingStructOffset, this.ErrorLocation, this.AttributeOwner); } } base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax, params object[] args) { Error(diagnostics, code, syntax.GetLocation(), args); }
internal static void ReportDiagnosticsIfObsolete( DiagnosticBag diagnostics, Symbol symbol, SyntaxNodeOrToken node, bool hasBaseReceiver, Symbol containingMember, NamedTypeSymbol containingType, BinderFlags location) { Debug.Assert((object)symbol != null); Debug.Assert(symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Event || symbol.Kind == SymbolKind.Property); // Dev11 also reports on the unconstructed method. It would be nice to report on // the constructed method, but then we wouldn't be able to walk the override chain. if (symbol.Kind == SymbolKind.Method) { symbol = ((MethodSymbol)symbol).ConstructedFrom; } // There are two reasons to walk up to the least-overridden member: // 1) That's the method to which we will actually emit a call. // 2) We don't know what virtual dispatch will do at runtime so an // overriding member is basically a shot in the dark. Better to // just be consistent and always use the least-overridden member. Symbol leastOverriddenSymbol = symbol.GetLeastOverriddenMember(containingType); bool checkOverridingSymbol = hasBaseReceiver && !ReferenceEquals(symbol, leastOverriddenSymbol); if (checkOverridingSymbol) { // If we have a base receiver, we must be done with declaration binding, so it should // be safe to decode diagnostics. We want to do this since reporting for the overriding // member is conditional on reporting for the overridden member (i.e. we need a definite // answer so we don't double-report). You might think that double reporting just results // in cascading diagnostics, but it's possible that the second diagnostic is an error // while the first is merely a warning. leastOverriddenSymbol.GetAttributes(); } ThreeState reportedOnOverridden = ReportDiagnosticsIfObsoleteInternal(diagnostics, leastOverriddenSymbol, node, containingMember, location); // CONSIDER: In place of hasBaseReceiver, dev11 also accepts cases where symbol.ContainingType is a "simple type" (e.g. int) // or a special by-ref type (e.g. ArgumentHandle). These cases are probably more important for other checks performed by // ExpressionBinder::PostBindMethod, but they do appear to ObsoleteAttribute as well. We're skipping them because they // don't make much sense for ObsoleteAttribute (e.g. this would seem to address the case where int.ToString has been made // obsolete but object.ToString has not). // If the overridden member was not definitely obsolete and this is a (non-virtual) base member // access, then check the overriding symbol as well. if (reportedOnOverridden != ThreeState.True && checkOverridingSymbol) { Debug.Assert(reportedOnOverridden != ThreeState.Unknown, "We forced attribute binding above."); ReportDiagnosticsIfObsoleteInternal(diagnostics, symbol, node, containingMember, location); } }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), token.GetLocation())); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, Location location) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), location)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax, params object[] args) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code, args), syntax.Location)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax) { Error(diagnostics, code, syntax.GetLocation()); }
internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, Location location) { diagnostics.Add(new CSDiagnostic(info, location)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, SyntaxToken token) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), token.GetLocation())); }
/// <summary> /// Get the element type of this iterator. /// </summary> /// <param name="node">Node to report diagnostics, if any, such as "yield statement cannot be used /// inside a lambda expression"</param> /// <param name="diagnostics">Where to place any diagnostics</param> /// <returns>Element type of the current iterator, or an error type.</returns> internal virtual TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics) { return(Next.GetIteratorElementType(node, diagnostics)); }
internal static void Error(DiagnosticBag diagnostics, ErrorCode code, CSharpSyntaxNode syntax) { diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(code), syntax.Location)); }
/// <summary> /// Finds the GetResult method of an Awaiter type. /// </summary> /// <remarks> /// Spec 7.7.7.1: /// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters. /// </remarks> private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out MethodSymbol getResultMethod, out BoundExpression getAwaiterGetResultCall) { var awaiterType = awaiterExpression.Type; getAwaiterGetResultCall = MakeInvocationExpression(node, awaiterExpression, WellKnownMemberNames.GetResult, ImmutableArray <BoundExpression> .Empty, diagnostics); if (getAwaiterGetResultCall.HasAnyErrors) { getResultMethod = null; getAwaiterGetResultCall = null; return(false); } if (getAwaiterGetResultCall.Kind != BoundKind.Call) { Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult); getResultMethod = null; getAwaiterGetResultCall = null; return(false); } getResultMethod = ((BoundCall)getAwaiterGetResultCall).Method; if (getResultMethod.IsExtensionMethod) { Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult); getResultMethod = null; getAwaiterGetResultCall = null; return(false); } if (HasOptionalOrVariableParameters(getResultMethod) || getResultMethod.IsConditional) { Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType); getResultMethod = null; getAwaiterGetResultCall = null; return(false); } // The lack of a GetResult method will be reported by ValidateGetResult(). return(true); }
internal static void Error(DiagnosticBag diagnostics, DiagnosticInfo info, CSharpSyntaxNode syntax) { diagnostics.Add(new CSDiagnostic(info, syntax.Location)); }
internal void ReportBadAwaitDiagnostics(SyntaxNode node, Location location, DiagnosticBag diagnostics, ref bool hasErrors) { hasErrors |= ReportBadAwaitWithoutAsync(location, diagnostics); hasErrors |= ReportBadAwaitContext(node, location, diagnostics); }
internal BoundAwaitableInfo BindAwaitInfo(BoundAwaitableValuePlaceholder placeholder, SyntaxNode node, DiagnosticBag diagnostics, ref bool hasErrors, BoundExpression expressionOpt = null) { bool hasGetAwaitableErrors = !GetAwaitableExpressionInfo( expressionOpt ?? placeholder, placeholder, out bool isDynamic, out BoundExpression getAwaiter, out PropertySymbol isCompleted, out MethodSymbol getResult, getAwaiterGetResultCall: out _, node, diagnostics); hasErrors |= hasGetAwaitableErrors; return(new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, hasErrors: hasGetAwaitableErrors) { WasCompilerGenerated = true }); }
/// <summary> /// Finds the GetAwaiter method of an awaitable expression. /// </summary> /// <remarks> /// Spec 7.7.7.1: /// An awaitable expression t has an accessible instance or extension method called GetAwaiter with no /// parameters and no type parameters, and a return type A that meets the additional requirements for an /// Awaiter. /// NOTE: this is an error in the spec. An extension method of the form /// Awaiter<T> GetAwaiter<T>(this Task<T>) may be used. /// </remarks> private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics, out BoundExpression getAwaiterCall) { if (expression.Type.IsVoidType()) { Error(diagnostics, ErrorCode.ERR_BadAwaitArgVoidCall, node); getAwaiterCall = null; return(false); } getAwaiterCall = MakeInvocationExpression(node, expression, WellKnownMemberNames.GetAwaiter, ImmutableArray <BoundExpression> .Empty, diagnostics); if (getAwaiterCall.HasAnyErrors) // && !expression.HasAnyErrors? { getAwaiterCall = null; return(false); } if (getAwaiterCall.Kind != BoundKind.Call) { Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type); getAwaiterCall = null; return(false); } var getAwaiterMethod = ((BoundCall)getAwaiterCall).Method; if (getAwaiterMethod is ErrorMethodSymbol || HasOptionalOrVariableParameters(getAwaiterMethod) || // We might have been able to resolve a GetAwaiter overload with optional parameters, so check for that here getAwaiterMethod.ReturnsVoid) // If GetAwaiter returns void, don't bother checking that it returns an Awaiter. { Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type); getAwaiterCall = null; return(false); } return(true); }
/// <summary> /// Checks that the Awaiter implements System.Runtime.CompilerServices.INotifyCompletion. /// </summary> /// <remarks> /// Spec 7.7.7.1: /// An Awaiter A implements the interface System.Runtime.CompilerServices.INotifyCompletion. /// </remarks> private bool AwaiterImplementsINotifyCompletion(TypeSymbol awaiterType, SyntaxNode node, DiagnosticBag diagnostics) { var INotifyCompletion = GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion, diagnostics, node); HashSet <DiagnosticInfo> useSiteDiagnostics = null; var conversion = this.Conversions.ClassifyImplicitConversionFromType(awaiterType, INotifyCompletion, ref useSiteDiagnostics); if (!conversion.IsImplicit) { diagnostics.Add(node, useSiteDiagnostics); Error(diagnostics, ErrorCode.ERR_DoesntImplementAwaitInterface, node, awaiterType, INotifyCompletion); return(false); } Debug.Assert(conversion.IsValid); return(true); }
private BoundAwaitExpression BindAwait(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics) { bool hasErrors = false; var placeholder = new BoundAwaitableValuePlaceholder(expression.Syntax, GetValEscape(expression, LocalScopeDepth), expression.Type); ReportBadAwaitDiagnostics(node, node.Location, diagnostics, ref hasErrors); var info = BindAwaitInfo(placeholder, node, diagnostics, ref hasErrors, expressionOpt: expression); // Spec 7.7.7.2: // The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Thus, // if the return type of GetResult is void, the await-expression is classified as nothing. If it has a // non-void return type T, the await-expression is classified as a value of type T. TypeSymbol awaitExpressionType = info.GetResult?.ReturnType ?? (hasErrors ? CreateErrorType() : Compilation.DynamicType); return(new BoundAwaitExpression(node, expression, info, awaitExpressionType, hasErrors)); }
/// <summary> /// Finds the IsCompleted property of an Awaiter type. /// </summary> /// <remarks> /// Spec 7.7.7.1: /// An Awaiter A has an accessible, readable instance property IsCompleted of type bool. /// </remarks> private bool GetIsCompletedProperty(TypeSymbol awaiterType, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out PropertySymbol isCompletedProperty) { var receiver = new BoundLiteral(node, ConstantValue.Null, awaiterType); var name = WellKnownMemberNames.IsCompleted; var qualified = BindInstanceMemberAccess(node, node, receiver, name, 0, default(SeparatedSyntaxList <TypeSyntax>), default(ImmutableArray <TypeWithAnnotations>), invoked: false, indexed: false, diagnostics); if (qualified.HasAnyErrors) { isCompletedProperty = null; return(false); } if (qualified.Kind != BoundKind.PropertyAccess) { Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.IsCompleted); isCompletedProperty = null; return(false); } isCompletedProperty = ((BoundPropertyAccess)qualified).PropertySymbol; if (isCompletedProperty.IsWriteOnly) { Error(diagnostics, ErrorCode.ERR_PropertyLacksGet, node, isCompletedProperty); isCompletedProperty = null; return(false); } if (isCompletedProperty.Type.SpecialType != SpecialType.System_Boolean) { Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType); isCompletedProperty = null; return(false); } return(true); }
private BoundExpression BindAwait(AwaitExpressionSyntax node, DiagnosticBag diagnostics) { BoundExpression expression = BindRValueWithoutTargetType(node.Expression, diagnostics); return(BindAwait(expression, node, diagnostics)); }
/// <summary> /// Validates the awaited expression, returning true if no errors are found. /// </summary> private static bool ValidateAwaitedExpression(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics) { if (expression.HasAnyErrors) { // The appropriate diagnostics have already been reported. return(false); } if ((object)expression.Type == null) { Error(diagnostics, ErrorCode.ERR_BadAwaitArgIntrinsic, node, expression.Display); return(false); } return(true); }