public override void DefaultVisit(SyntaxNode node) { SyntaxKind nodeKind = node.CSharpKind(); bool diagnose = node.SyntaxTree.ReportDocumentationCommentDiagnostics(); if (nodeKind == SyntaxKind.XmlCrefAttribute) { XmlCrefAttributeSyntax crefAttr = (XmlCrefAttributeSyntax)node; CrefSyntax cref = crefAttr.Cref; BinderFactory factory = compilation.GetBinderFactory(cref.SyntaxTree); Binder binder = factory.GetBinder(cref); // Do this for the diagnostics, even if it won't be written. DiagnosticBag crefDiagnostics = DiagnosticBag.GetInstance(); string docCommentId = GetDocumentationCommentId(cref, binder, crefDiagnostics); if (diagnose) { diagnostics.AddRange(crefDiagnostics); } crefDiagnostics.Free(); if (writer != null) { Visit(crefAttr.Name); VisitToken(crefAttr.EqualsToken); // Not going to visit normally, because we want to skip trivia within // the attribute value. crefAttr.StartQuoteToken.WriteTo(writer, leading: true, trailing: false); // We're not going to visit the cref because we want to bind it // and write a doc comment ID in its place. writer.Write(docCommentId); // Not going to visit normally, because we want to skip trivia within // the attribute value. crefAttr.EndQuoteToken.WriteTo(writer, leading: false, trailing: true); } // Don't descend - we've already written out everything necessary. return; } else if (diagnose && nodeKind == SyntaxKind.XmlNameAttribute) { XmlNameAttributeSyntax nameAttr = (XmlNameAttributeSyntax)node; BinderFactory factory = compilation.GetBinderFactory(nameAttr.SyntaxTree); Binder binder = factory.GetBinder(nameAttr, nameAttr.Identifier.SpanStart); // Do this for diagnostics, even if we aren't writing. BindName(nameAttr, binder, memberSymbol, ref documentedParameters, ref documentedTypeParameters, diagnostics); // Do descend - we still need to write out the tokens of the attribute. } // NOTE: if we're recording any include element nodes (i.e. if includeElementsNodes is non-null), // then we want to record all of them, because we won't be able to distinguish in the XML DOM. if (includeElementNodes != null) { XmlNameSyntax nameSyntax = null; if (nodeKind == SyntaxKind.XmlEmptyElement) { nameSyntax = ((XmlEmptyElementSyntax)node).Name; } else if (nodeKind == SyntaxKind.XmlElementStartTag) { nameSyntax = ((XmlElementStartTagSyntax)node).Name; } if (nameSyntax != null && nameSyntax.Prefix == null && DocumentationCommentXmlNames.ElementEquals(nameSyntax.LocalName.ValueText, DocumentationCommentXmlNames.IncludeElementName)) { includeElementNodes.Add((CSharpSyntaxNode)node); } } base.DefaultVisit(node); }
/// <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, RefKind.None, trailingExpression)); block = new BoundBlock(block.Syntax, ImmutableArray <LocalSymbol> .Empty, ImmutableArray <LocalFunctionSymbol> .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 sealed override TypeSymbolWithAnnotations GetFieldType(ConsList <FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if (!_lazyType.IsNull) { return(_lazyType.ToType()); } var declarator = VariableDeclaratorNode; var fieldSyntax = GetFieldDeclaration(declarator); var typeSyntax = fieldSyntax.Declaration.Type; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbolWithAnnotations type; // When we have multiple declarators, we report the type diagnostics on only the first. DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance(); Symbol associatedPropertyOrEvent = this.AssociatedSymbol; if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event) { EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T> // type that has additional generic constraints? type = TypeSymbolWithAnnotations.Create(tokenTableType.Construct(ImmutableArray.Create(@event.Type))); } else { type = @event.Type; } } else { var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); binder = binder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); if (!ContainingType.IsScriptClass) { type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator); } else { bool isVar; type = binder.BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar); Debug.Assert(!type.IsNull || isVar); if (isVar) { if (this.IsConst) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location); } if (fieldsBeingBound.ContainsReference(this)) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this); type = default; } else if (fieldSyntax.Declaration.Variables.Count > 1) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location); } else if (this.IsConst && this.ContainingType.IsScriptClass) { // For const var in script, we won't try to bind the initializer (case below), as it can lead to an unbound recursion type = default; } else { fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound); var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound); var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind.None, (EqualsValueClauseSyntax)declarator.Initializer, declarator); if (initializerOpt != null) { if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType()) { type = TypeSymbolWithAnnotations.Create(initializerOpt.Type); } _lazyFieldTypeInferred = 1; } } if (type.IsNull) { type = TypeSymbolWithAnnotations.Create(binder.CreateErrorType("var")); } } } if (IsFixedSizeBuffer) { type = TypeSymbolWithAnnotations.Create(new PointerTypeSymbol(type)); if (ContainingType.TypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation); } var elementType = ((PointerTypeSymbol)type.TypeSymbol).PointedAtType.TypeSymbol; int elementSize = elementType.FixedBufferElementSizeInBytes(); if (elementSize == 0) { var loc = typeSyntax.Location; diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc); } if (!binder.InUnsafeRegion) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location); } } } // update the lazyType only if it contains value last seen by the current thread: if (_lazyType.InterlockedInitialize(type.WithModifiers(this.RequiredCustomModifiers))) { TypeChecks(type.TypeSymbol, diagnostics); // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics. compilation.DeclarationDiagnostics.AddRange(diagnostics); bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator; if (isFirstDeclarator) { compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator); } state.NotePartComplete(CompletionPart.Type); } diagnostics.Free(); diagnosticsForFirstDeclarator.Free(); return(_lazyType.ToType()); }
private ConcurrentSet <AssemblySymbol>?GetCompleteSetOfUsedAssemblies(CancellationToken cancellationToken) { if (!_usedAssemblyReferencesFrozen && !Volatile.Read(ref _usedAssemblyReferencesFrozen)) { var diagnostics = new BindingDiagnosticBag(DiagnosticBag.GetInstance(), new ConcurrentSet <AssemblySymbol>()); RoslynDebug.Assert(diagnostics.DiagnosticBag is object); GetDiagnosticsWithoutFiltering(CompilationStage.Declare, includeEarlierStages: true, diagnostics, cancellationToken); bool seenErrors = diagnostics.HasAnyErrors(); if (!seenErrors) { diagnostics.DiagnosticBag.Clear(); GetDiagnosticsForAllMethodBodies(diagnostics, doLowering: true, cancellationToken); seenErrors = diagnostics.HasAnyErrors(); if (!seenErrors) { AddUsedAssemblies(diagnostics.DependenciesBag); } } completeTheSetOfUsedAssemblies(seenErrors, cancellationToken); diagnostics.DiagnosticBag.Free(); } return(_lazyUsedAssemblyReferences); void addUsedAssembly(AssemblySymbol dependency, ArrayBuilder <AssemblySymbol> stack) { if (AddUsedAssembly(dependency)) { stack.Push(dependency); } } void addReferencedAssemblies(AssemblySymbol assembly, bool includeMainModule, ArrayBuilder <AssemblySymbol> stack) { for (int i = (includeMainModule ? 0 : 1); i < assembly.Modules.Length; i++) { foreach (var dependency in assembly.Modules[i].ReferencedAssemblySymbols) { addUsedAssembly(dependency, stack); } } } void completeTheSetOfUsedAssemblies(bool seenErrors, CancellationToken cancellationToken) { if (_usedAssemblyReferencesFrozen || Volatile.Read(ref _usedAssemblyReferencesFrozen)) { return; } if (seenErrors) { // Add all referenced assemblies foreach (var assembly in SourceModule.ReferencedAssemblySymbols) { AddUsedAssembly(assembly); } } else { // Assume that all assemblies used by the added modules are also used for (int i = 1; i < SourceAssembly.Modules.Length; i++) { foreach (var dependency in SourceAssembly.Modules[i].ReferencedAssemblySymbols) { AddUsedAssembly(dependency); } } if (_usedAssemblyReferencesFrozen || Volatile.Read(ref _usedAssemblyReferencesFrozen)) { return; } // Assume that all assemblies used by the used assemblies are also used // This, for example, takes care of including facade assemblies that forward types around. if (_lazyUsedAssemblyReferences is object) { lock (_lazyUsedAssemblyReferences) { if (_usedAssemblyReferencesFrozen || Volatile.Read(ref _usedAssemblyReferencesFrozen)) { return; } var stack = ArrayBuilder <AssemblySymbol> .GetInstance(_lazyUsedAssemblyReferences.Count); stack.AddRange(_lazyUsedAssemblyReferences); while (stack.Count != 0) { AssemblySymbol current = stack.Pop(); ConcurrentSet <AssemblySymbol>?usedAssemblies; switch (current) { case SourceAssemblySymbol sourceAssembly: // The set of assemblies used by the referenced compilation feels like // a reasonable approximation to the set of assembly references that would // be emitted into the resulting binary for that compilation. An alternative // would be to attempt to emit and get the exact set of emitted references // in case of success. This might be too slow though. usedAssemblies = sourceAssembly.DeclaringCompilation.GetCompleteSetOfUsedAssemblies(cancellationToken); if (usedAssemblies is object) { foreach (AssemblySymbol dependency in usedAssemblies) { Debug.Assert(!dependency.IsLinked); addUsedAssembly(dependency, stack); } } break; case RetargetingAssemblySymbol retargetingAssembly: usedAssemblies = retargetingAssembly.UnderlyingAssembly.DeclaringCompilation.GetCompleteSetOfUsedAssemblies(cancellationToken); if (usedAssemblies is object) { foreach (AssemblySymbol underlyingDependency in retargetingAssembly.UnderlyingAssembly.SourceModule.ReferencedAssemblySymbols) { if (!underlyingDependency.IsLinked && usedAssemblies.Contains(underlyingDependency)) { AssemblySymbol dependency; if (!((RetargetingModuleSymbol)retargetingAssembly.Modules[0]).RetargetingDefinitions(underlyingDependency, out dependency)) { Debug.Assert(retargetingAssembly.Modules[0].ReferencedAssemblySymbols.Contains(underlyingDependency)); dependency = underlyingDependency; } addUsedAssembly(dependency, stack); } } } addReferencedAssemblies(retargetingAssembly, includeMainModule: false, stack); break; default: addReferencedAssemblies(current, includeMainModule: true, stack); break; } } stack.Free(); } } if (SourceAssembly.CorLibrary is object) { // Add core library AddUsedAssembly(SourceAssembly.CorLibrary); } } _usedAssemblyReferencesFrozen = true; } }
/// <remarks> /// This method boils down to Rewrite(XDocument.Load(fileAttrValue).XPathSelectElements(pathAttrValue)). /// Everything else is error handling. /// </remarks> private XNode[] RewriteIncludeElement(XElement includeElement, string currentXmlFilePath, CSharpSyntaxNode originatingSyntax, out string commentMessage) { Location location = GetIncludeElementLocation(includeElement, ref currentXmlFilePath, ref originatingSyntax); Debug.Assert(originatingSyntax != null); bool diagnose = originatingSyntax.SyntaxTree.ReportDocumentationCommentDiagnostics(); if (!EnterIncludeElement(location)) { // NOTE: these must exist since we're already processed this node elsewhere in the call stack. XAttribute fileAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName)); XAttribute pathAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName)); string filePathValue = fileAttr.Value; string xpathValue = pathAttr.Value; if (diagnose) { _diagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new LocalizableErrorArgument(MessageID.IDS_OperationCausedStackOverflow)); } commentMessage = ErrorFacts.GetMessage(MessageID.IDS_XMLNOINCLUDE, CultureInfo.CurrentUICulture); // Don't inspect the children - we're already in a cycle. return(new XNode[] { new XComment(commentMessage), includeElement.Copy(copyAttributeAnnotations: false) }); } DiagnosticBag includeDiagnostics = DiagnosticBag.GetInstance(); try { XAttribute fileAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName)); XAttribute pathAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName)); bool hasFileAttribute = fileAttr != null; bool hasPathAttribute = pathAttr != null; if (!hasFileAttribute || !hasPathAttribute) { var subMessage = hasFileAttribute ? MessageID.IDS_XMLMISSINGINCLUDEPATH.Localize() : MessageID.IDS_XMLMISSINGINCLUDEFILE.Localize(); includeDiagnostics.Add(ErrorCode.WRN_InvalidInclude, location, subMessage); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLBADINCLUDE); return(null); } string xpathValue = pathAttr.Value; string filePathValue = fileAttr.Value; var resolver = _compilation.Options.XmlReferenceResolver; if (resolver == null) { includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.XmlReferencesNotSupported))); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } string resolvedFilePath = resolver.ResolveReference(filePathValue, currentXmlFilePath); if (resolvedFilePath == null) { // NOTE: same behavior as IOException. includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.FileNotFound))); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } if (_includedFileCache == null) { _includedFileCache = new DocumentationCommentIncludeCache(resolver); } try { XDocument doc; try { doc = _includedFileCache.GetOrMakeDocument(resolvedFilePath); } catch (IOException e) { // NOTE: same behavior as resolvedFilePath == null. includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, e.Message); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } Debug.Assert(doc != null); string errorMessage; bool invalidXPath; XElement[] loadedElements = XmlUtilities.TrySelectElements(doc, xpathValue, out errorMessage, out invalidXPath); if (loadedElements == null) { includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, errorMessage); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); if (invalidXPath) { // leave the include node as is return(null); } if (location.IsInSource) { // As in Dev11, return only the comment - drop the include element. return(new XNode[] { new XComment(commentMessage) }); } else { commentMessage = null; return(Array.Empty <XNode>()); } } if (loadedElements != null && loadedElements.Length > 0) { // change the current XML file path for nodes contained in the document: XNode[] result = RewriteMany(loadedElements, resolvedFilePath, originatingSyntax); // The elements could be rewritten away if they are includes that refer to invalid // (but existing and accessible) XML files. If this occurs, behave as if we // had failed to find any XPath results (as in Dev11). if (result.Length > 0) { // NOTE: in this case, we do NOT visit the children of the include element - // they are dropped. commentMessage = null; return(result); } } commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLNOINCLUDE); return(null); } catch (XmlException e) { // NOTE: invalid XML is handled differently from other errors - we don't include the include element // in the results and the location is in the included (vs includING) file. Location errorLocation = XmlLocation.Create(e, resolvedFilePath); includeDiagnostics.Add(ErrorCode.WRN_XMLParseIncludeError, errorLocation, GetDescription(e)); //NOTE: location is in included file. if (location.IsInSource) { commentMessage = string.Format(ErrorFacts.GetMessage(MessageID.IDS_XMLIGNORED2, CultureInfo.CurrentUICulture), resolvedFilePath); // As in Dev11, return only the comment - drop the include element. return(new XNode[] { new XComment(commentMessage) }); } else { commentMessage = null; return(Array.Empty <XNode>()); } } } finally { if (diagnose) { _diagnostics.AddRange(includeDiagnostics); } includeDiagnostics.Free(); LeaveIncludeElement(location); } }
internal override CompileResult CompileAssignment( InspectionContext inspectionContext, string target, string expr, DiagnosticFormatter formatter, out ResultProperties resultProperties, out string error, out ImmutableArray <AssemblyIdentity> missingAssemblyIdentities, System.Globalization.CultureInfo preferredUICulture, Microsoft.CodeAnalysis.CodeGen.CompilationTestData testData) { var diagnostics = DiagnosticBag.GetInstance(); try { var assignment = target.ParseAssignment(expr, diagnostics); if (assignment == null) { error = GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, out missingAssemblyIdentities); resultProperties = default(ResultProperties); return(default(CompileResult)); } var context = this.CreateCompilationContext(assignment); ResultProperties properties; var moduleBuilder = context.CompileAssignment(inspectionContext, TypeName, MethodName, testData, diagnostics, out properties); if (moduleBuilder == null) { error = GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, out missingAssemblyIdentities); resultProperties = default(ResultProperties); return(default(CompileResult)); } using (var stream = new MemoryStream()) { Cci.PeWriter.WritePeToStream( new EmitContext((Cci.IModule)moduleBuilder, null, diagnostics), context.MessageProvider, () => stream, nativePdbWriterOpt: null, allowMissingMethodBodies: false, deterministic: false, cancellationToken: default(CancellationToken)); if (diagnostics.HasAnyErrors()) { error = GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, out missingAssemblyIdentities); resultProperties = default(ResultProperties); return(default(CompileResult)); } resultProperties = properties; error = null; missingAssemblyIdentities = ImmutableArray <AssemblyIdentity> .Empty; return(new CompileResult( stream.ToArray(), typeName: TypeName, methodName: MethodName, formatSpecifiers: null)); } } finally { diagnostics.Free(); } }
public void AliasElement() { var source = @"class C { static (int, int) F; static void M() { } }"; var comp = CreateCompilationWithMscorlib40(source, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugDll); WithRuntimeInstance(comp, new[] { ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef }, runtime => { var context = CreateMethodContext( runtime, "C.M"); // (int A, (int, int D) B)[] t; var aliasElementNames = new ReadOnlyCollection <string>(new[] { "A", "B", null, "D" }); var alias = new Alias( DkmClrAliasKind.Variable, "t", "t", "System.ValueTuple`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.ValueTuple`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]][], System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51", CustomTypeInfo.PayloadTypeId, CustomTypeInfo.Encode(null, aliasElementNames)); var locals = ArrayBuilder <LocalAndMethod> .GetInstance(); string typeName; var diagnostics = DiagnosticBag.GetInstance(); var testData = new CompilationTestData(); var assembly = context.CompileGetLocals( locals, argumentsOnly: false, aliases: ImmutableArray.Create(alias), diagnostics: diagnostics, typeName: out typeName, testData: testData); diagnostics.Verify(); diagnostics.Free(); Assert.Equal(1, locals.Count); ReadOnlyCollection <byte> customTypeInfo; var customTypeInfoId = locals[0].GetCustomTypeInfo(out customTypeInfo); ReadOnlyCollection <byte> dynamicFlags; ReadOnlyCollection <string> tupleElementNames; CustomTypeInfo.Decode(customTypeInfoId, customTypeInfo, out dynamicFlags, out tupleElementNames); Assert.Equal(aliasElementNames, tupleElementNames); var method = (MethodSymbol)testData.GetExplicitlyDeclaredMethods().Single().Value.Method; CheckAttribute(assembly, method, AttributeDescription.TupleElementNamesAttribute, expected: true); var returnType = (TypeSymbol)method.ReturnType; Assert.False(returnType.IsTupleType); Assert.True(((ArrayTypeSymbol)returnType).ElementType.IsTupleType); VerifyLocal(testData, typeName, locals[0], "<>m0", "t", expectedILOpt: @"{ // Code size 16 (0x10) .maxstack 1 IL_0000: ldstr ""t"" IL_0005: call ""object Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetObjectByAlias(string)"" IL_000a: castclass ""System.ValueTuple<int, System.ValueTuple<int, int>>[]"" IL_000f: ret }"); locals.Free(); }); }
public void NullableConversionFromFloatingPointConst() { var source = @" class C { void Use(int? p) { } void Test() { int? i; // double checks i = (int?)3.5d; i = (int?)double.MaxValue; i = (int?)double.NaN; i = (int?)double.NegativeInfinity; i = (int?)double.PositiveInfinity; // float checks i = (int?)3.5d; i = (int?)float.MaxValue; i = (int?)float.NaN; i = (int?)float.NegativeInfinity; i = (int?)float.PositiveInfinity; Use(i); unchecked { // double checks i = (int?)3.5d; i = (int?)double.MaxValue; i = (int?)double.NaN; i = (int?)double.NegativeInfinity; i = (int?)double.PositiveInfinity; // float checks i = (int?)3.5d; i = (int?)float.MaxValue; i = (int?)float.NaN; i = (int?)float.NegativeInfinity; i = (int?)float.PositiveInfinity; } } } "; var compilation = CreateCompilationWithMscorlib(source); compilation.VerifyDiagnostics( // (15,13): error CS0030: Cannot convert type 'double' to 'int?' // i = (int?)double.MaxValue; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)double.MaxValue").WithArguments("double", "int?").WithLocation(15, 13), // (16,13): error CS0030: Cannot convert type 'double' to 'int?' // i = (int?)double.NaN; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)double.NaN").WithArguments("double", "int?").WithLocation(16, 13), // (17,13): error CS0030: Cannot convert type 'double' to 'int?' // i = (int?)double.NegativeInfinity; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)double.NegativeInfinity").WithArguments("double", "int?").WithLocation(17, 13), // (18,13): error CS0030: Cannot convert type 'double' to 'int?' // i = (int?)double.PositiveInfinity; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)double.PositiveInfinity").WithArguments("double", "int?").WithLocation(18, 13), // (22,13): error CS0030: Cannot convert type 'float' to 'int?' // i = (int?)float.MaxValue; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)float.MaxValue").WithArguments("float", "int?").WithLocation(22, 13), // (23,13): error CS0030: Cannot convert type 'float' to 'int?' // i = (int?)float.NaN; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)float.NaN").WithArguments("float", "int?").WithLocation(23, 13), // (24,13): error CS0030: Cannot convert type 'float' to 'int?' // i = (int?)float.NegativeInfinity; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)float.NegativeInfinity").WithArguments("float", "int?").WithLocation(24, 13), // (25,13): error CS0030: Cannot convert type 'float' to 'int?' // i = (int?)float.PositiveInfinity; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int?)float.PositiveInfinity").WithArguments("float", "int?").WithLocation(25, 13)); var syntaxTree = compilation.SyntaxTrees.First(); var target = syntaxTree.GetRoot().DescendantNodes().OfType <CastExpressionSyntax>().ToList()[2]; var operand = target.Expression; Assert.Equal("double.NaN", operand.ToFullString()); // Note: there is a valid conversion here at the type level. It's the process of evaluating the conversion, which for // constants happens at compile time, that triggers the error. HashSet <DiagnosticInfo> unused = null; var bag = DiagnosticBag.GetInstance(); var nullableIntType = compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(compilation.GetSpecialType(SpecialType.System_Int32)); var conversion = compilation.Conversions.ClassifyConversionFromExpression( compilation.GetBinder(target).BindExpression(operand, bag), nullableIntType, ref unused); Assert.True(conversion.IsExplicit && conversion.IsNullable); }
/// <summary> /// The spec describes an algorithm for finding the following types: /// 1) Collection type /// 2) Enumerator type /// 3) Element type /// /// The implementation details are a bit difference. If we're iterating over a string or an array, then we don't need to record anything /// but the inferredType (in case the iteration variable is implicitly typed). If we're iterating over anything else, then we want the /// inferred type plus a ForEachEnumeratorInfo.Builder with: /// 1) Collection type /// 2) Element type /// 3) GetEnumerator method of the collection type (return type will be the enumerator type from the spec) /// 4) Current property of the enumerator type /// 5) MoveNext method of the enumerator type /// /// The caller will have to do some extra conversion checks before creating a ForEachEnumeratorInfo for the BoundForEachStatement. /// </summary> /// <param name="builder">Builder to fill in (partially, all but conversions).</param> /// <param name="collectionExpr">The expression over which to iterate.</param> /// <param name="diagnostics">Populated with binding diagnostics.</param> /// <returns>Partially populated (all but conversions) or null if there was an error.</returns> private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundExpression collectionExpr, DiagnosticBag diagnostics) { TypeSymbol collectionExprType = collectionExpr.Type; if (collectionExpr.ConstantValue != null && collectionExpr.ConstantValue.IsNull) { // Spec seems to refer to null literals, but Dev10 reports anything known to be null. Debug.Assert(collectionExpr.ConstantValue.IsNull); // only constant value with no type diagnostics.Add(ErrorCode.ERR_NullNotValid, _syntax.Expression.Location); return(false); } if ((object)collectionExprType == null) // There's no way to enumerate something without a type. { // The null literal was caught above, so anything else with a null type is a method group or anonymous function diagnostics.Add(ErrorCode.ERR_AnonMethGrpInForEach, _syntax.Expression.Location, collectionExpr.Display); // CONSIDER: dev10 also reports ERR_ForEachMissingMember (i.e. failed pattern match). return(false); } if (collectionExpr.ResultKind == LookupResultKind.NotAValue) { // Short-circuiting to prevent strange behavior in the case where the collection // expression is a type expression and the type is enumerable. Debug.Assert(collectionExpr.HasAnyErrors); // should already have been reported return(false); } // The spec specifically lists the collection, enumerator, and element types for arrays and dynamic. if (collectionExprType.Kind == SymbolKind.ArrayType || collectionExprType.Kind == SymbolKind.DynamicType) { // NOTE: for arrays, we won't actually use any of these members - they're just for the API. builder.CollectionType = GetSpecialType(SpecialType.System_Collections_IEnumerable, diagnostics, _syntax); builder.ElementType = collectionExprType.IsDynamic() ? (_syntax.Type.IsVar ? (TypeSymbol)DynamicTypeSymbol.Instance : GetSpecialType(SpecialType.System_Object, diagnostics, _syntax)) : ((ArrayTypeSymbol)collectionExprType).ElementType; // CONSIDER: // For arrays none of these members will actually be emitted, so it seems strange to prevent compilation if they can't be found. // skip this work in the batch case? (If so, also special case string, which won't use the pattern methods.) builder.GetEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, _syntax); builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, _syntax); builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, _syntax); Debug.Assert((object)builder.GetEnumeratorMethod == null || builder.GetEnumeratorMethod.ReturnType == this.Compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator)); // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose). builder.NeedsDisposeMethod = true; return(true); } bool foundMultipleGenericIEnumerableInterfaces; if (SatisfiesGetEnumeratorPattern(ref builder, collectionExprType, diagnostics)) { Debug.Assert((object)builder.GetEnumeratorMethod != null); builder.CollectionType = collectionExprType; if (SatisfiesForEachPattern(ref builder, diagnostics)) { builder.ElementType = ((PropertySymbol)builder.CurrentPropertyGetter.AssociatedSymbol).Type; // NOTE: if IDisposable is not available at all, no diagnostics will be reported - we will just assume that // the enumerator is not disposable. If it has IDisposable in its interface list, there will be a diagnostic there. // If IDisposable is available but its Dispose method is not, then diagnostics will be reported only if the enumerator // is potentially disposable. var useSiteDiagnosticBag = DiagnosticBag.GetInstance(); TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType; HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (!enumeratorType.IsSealed || this.Conversions.ClassifyImplicitConversion(enumeratorType, this.Compilation.GetSpecialType(SpecialType.System_IDisposable), ref useSiteDiagnostics).IsImplicit) { builder.NeedsDisposeMethod = true; diagnostics.AddRange(useSiteDiagnosticBag); } useSiteDiagnosticBag.Free(); diagnostics.Add(_syntax, useSiteDiagnostics); return(true); } MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod; diagnostics.Add(ErrorCode.ERR_BadGetEnumerator, _syntax.Expression.Location, getEnumeratorMethod.ReturnType, getEnumeratorMethod); return(false); } if (IsIEnumerable(collectionExprType)) { // This indicates a problem with the special IEnumerable type - it should have satisfied the GetEnumerator pattern. diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName); return(false); } if (AllInterfacesContainsIEnumerable(ref builder, collectionExprType, diagnostics, out foundMultipleGenericIEnumerableInterfaces)) { CSharpSyntaxNode errorLocationSyntax = _syntax.Expression; if (foundMultipleGenericIEnumerableInterfaces) { diagnostics.Add(ErrorCode.ERR_MultipleIEnumOfT, errorLocationSyntax.Location, collectionExprType, this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)); return(false); } Debug.Assert((object)builder.CollectionType != null); NamedTypeSymbol collectionType = (NamedTypeSymbol)builder.CollectionType; if (collectionType.IsGenericType) { // If the type is generic, we have to search for the methods Debug.Assert(collectionType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T); builder.ElementType = collectionType.TypeArgumentsNoUseSiteDiagnostics.Single(); MethodSymbol getEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator, diagnostics, errorLocationSyntax); if ((object)getEnumeratorMethod != null) { builder.GetEnumeratorMethod = getEnumeratorMethod.AsMember(collectionType); TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType; Debug.Assert(enumeratorType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T); MethodSymbol currentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerator_T__get_Current, diagnostics, errorLocationSyntax); if ((object)currentPropertyGetter != null) { builder.CurrentPropertyGetter = currentPropertyGetter.AsMember((NamedTypeSymbol)enumeratorType); } } builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax); // NOTE: MoveNext is actually inherited from System.Collections.IEnumerator } else { // Non-generic - use special members to avoid re-computing Debug.Assert(collectionType.SpecialType == SpecialType.System_Collections_IEnumerable); builder.ElementType = GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationSyntax); builder.GetEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, errorLocationSyntax); builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, errorLocationSyntax); builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax); Debug.Assert((object)builder.GetEnumeratorMethod == null || builder.GetEnumeratorMethod.ReturnType == GetSpecialType(SpecialType.System_Collections_IEnumerator, diagnostics, errorLocationSyntax)); } // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose). builder.NeedsDisposeMethod = true; return(true); } if (!string.IsNullOrEmpty(collectionExprType.Name) || !collectionExpr.HasErrors) { diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType.ToDisplayString(), GetEnumeratorMethodName); } return(false); }
public void EmitCtor(Emit.PEModuleBuilder module, Action <Microsoft.CodeAnalysis.CodeGen.ILBuilder> builder) { Debug.Assert(_ctor == null); // emit default .ctor _ctor = new SynthesizedCtorSymbol(this); _ctor.SetParameters();// empty params (default ctor) var body = CodeGen.MethodGenerator.GenerateMethodBody(module, _ctor, builder, null, DiagnosticBag.GetInstance(), false); module.SetMethodBody(_ctor, body); }
public void EmitInit(Emit.PEModuleBuilder module, Action <Microsoft.CodeAnalysis.CodeGen.ILBuilder> builder) { Debug.Assert(_initMethod == null); var tt = DeclaringCompilation.CoreTypes; // override IStaticInit.Init(Context) _initMethod = new SynthesizedMethodSymbol(this, "Init", false, true, tt.Void, Accessibility.Public); _initMethod.SetParameters(new SynthesizedParameterSymbol(_initMethod, tt.Context, 0, RefKind.None, "ctx")); var body = CodeGen.MethodGenerator.GenerateMethodBody(module, _initMethod, builder, null, DiagnosticBag.GetInstance(), false); module.SetMethodBody(_initMethod, body); }
internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics, bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray <NamespaceScope> namespaceScopes) { // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings. Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened"); bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync; var module = compilationState.ModuleBuilder; var compilation = module.Compilation; var localSlotManager = module.CreateLocalSlotManager(method); ILBuilder builder = new ILBuilder(module, localSlotManager, optimize); DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); try { AsyncMethodBodyDebugInfo asyncDebugInfo = null; if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method? { CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints); } else { int asyncCatchHandlerOffset; ImmutableArray <int> asyncYieldPoints; ImmutableArray <int> asyncResumePoints; CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints, out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints); } var localVariables = builder.LocalSlotManager.LocalsInOrder(); if (localVariables.Length > 0xFFFE) { diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First()); } if (diagnosticsForThisMethod.HasAnyErrors()) { // we are done here. Since there were errors we should not emit anything. return(null); } // We will only save the IL builders when running tests. if (module.SaveTestData) { module.SetMethodTestData(method, builder.GetSnapshot()); } // Only compiler-generated MoveNext methods have iterator scopes. See if this is one. bool hasIteratorScopes = method.Locations.IsEmpty && method.Name == "MoveNext" && (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) || method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol)); var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray <LocalScope> .Empty; var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method); return(new MethodBody( builder.RealizedIL, builder.MaxStack, method, localVariables, builder.RealizedSequencePoints, debugDocumentProvider, builder.RealizedExceptionHandlers, builder.GetAllScopes(), Microsoft.Cci.CustomDebugInfoKind.CSharpStyle, builder.HasDynamicLocal, namespaceScopes, (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName, iteratorScopes, asyncMethodDebugInfo: asyncDebugInfo )); } finally { // Basic blocks contain poolable builders for IL and sequence points. Free those back // to their pools. builder.FreeBasicBlocks(); // Remember diagnostics. diagnostics.AddRange(diagnosticsForThisMethod); diagnosticsForThisMethod.Free(); } }
/// <summary> /// This method handles duplicate types in a few different ways: /// - for types before C# 7, the first candidate is returned with a warning /// - for types after C# 7, the type is considered missing /// - in both cases, when BinderFlags.IgnoreCorLibraryDuplicatedTypes is set, any duplicate coming from corlib will be ignored (ie not count as a duplicate) /// </summary> internal NamedTypeSymbol GetWellKnownType(WellKnownType type) { Debug.Assert(type.IsValid()); bool ignoreCorLibraryDuplicatedTypes = this.Options.TopLevelBinderFlags.Includes(BinderFlags.IgnoreCorLibraryDuplicatedTypes); int index = (int)type - (int)WellKnownType.First; if (_lazyWellKnownTypes == null || (object)_lazyWellKnownTypes[index] == null) { if (_lazyWellKnownTypes == null) { Interlocked.CompareExchange(ref _lazyWellKnownTypes, new NamedTypeSymbol[(int)WellKnownTypes.Count], null); } string mdName = type.GetMetadataName(); var warnings = DiagnosticBag.GetInstance(); NamedTypeSymbol result; if (IsTypeMissing(type)) { result = null; } else { // well-known types introduced before CSharp7 allow lookup ambiguity and report a warning DiagnosticBag legacyWarnings = (type <= WellKnownType.CSharp7Sentinel) ? warnings : null; result = this.Assembly.GetTypeByMetadataName( mdName, includeReferences: true, useCLSCompliantNameArityEncoding: true, isWellKnownType: true, warnings: legacyWarnings, ignoreCorLibraryDuplicatedTypes: ignoreCorLibraryDuplicatedTypes); } if ((object)result == null) { // TODO: should GetTypeByMetadataName rather return a missing symbol? MetadataTypeName emittedName = MetadataTypeName.FromFullName(mdName, useCLSCompliantNameArityEncoding: true); if (type.IsValueTupleType()) { result = new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Assembly.Modules[0], ref emittedName, new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, emittedName.FullName), type); } else { result = new MissingMetadataTypeSymbol.TopLevel(this.Assembly.Modules[0], ref emittedName, type); } } if ((object)Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null) != null) { Debug.Assert( result == _lazyWellKnownTypes[index] || (_lazyWellKnownTypes[index].IsErrorType() && result.IsErrorType()) ); } else { AdditionalCodegenWarnings.AddRange(warnings); } warnings.Free(); } return(_lazyWellKnownTypes[index]); }
/// <summary> /// Emits the compilation into given <see cref="ModuleBuilder"/> using Reflection.Emit APIs. /// </summary> /// <param name="compilation">Compilation.</param> /// <param name="moduleBuilder"> /// The module builder to add the types into. Can be reused for multiple compilation units. /// </param> /// <param name="assemblyLoader"> /// Loads an assembly given an <see cref="AssemblyIdentity"/>. /// This callback is used for loading assemblies referenced by the compilation. /// <see cref="System.Reflection.Assembly.Load(AssemblyName)"/> is used if not specified. /// </param> /// <param name="assemblySymbolMapper"> /// Applied when converting assembly symbols to assembly references. /// <see cref="IAssemblySymbol"/> is mapped to its <see cref="IAssemblySymbol.Identity"/> by default. /// </param> /// <param name="cancellationToken">Can be used to cancel the emit process.</param> /// <param name="recoverOnError">If false the method returns an unsuccessful result instead of falling back to CCI writer.</param> /// <param name="compiledAssemblyImage">Assembly image, returned only if we fallback to CCI writer.</param> /// <param name="entryPoint">An entry point or null if not applicable or on failure.</param> /// <param name="diagnostics">Diagnostics.</param> /// <returns>True on success, false if a compilation error occurred or the compilation doesn't contain any code or declarations.</returns> /// <remarks> /// Reflection.Emit doesn't support all metadata constructs. If an unsupported construct is /// encountered a metadata writer that procudes uncollectible code is used instead. This is /// indicated by /// <see cref="ReflectionEmitResult.IsUncollectible"/> flag on the result. /// /// Reusing <see cref="System.Reflection.Emit.ModuleBuilder"/> may be beneficial in certain /// scenarios. For example, when emitting a sequence of code snippets one at a time (like in /// REPL). All the snippets can be compiled into a single module as long as the types being /// emitted have unique names. Reusing a single module/assembly reduces memory overhead. On /// the other hand, collectible assemblies are units of collection. Defining too many /// unrelated types in a single assemly might prevent the unused types to be collected. /// /// No need to provide a name override when using Reflection.Emit, since the assembly already /// exists. /// </remarks> /// <exception cref="InvalidOperationException">Referenced assembly can't be resolved.</exception> internal static bool Emit( this Compilation compilation, ModuleBuilder moduleBuilder, AssemblyLoader assemblyLoader, Func <IAssemblySymbol, AssemblyIdentity> assemblySymbolMapper, bool recoverOnError, DiagnosticBag diagnostics, CancellationToken cancellationToken, out MethodInfo entryPoint, out byte[] compiledAssemblyImage) { compiledAssemblyImage = default(byte[]); var moduleBeingBuilt = compilation.CreateModuleBuilder( emitOptions: EmitOptions.Default, manifestResources: null, assemblySymbolMapper: assemblySymbolMapper, testData: null, diagnostics: diagnostics, cancellationToken: cancellationToken); if (moduleBeingBuilt == null) { entryPoint = null; return(false); } if (!compilation.Compile( moduleBeingBuilt, win32Resources: null, xmlDocStream: null, generateDebugInfo: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) { entryPoint = null; return(false); } Cci.IMethodReference cciEntryPoint = moduleBeingBuilt.EntryPoint; cancellationToken.ThrowIfCancellationRequested(); DiagnosticBag metadataDiagnostics = DiagnosticBag.GetInstance(); var context = new EmitContext((Cci.IModule)moduleBeingBuilt, null, metadataDiagnostics); // try emit via Reflection.Emit try { var referencedAssemblies = from referencedAssembly in compilation.GetBoundReferenceManager().GetReferencedAssemblies() let peReference = referencedAssembly.Key as PortableExecutableReference select KeyValuePair.Create( moduleBeingBuilt.Translate(referencedAssembly.Value, metadataDiagnostics), (peReference != null)?peReference.FilePath : null); entryPoint = ReflectionEmitter.Emit( context, referencedAssemblies, moduleBuilder, assemblyLoader ?? AssemblyLoader.Default, cciEntryPoint, cancellationToken); // translate metadata errors. return(compilation.FilterAndAppendAndFreeDiagnostics(diagnostics, ref metadataDiagnostics)); } catch (TypeLoadException) { // attempted to emit reference to a type that can't be loaded (has invalid metadata) } catch (NotSupportedException) { // nop } // TODO (tomat): // // Another possible approach would be to just return an error, that we can't emit via // Ref.Emit and let the user choose another method of emitting. For that we would want // to preserve the state of the Emit.Assembly object with all the compiled methods so // that the subsequent emit doesn't need to compile method bodies again. // TODO (tomat): // // If Ref.Emit fails to emit the code the type builders already created will stay // defined on the module builder. Ideally we would clean them up but Ref.Emit doesn't // provide any API to do so. In fact it also keeps baked TypeBuilders alive as well. if (!recoverOnError) { metadataDiagnostics.Free(); entryPoint = null; return(false); } using (var stream = new System.IO.MemoryStream()) { Cci.PeWriter.WritePeToStream( context, compilation.MessageProvider, () => stream, nativePdbWriterOpt: null, pdbPathOpt: null, allowMissingMethodBodies: false, deterministic: false, cancellationToken: cancellationToken); compiledAssemblyImage = stream.ToArray(); } var compiledAssembly = Assembly.Load(compiledAssemblyImage); entryPoint = (cciEntryPoint != null) ? ReflectionEmitter.ResolveEntryPoint(compiledAssembly, cciEntryPoint, context) : null; // translate metadata errors. return(compilation.FilterAndAppendAndFreeDiagnostics(diagnostics, ref metadataDiagnostics)); }
private BoundExpression FinalTranslation(QueryTranslationState state, DiagnosticBag diagnostics) { Debug.Assert(state.clauses.IsEmpty()); switch (state.selectOrGroup.Kind()) { case SyntaxKind.SelectClause: { // A query expression of the form // from x in e select v // is translated into // ( e ) . Select ( x => v ) var selectClause = (SelectClauseSyntax)state.selectOrGroup; var x = state.rangeVariable; var e = state.fromExpression; var v = selectClause.Expression; var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v); var result = MakeQueryInvocation(state.selectOrGroup, e, "Select", lambda, diagnostics); return(MakeQueryClause(selectClause, result, queryInvocation: result)); } case SyntaxKind.GroupClause: { // A query expression of the form // from x in e group v by k // is translated into // ( e ) . GroupBy ( x => k , x => v ) // except when v is the identifier x, the translation is // ( e ) . GroupBy ( x => k ) var groupClause = (GroupClauseSyntax)state.selectOrGroup; var x = state.rangeVariable; var e = state.fromExpression; var v = groupClause.GroupExpression; var k = groupClause.ByExpression; var vId = v as IdentifierNameSyntax; BoundCall result; var lambdaLeft = MakeQueryUnboundLambda(state.RangeVariableMap(), x, k); // this is the unoptimized form (when v is not the identifier x) var d = DiagnosticBag.GetInstance(); BoundExpression lambdaRight = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v); result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", ImmutableArray.Create(lambdaLeft, lambdaRight), d); // k and v appear reversed in the invocation, so we reorder their evaluation result = ReverseLastTwoParameterOrder(result); BoundExpression unoptimizedForm = null; if (vId != null && vId.Identifier.ValueText == x.Name) { // The optimized form. We store the unoptimized form for analysis unoptimizedForm = result; result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", lambdaLeft, diagnostics); if (unoptimizedForm.HasAnyErrors && !result.HasAnyErrors) { unoptimizedForm = null; } } else { diagnostics.AddRange(d); } d.Free(); return(MakeQueryClause(groupClause, result, queryInvocation: result, unoptimizedForm: unoptimizedForm)); } default: { // there should have been a syntax error if we get here. return(new BoundBadExpression( state.selectOrGroup, LookupResultKind.OverloadResolutionFailure, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(state.fromExpression), state.fromExpression.Type)); } } }
internal static EmitDifferenceResult EmitDifference( CSharpCompilation compilation, EmitBaseline baseline, IEnumerable <SemanticEdit> edits, Stream metadataStream, Stream ilStream, Stream pdbStream, ICollection <uint> updatedMethodTokens, CompilationTestData testData, CancellationToken cancellationToken) { Guid moduleVersionId; try { moduleVersionId = baseline.OriginalMetadata.GetModuleVersionId(); } catch (BadImageFormatException) { // return MakeEmitResult(success: false, diagnostics: ..., baseline: null); throw; } var pdbName = PathUtilities.ChangeExtension(compilation.SourceModule.Name, "pdb"); var diagnostics = DiagnosticBag.GetInstance(); string runtimeMDVersion = compilation.GetRuntimeMetadataVersion(diagnostics); var serializationProperties = compilation.ConstructModuleSerializationProperties(runtimeMDVersion, moduleVersionId); var manifestResources = SpecializedCollections.EmptyEnumerable <ResourceDescription>(); var moduleBeingBuilt = new PEDeltaAssemblyBuilder( compilation.SourceAssembly, outputName: null, outputKind: compilation.Options.OutputKind, serializationProperties: serializationProperties, manifestResources: manifestResources, assemblySymbolMapper: null, previousGeneration: baseline, edits: edits); if (testData != null) { moduleBeingBuilt.SetMethodTestData(testData.Methods); testData.Module = moduleBeingBuilt; } baseline = moduleBeingBuilt.PreviousGeneration; var definitionMap = moduleBeingBuilt.PreviousDefinitions; var changes = moduleBeingBuilt.Changes; if (compilation.Compile( moduleBeingBuilt, outputName: null, win32Resources: null, xmlDocStream: null, cancellationToken: cancellationToken, generateDebugInfo: true, diagnostics: diagnostics, filterOpt: changes.RequiresCompilation)) { // Map the definitions from the previous compilation to the current compilation. // This must be done after compiling above since synthesized definitions // (generated when compiling method bodies) may be required. baseline = MapToCompilation(compilation, moduleBeingBuilt); using (var pdbWriter = new Cci.PdbWriter(pdbName, pdbStream, (testData != null) ? testData.SymWriterFactory : null)) { var context = new EmitContext(moduleBeingBuilt, null, diagnostics); var encId = Guid.NewGuid(); try { var writer = new DeltaPeWriter( context, compilation.MessageProvider, pdbWriter, baseline, encId, definitionMap, changes, cancellationToken); writer.WriteMetadataAndIL(metadataStream, ilStream); writer.GetMethodTokens(updatedMethodTokens); return(new EmitDifferenceResult( success: true, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: writer.GetDelta(baseline, compilation, encId))); } catch (Cci.PdbWritingException e) { diagnostics.Add(ErrorCode.FTL_DebugEmitFailure, Location.None, e.Message); } catch (PermissionSetFileReadException e) { diagnostics.Add(ErrorCode.ERR_PermissionSetAttributeFileReadError, Location.None, e.FileName, e.PropertyName, e.Message); } } } return(new EmitDifferenceResult(success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null)); }
public override Compilation?CreateCompilation( TextWriter consoleOutput, TouchedFileLogger touchedFilesLogger, ErrorLogger errorLogger, ImmutableArray <AnalyzerConfigOptionsResult> analyzerConfigOptions, AnalyzerConfigOptionsResult globalConfigOptions) { var parseOptions = Arguments.ParseOptions; // We compute script parse options once so we don't have to do it repeatedly in // case there are many script files. var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script); bool hadErrors = false; var sourceFiles = Arguments.SourceFiles; var trees = new SyntaxTree?[sourceFiles.Length]; var normalizedFilePaths = new string[sourceFiles.Length]; var diagnosticBag = DiagnosticBag.GetInstance(); if (Arguments.CompilationOptions.ConcurrentBuild) { RoslynParallel.For( 0, sourceFiles.Length, UICultureUtilities.WithCurrentUICulture <int>(i => { //NOTE: order of trees is important!! trees[i] = ParseFile( parseOptions, scriptParseOptions, ref hadErrors, sourceFiles[i], diagnosticBag, out normalizedFilePaths[i]); }), CancellationToken.None); } else { for (int i = 0; i < sourceFiles.Length; i++) { //NOTE: order of trees is important!! trees[i] = ParseFile( parseOptions, scriptParseOptions, ref hadErrors, sourceFiles[i], diagnosticBag, out normalizedFilePaths[i]); } } // If errors had been reported in ParseFile, while trying to read files, then we should simply exit. if (ReportDiagnostics(diagnosticBag.ToReadOnlyAndFree(), consoleOutput, errorLogger)) { Debug.Assert(hadErrors); return(null); } var diagnostics = new List <DiagnosticInfo>(); var uniqueFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < sourceFiles.Length; i++) { var normalizedFilePath = normalizedFilePaths[i]; Debug.Assert(normalizedFilePath != null); Debug.Assert(sourceFiles[i].IsInputRedirected || PathUtilities.IsAbsolute(normalizedFilePath)); if (!uniqueFilePaths.Add(normalizedFilePath)) { // warning CS2002: Source file '{0}' specified multiple times diagnostics.Add(new DiagnosticInfo(MessageProvider, (int)ErrorCode.WRN_FileAlreadyIncluded, Arguments.PrintFullPaths ? normalizedFilePath : _diagnosticFormatter.RelativizeNormalizedPath(normalizedFilePath))); trees[i] = null; } } if (Arguments.TouchedFilesPath != null) { foreach (var path in uniqueFilePaths) { touchedFilesLogger.AddRead(path); } } var assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default; var appConfigPath = this.Arguments.AppConfigPath; if (appConfigPath != null) { try { using (var appConfigStream = new FileStream(appConfigPath, FileMode.Open, FileAccess.Read)) { assemblyIdentityComparer = DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream); } if (touchedFilesLogger != null) { touchedFilesLogger.AddRead(appConfigPath); } } catch (Exception ex) { diagnostics.Add(new DiagnosticInfo(MessageProvider, (int)ErrorCode.ERR_CantReadConfigFile, appConfigPath, ex.Message)); } } var xmlFileResolver = new LoggingXmlFileResolver(Arguments.BaseDirectory, touchedFilesLogger); var sourceFileResolver = new LoggingSourceFileResolver(ImmutableArray <string> .Empty, Arguments.BaseDirectory, Arguments.PathMap, touchedFilesLogger); MetadataReferenceResolver referenceDirectiveResolver; var resolvedReferences = ResolveMetadataReferences(diagnostics, touchedFilesLogger, out referenceDirectiveResolver); if (ReportDiagnostics(diagnostics, consoleOutput, errorLogger)) { return(null); } var loggingFileSystem = new LoggingStrongNameFileSystem(touchedFilesLogger, _tempDirectory); var optionsProvider = new CompilerSyntaxTreeOptionsProvider(trees, analyzerConfigOptions, globalConfigOptions); return(CSharpCompilation.Create( Arguments.CompilationName, trees.WhereNotNull(), resolvedReferences, Arguments.CompilationOptions .WithMetadataReferenceResolver(referenceDirectiveResolver) .WithAssemblyIdentityComparer(assemblyIdentityComparer) .WithXmlReferenceResolver(xmlFileResolver) .WithStrongNameProvider(Arguments.GetStrongNameProvider(loggingFileSystem)) .WithSourceReferenceResolver(sourceFileResolver) .WithSyntaxTreeOptionsProvider(optionsProvider))); }
private static void AppendAllLoadedSyntaxTrees( ArrayBuilder <SyntaxTree> treesBuilder, SyntaxTree tree, string scriptClassName, SourceReferenceResolver resolver, CommonMessageProvider messageProvider, bool isSubmission, IDictionary <SyntaxTree, int> ordinalMapBuilder, IDictionary <SyntaxTree, ImmutableArray <DeclarationLoadDirective> > loadDirectiveMapBuilder, IDictionary <string, SyntaxTree> loadedSyntaxTreeMapBuilder, IDictionary <SyntaxTree, Lazy <RootSingleNamespaceDeclaration> > declMapBuilder, ref DeclarationTable declTable) { ArrayBuilder <DeclarationLoadDirective> loadDirectives = null; foreach (var directive in tree.GetCompilationUnitRoot().GetLoadDirectives()) { var fileToken = directive.File; var path = (string)fileToken.Value; if (path == null) { // If there is no path, the parser should have some Diagnostics to report (if we're in an active region). Debug.Assert(!directive.IsActive || tree.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); continue; } var diagnostics = DiagnosticBag.GetInstance(); string resolvedFilePath = null; if (resolver == null) { diagnostics.Add( messageProvider.CreateDiagnostic( (int)ErrorCode.ERR_SourceFileReferencesNotSupported, directive.Location)); } else { resolvedFilePath = resolver.ResolveReference(path, baseFilePath: tree.FilePath); if (resolvedFilePath == null) { diagnostics.Add( messageProvider.CreateDiagnostic( (int)ErrorCode.ERR_NoSourceFile, fileToken.GetLocation(), path, CSharpResources.CouldNotFindFile)); } else if (!loadedSyntaxTreeMapBuilder.ContainsKey(resolvedFilePath)) { try { var code = resolver.ReadText(resolvedFilePath); var loadedTree = SyntaxFactory.ParseSyntaxTree( code, tree.Options, // Use ParseOptions propagated from "external" tree. resolvedFilePath); // All #load'ed trees should have unique path information. loadedSyntaxTreeMapBuilder.Add(loadedTree.FilePath, loadedTree); AppendAllSyntaxTrees( treesBuilder, loadedTree, scriptClassName, resolver, messageProvider, isSubmission, ordinalMapBuilder, loadDirectiveMapBuilder, loadedSyntaxTreeMapBuilder, declMapBuilder, ref declTable); } catch (Exception e) { diagnostics.Add( CommonCompiler.ToFileReadDiagnostics(messageProvider, e, resolvedFilePath), fileToken.GetLocation()); } } else { // The path resolved, but we've seen this file before, // so don't attempt to load it again. Debug.Assert(diagnostics.IsEmptyWithoutResolution); } } if (loadDirectives == null) { loadDirectives = ArrayBuilder <DeclarationLoadDirective> .GetInstance(); } loadDirectives.Add(new DeclarationLoadDirective(resolvedFilePath, diagnostics.ToReadOnlyAndFree())); } if (loadDirectives != null) { loadDirectiveMapBuilder.Add(tree, loadDirectives.ToImmutableAndFree()); } }
internal static EmitDifferenceResult EmitDifference( CSharpCompilation compilation, EmitBaseline baseline, IEnumerable <SemanticEdit> edits, Func <ISymbol, bool> isAddedSymbol, Stream metadataStream, Stream ilStream, Stream pdbStream, ICollection <MethodDefinitionHandle> updatedMethods, CompilationTestData testData, CancellationToken cancellationToken) { var diagnostics = DiagnosticBag.GetInstance(); var emitOptions = EmitOptions.Default.WithDebugInformationFormat(baseline.HasPortablePdb ? DebugInformationFormat.PortablePdb : DebugInformationFormat.Pdb); string runtimeMDVersion = compilation.GetRuntimeMetadataVersion(emitOptions, diagnostics); var serializationProperties = compilation.ConstructModuleSerializationProperties(emitOptions, runtimeMDVersion, baseline.ModuleVersionId); var manifestResources = SpecializedCollections.EmptyEnumerable <ResourceDescription>(); PEDeltaAssemblyBuilder moduleBeingBuilt; try { moduleBeingBuilt = new PEDeltaAssemblyBuilder( compilation.SourceAssembly, emitOptions: emitOptions, outputKind: compilation.Options.OutputKind, serializationProperties: serializationProperties, manifestResources: manifestResources, previousGeneration: baseline, edits: edits, isAddedSymbol: isAddedSymbol); } catch (NotSupportedException) { // TODO: better error code (https://github.com/dotnet/roslyn/issues/8910) diagnostics.Add(ErrorCode.ERR_ModuleEmitFailure, NoLocation.Singleton, compilation.AssemblyName); return(new EmitDifferenceResult(success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null)); } if (testData != null) { moduleBeingBuilt.SetMethodTestData(testData.Methods); testData.Module = moduleBeingBuilt; } var definitionMap = moduleBeingBuilt.PreviousDefinitions; var changes = moduleBeingBuilt.Changes; EmitBaseline newBaseline = null; if (compilation.Compile( moduleBeingBuilt, emittingPdb: true, diagnostics: diagnostics, filterOpt: changes.RequiresCompilation, cancellationToken: cancellationToken)) { // Map the definitions from the previous compilation to the current compilation. // This must be done after compiling above since synthesized definitions // (generated when compiling method bodies) may be required. var mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt); newBaseline = compilation.SerializeToDeltaStreams( moduleBeingBuilt, mappedBaseline, definitionMap, changes, metadataStream, ilStream, pdbStream, updatedMethods, diagnostics, testData?.SymWriterFactory, cancellationToken); } return(new EmitDifferenceResult( success: newBaseline != null, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: newBaseline)); }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var returnType = DelegateReturnType(delegateType); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. MethodSymbol cacheKey = GetCacheKey(delegateType); BoundLambda returnInferenceLambda; if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType) { var lambdaSym = returnInferenceLambda.Symbol; var lambdaRetType = lambdaSym.ReturnType; if (lambdaRetType == returnType) { lambdaSymbol = lambdaSym; lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } } var parameters = DelegateParameters(delegateType); lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, returnType); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, ref lambdaBodyBinder, diagnostics); ValidateUnsafeParameters(diagnostics, parameters); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(delegateType)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.Locations[0], this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol, _unboundLambda.Syntax); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && returnType != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) && returnType.OriginalDefinition != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.Locations[0], lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol, diagnostics, lambdaSymbol.Locations[0]); } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return(result); }
internal override void ForceComplete(SourceLocation locationOpt, CancellationToken cancellationToken) { while (true) { cancellationToken.ThrowIfCancellationRequested(); var incompletePart = _state.NextIncompletePart; switch (incompletePart) { case CompletionPart.Attributes: GetAttributes(); break; case CompletionPart.StartValidatingReferencedAssemblies: { DiagnosticBag diagnostics = null; if (AnyReferencedAssembliesAreLinked) { diagnostics = DiagnosticBag.GetInstance(); ValidateLinkedAssemblies(diagnostics, cancellationToken); } if (_state.NotePartComplete(CompletionPart.StartValidatingReferencedAssemblies)) { if (diagnostics != null) { _assemblySymbol.DeclaringCompilation.DeclarationDiagnostics.AddRange(diagnostics); } _state.NotePartComplete(CompletionPart.FinishValidatingReferencedAssemblies); } if (diagnostics != null) { diagnostics.Free(); } } break; case CompletionPart.FinishValidatingReferencedAssemblies: // some other thread has started validating references (otherwise we would be in the case above) so // we just wait for it to both finish and report the diagnostics. Debug.Assert(_state.HasComplete(CompletionPart.StartValidatingReferencedAssemblies)); _state.SpinWaitComplete(CompletionPart.FinishValidatingReferencedAssemblies, cancellationToken); break; case CompletionPart.MembersCompleted: this.GlobalNamespace.ForceComplete(locationOpt, cancellationToken); if (this.GlobalNamespace.HasComplete(CompletionPart.MembersCompleted)) { _state.NotePartComplete(CompletionPart.MembersCompleted); } else { Debug.Assert(locationOpt != null, "If no location was specified, then the namespace members should be completed"); return; } break; case CompletionPart.None: return; default: // any other values are completion parts intended for other kinds of symbols _state.NotePartComplete(incompletePart); break; } _state.SpinWaitComplete(incompletePart, cancellationToken); } }
private BoundPattern BindDeclarationPattern( DeclarationPatternSyntax node, BoundExpression operand, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics) { Debug.Assert(operand != null && operandType != (object)null); var typeSyntax = node.Type; bool isVar; AliasSymbol aliasOpt; TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt); if (isVar) { declType = operandType; } if (declType == (object)null) { Debug.Assert(hasErrors); declType = this.CreateErrorType("var"); } var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType); if (IsOperatorErrors(node, operandType, boundDeclType, diagnostics)) { hasErrors = true; } else { hasErrors |= CheckValidPatternType(typeSyntax, operand, operandType, declType, isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics); } switch (node.Designation.Kind()) { case SyntaxKind.SingleVariableDesignation: break; case SyntaxKind.DiscardDesignation: return(new BoundDeclarationPattern(node, null, boundDeclType, isVar, hasErrors)); default: throw ExceptionUtilities.UnexpectedValue(node.Designation.Kind()); } var designation = (SingleVariableDesignationSyntax)node.Designation; var identifier = designation.Identifier; SourceLocalSymbol localSymbol = this.LookupLocal(identifier); if (localSymbol != (object)null) { if ((InConstructorInitializer || InFieldInitializer) && ContainingMemberOrLambda.ContainingSymbol.Kind == SymbolKind.NamedType) { Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, node); } localSymbol.SetType(declType); // Check for variable declaration errors. hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics); if (!hasErrors) { hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax); } return(new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors)); } else { // We should have the right binder in the chain for a script or interactive, so we use the field for the pattern. Debug.Assert(node.SyntaxTree.Options.Kind != SourceCodeKind.Regular); GlobalExpressionVariable expressionVariableField = LookupDeclaredField(designation); DiagnosticBag tempDiagnostics = DiagnosticBag.GetInstance(); expressionVariableField.SetType(declType, tempDiagnostics); tempDiagnostics.Free(); BoundExpression receiver = SynthesizeReceiver(node, expressionVariableField, diagnostics); var variableAccess = new BoundFieldAccess(node, receiver, expressionVariableField, null, hasErrors); return(new BoundDeclarationPattern(node, expressionVariableField, variableAccess, boundDeclType, isVar, hasErrors)); } }
/// <summary> /// This method does the following set of operations in the specified order: /// (1) GetAttributesToBind: Merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target. /// (2) BindAttributeTypes: Bind all the attribute types to enable early decode of certain well-known attributes by type. /// (3) EarlyDecodeWellKnownAttributes: Perform early decoding of certain well-known attributes that could be queried by the binder in subsequent steps. /// (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes). /// (4) GetAttributes: Bind the attributes (attribute arguments and constructor) using bound attribute types. /// (5) DecodeWellKnownAttributes: Decode and validate bound well known attributes. /// (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes). /// (6) StoreBoundAttributesAndDoPostValidation: /// (a) Store the bound attributes in lazyCustomAttributes in a thread safe manner. /// (b) Perform some additional post attribute validations, such as /// 1) Duplicate attributes, attribute usage target validation, etc. /// 2) Post validation for attributes dependant on other attributes /// These validations cannot be performed prior to step 6(a) as we might need to /// perform a GetAttributes() call on a symbol which can introduce a cycle in attribute binding. /// We avoid this cycle by performing such validations in PostDecodeWellKnownAttributes after lazyCustomAttributes have been set. /// NOTE: PostDecodeWellKnownAttributes SHOULD NOT change the symbol state. /// </summary> /// <remarks> /// Current design of early decoding well-known attributes doesn't permit decoding attribute arguments/constructor as this can lead to binding cycles. /// For well-known attributes used by the binder, where we need the decoded arguments, we must handle them specially in one of the following possible ways: /// (a) Avoid decoding the attribute arguments during binding and delay the corresponding binder tasks to a separate post-pass executed after binding. /// (b) As the cycles can be caused only when we are binding attribute arguments/constructor, special case the corresponding binder tasks based on the current BinderFlags. /// </remarks> /// <param name="attributesSyntaxLists"></param> /// <param name="lazyCustomAttributesBag"></param> /// <param name="symbolPart">Specific part of the symbol to which the attributes apply, or <see cref="AttributeLocation.None"/> if the attributes apply to the symbol itself.</param> /// <param name="earlyDecodingOnly">Indicates that only early decoding should be performed. WARNING: the resulting bag will not be sealed.</param> /// <returns>Flag indicating whether lazyCustomAttributes were stored on this thread. Caller should check for this flag and perform NotePartComplete if true.</returns> internal bool LoadAndValidateAttributes( OneOrMany <SyntaxList <AttributeListSyntax> > attributesSyntaxLists, ref CustomAttributesBag <CSharpAttributeData> lazyCustomAttributesBag, AttributeLocation symbolPart = AttributeLocation.None, bool earlyDecodingOnly = false) { var diagnostics = DiagnosticBag.GetInstance(); var compilation = this.DeclaringCompilation; ImmutableArray <Binder> binders; ImmutableArray <AttributeSyntax> attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, out binders); Debug.Assert(!attributesToBind.IsDefault); ImmutableArray <CSharpAttributeData> boundAttributes; WellKnownAttributeData wellKnownAttributeData; if (attributesToBind.Any()) { Debug.Assert(!binders.IsDefault); Debug.Assert(binders.Length == attributesToBind.Length); // Initialize the bag so that data decoded from early attributes can be stored onto it. if (lazyCustomAttributesBag == null) { Interlocked.CompareExchange(ref lazyCustomAttributesBag, new CustomAttributesBag <CSharpAttributeData>(), null); } // Bind the attribute types and then early decode them. int totalAttributesCount = attributesToBind.Length; var attributeTypesBuilder = new NamedTypeSymbol[totalAttributesCount]; Binder.BindAttributeTypes(binders, attributesToBind, this, attributeTypesBuilder, diagnostics); ImmutableArray <NamedTypeSymbol> boundAttributeTypes = attributeTypesBuilder.AsImmutableOrNull(); this.EarlyDecodeWellKnownAttributeTypes(boundAttributeTypes, attributesToBind); this.PostEarlyDecodeWellKnownAttributeTypes(); // Bind the attribute in two stages - early and normal. var attributesBuilder = new CSharpAttributeData[totalAttributesCount]; // Early bind and decode some well-known attributes. EarlyWellKnownAttributeData earlyData = this.EarlyDecodeWellKnownAttributes(binders, boundAttributeTypes, attributesToBind, symbolPart, attributesBuilder); Debug.Assert(!attributesBuilder.Contains((attr) => attr != null && attr.HasErrors)); // Store data decoded from early bound well-known attributes. // TODO: what if this succeeds on another thread, not ours? lazyCustomAttributesBag.SetEarlyDecodedWellKnownAttributeData(earlyData); if (earlyDecodingOnly) { diagnostics.Free(); //NOTE: dropped. return(false); } // Bind attributes. Binder.GetAttributes(binders, attributesToBind, boundAttributeTypes, attributesBuilder, diagnostics); boundAttributes = attributesBuilder.AsImmutableOrNull(); // All attributes must be bound by now. Debug.Assert(!boundAttributes.Any((attr) => attr == null)); // Validate attribute usage and Decode remaining well-known attributes. wellKnownAttributeData = this.ValidateAttributeUsageAndDecodeWellKnownAttributes(binders, attributesToBind, boundAttributes, diagnostics, symbolPart); // Store data decoded from remaining well-known attributes. // TODO: what if this succeeds on another thread but not this thread? lazyCustomAttributesBag.SetDecodedWellKnownAttributeData(wellKnownAttributeData); } else if (earlyDecodingOnly) { diagnostics.Free(); //NOTE: dropped. return(false); } else { boundAttributes = ImmutableArray <CSharpAttributeData> .Empty; wellKnownAttributeData = null; Interlocked.CompareExchange(ref lazyCustomAttributesBag, CustomAttributesBag <CSharpAttributeData> .WithEmptyData(), null); this.PostEarlyDecodeWellKnownAttributeTypes(); } this.PostDecodeWellKnownAttributes(boundAttributes, attributesToBind, diagnostics, symbolPart, wellKnownAttributeData); // Store attributes into the bag. bool lazyAttributesStoredOnThisThread = false; if (lazyCustomAttributesBag.SetAttributes(boundAttributes)) { this.AddDeclarationDiagnostics(diagnostics); lazyAttributesStoredOnThisThread = true; if (lazyCustomAttributesBag.IsEmpty) { lazyCustomAttributesBag = CustomAttributesBag <CSharpAttributeData> .Empty; } } Debug.Assert(lazyCustomAttributesBag.IsSealed); diagnostics.Free(); return(lazyAttributesStoredOnThisThread); }
internal void ComputeReturnType() { if (_lazyReturnType is object) { return; } var diagnostics = DiagnosticBag.GetInstance(); TypeSyntax returnTypeSyntax = _syntax.ReturnType; TypeWithAnnotations returnType = _binder.BindType(returnTypeSyntax.SkipRef(), diagnostics); var compilation = DeclaringCompilation; // Skip some diagnostics when the local function is not associated with a compilation // (specifically, local functions nested in expressions in the EE). if (compilation is object) { if (this.IsAsync) { if (this.RefKind != RefKind.None) { ReportBadRefToken(returnTypeSyntax, diagnostics); } else if (returnType.Type.IsBadAsyncReturn(compilation)) { diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, this.Locations[0]); } } var location = _syntax.ReturnType.Location; if (_refKind == RefKind.RefReadOnly) { compilation.EnsureIsReadOnlyAttributeExists(diagnostics, location, modifyCompilation: false); } if (compilation.ShouldEmitNullableAttributes(this) && returnType.NeedsNullableAttribute()) { compilation.EnsureNullableAttributeExists(diagnostics, location, modifyCompilation: false); // Note: we don't need to warn on annotations used in #nullable disable context for local functions, as this is handled in binding already } } // span-like types are returnable in general if (returnType.IsRestrictedType(ignoreSpanLikeTypes: true)) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, returnTypeSyntax.Location, returnType.Type); } Debug.Assert(_refKind == RefKind.None || !returnType.IsVoidType() || returnTypeSyntax.HasErrors); lock (_declarationDiagnostics) { if (_lazyReturnType is object) { diagnostics.Free(); return; } _declarationDiagnostics.AddRangeAndFree(diagnostics); Interlocked.CompareExchange(ref _lazyReturnType, new TypeWithAnnotations.Boxed(returnType), null); } }
public static bool ReportDelegateMethodGroupDiagnostics(Binder binder, BoundMethodGroup expr, TypeSymbol targetType, DiagnosticBag diagnostics) { var invokeMethodOpt = GetDelegateInvokeMethodIfAvailable(targetType); HashSet <DiagnosticInfo> useSiteDiagnostics = null; var resolution = ResolveDelegateMethodGroup(binder, expr, invokeMethodOpt, ref useSiteDiagnostics); diagnostics.Add(expr.Syntax, useSiteDiagnostics); bool hasErrors = resolution.HasAnyErrors; diagnostics.AddRange(resolution.Diagnostics); // SPEC VIOLATION: Unfortunately, we cannot exactly implement the specification for // the scenario in which an extension method that extends a value type is converted // to a delegate. The code we generate that captures a delegate to a static method // that is "partially evaluated" with the bound-to-the-delegate first argument // requires that the first argument be of reference type. // // SPEC VIOLATION: Similarly, we cannot capture a method of Nullable<T>, because // boxing a Nullable<T> gives a T, not a boxed Nullable<T>. // // We give special error messages in these situations. if (resolution.MethodGroup != null) { var result = resolution.OverloadResolutionResult; if (result != null) { if (result.Succeeded) { var method = result.BestResult.Member; Debug.Assert((object)method != null); if (resolution.MethodGroup.IsExtensionMethodGroup) { Debug.Assert(method.IsExtensionMethod); var thisParameter = method.Parameters[0]; if (!thisParameter.Type.IsReferenceType) { // Extension method '{0}' defined on value type '{1}' cannot be used to create delegates diagnostics.Add( ErrorCode.ERR_ValueTypeExtDelegate, expr.Syntax.Location, method, thisParameter.Type); hasErrors = true; } } else if (method.OriginalDefinition.ContainingType.SpecialType == SpecialType.System_Nullable_T && !method.IsOverride) { // CS1728: Cannot bind delegate to '{0}' because it is a member of 'System.Nullable<T>' diagnostics.Add( ErrorCode.ERR_DelegateOnNullable, expr.Syntax.Location, method); hasErrors = true; } } else if (!hasErrors && !resolution.IsEmpty && resolution.ResultKind == LookupResultKind.Viable) { var overloadDiagnostics = DiagnosticBag.GetInstance(); result.ReportDiagnostics(binder, expr.Syntax.Location, overloadDiagnostics, expr.Name, resolution.MethodGroup.Receiver, resolution.AnalyzedArguments, resolution.MethodGroup.Methods.ToImmutable(), typeContainingConstructor: null, delegateTypeBeingInvoked: null, isMethodGroupConversion: true); if (!overloadDiagnostics.IsEmptyWithoutResolution) { hasErrors = overloadDiagnostics.HasAnyErrors(); diagnostics.AddRange(overloadDiagnostics); } overloadDiagnostics.Free(); } } } resolution.Free(); return(hasErrors); }
internal sealed override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if ((object)lazyType != null) { return(lazyType); } var declarator = VariableDeclaratorNode; var fieldSyntax = GetFieldDeclaration(declarator); var typeSyntax = fieldSyntax.Declaration.Type; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbol type; // When we have multiple declarators, we report the type diagnostics on only the first. DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance(); Symbol associatedPropertyOrEvent = this.AssociatedSymbol; if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event) { EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T> // type that has additional generic constraints? type = tokenTableType.Construct(@event.Type); } else { type = @event.Type; } } else { var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); binder = binder.WithContainingMemberOrLambda(this); if (!ContainingType.IsScriptClass) { type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator); if (IsFixed) { type = new PointerTypeSymbol(type); } } else { bool isVar; type = binder.BindType(typeSyntax, diagnostics, out isVar); Debug.Assert((object)type != null || isVar); if (isVar) { if (this.IsConst) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location); } if (fieldsBeingBound.ContainsReference(this)) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this); type = null; } else if (fieldSyntax.Declaration.Variables.Count > 1) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location); } else { fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound); var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound); var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, declarator.Initializer, declarator); if (initializerOpt != null) { if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType()) { type = initializerOpt.Type; } this.lazyFieldTypeInferred = 1; } } if ((object)type == null) { type = binder.CreateErrorType("var"); } } } if (IsFixed) { if (ContainingType.TypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation); } if (IsStatic) { diagnostics.Add(ErrorCode.ERR_BadMemberFlag, ErrorLocation, SyntaxFacts.GetText(SyntaxKind.StaticKeyword)); } if (IsVolatile) { diagnostics.Add(ErrorCode.ERR_BadMemberFlag, ErrorLocation, SyntaxFacts.GetText(SyntaxKind.VolatileKeyword)); } var elementType = ((PointerTypeSymbol)type).PointedAtType; int elementSize = elementType.FixedBufferElementSizeInBytes(); if (elementSize == 0) { var loc = typeSyntax.Location; diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc); } if (!binder.InUnsafeRegion) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location); } } } // update the lazyType only if it contains value last seen by the current thread: if ((object)Interlocked.CompareExchange(ref lazyType, type, null) == null) { TypeChecks(type, fieldSyntax, declarator, diagnostics); // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics. compilation.SemanticDiagnostics.AddRange(diagnostics); bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator; if (isFirstDeclarator) { compilation.SemanticDiagnostics.AddRange(diagnosticsForFirstDeclarator); } state.NotePartComplete(CompletionPart.Type); } diagnostics.Free(); diagnosticsForFirstDeclarator.Free(); return(lazyType); }
internal BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type, Binder?binderOpt, DiagnosticBag?diagnosticsOpt) { Debug.Assert(binderOpt != null || type.HasType); Debug.Assert(this.Syntax.Kind() == SyntaxKind.SingleVariableDesignation || (this.Syntax.Kind() == SyntaxKind.DeclarationExpression && ((DeclarationExpressionSyntax)this.Syntax).Designation.Kind() == SyntaxKind.SingleVariableDesignation)); bool inferenceFailed = !type.HasType; if (inferenceFailed) { type = TypeWithAnnotations.Create(binderOpt !.CreateErrorType("var")); } switch (this.VariableSymbol.Kind) { case SymbolKind.Local: var localSymbol = (SourceLocalSymbol)this.VariableSymbol; if (diagnosticsOpt != null) { if (inferenceFailed) { ReportInferenceFailure(diagnosticsOpt); } else { SyntaxNode typeOrDesignationSyntax = this.Syntax.Kind() == SyntaxKind.DeclarationExpression ? ((DeclarationExpressionSyntax)this.Syntax).Type : this.Syntax; Binder.CheckRestrictedTypeInAsyncMethod(localSymbol.ContainingSymbol, type.Type, diagnosticsOpt, typeOrDesignationSyntax); } } localSymbol.SetTypeWithAnnotations(type); return(new BoundLocal(this.Syntax, localSymbol, BoundLocalDeclarationKind.WithInferredType, constantValueOpt: null, isNullableUnknown: false, type: type.Type, hasErrors: this.HasErrors || inferenceFailed).WithWasConverted()); case SymbolKind.Field: var fieldSymbol = (GlobalExpressionVariable)this.VariableSymbol; var inferenceDiagnostics = DiagnosticBag.GetInstance(); if (inferenceFailed) { ReportInferenceFailure(inferenceDiagnostics); } type = fieldSymbol.SetTypeWithAnnotations(type, inferenceDiagnostics); inferenceDiagnostics.Free(); return(new BoundFieldAccess(this.Syntax, this.ReceiverOpt, fieldSymbol, null, LookupResultKind.Viable, isDeclaration: true, type: type.Type, hasErrors: this.HasErrors || inferenceFailed)); default: throw ExceptionUtilities.UnexpectedValue(this.VariableSymbol.Kind); } }
internal override bool CompileImpl(CommonPEModuleBuilder moduleBuilder, Stream win32Resources, Stream xmlDocStream, bool emittingPdb, DiagnosticBag diagnostics, Predicate <ISymbol> filterOpt, CancellationToken cancellationToken) { // The diagnostics should include syntax and declaration errors. We insert these before calling Emitter.Emit, so that the emitter // does not attempt to emit if there are declaration errors (but we do insert all errors from method body binding...) bool hasDeclarationErrors = false; // !FilterAndAppendDiagnostics(diagnostics, GetDiagnostics(CompilationStage.Declare, true, cancellationToken)); var moduleBeingBuilt = (PEModuleBuilder)moduleBuilder; if (moduleBeingBuilt.EmitOptions.EmitMetadataOnly) { throw new NotImplementedException(); } // Perform initial bind of method bodies in spite of earlier errors. This is the same // behavior as when calling GetDiagnostics() // Use a temporary bag so we don't have to refilter pre-existing diagnostics. DiagnosticBag methodBodyDiagnosticBag = DiagnosticBag.GetInstance(); SourceCompiler.CompileSources( this, moduleBeingBuilt, emittingPdb, hasDeclarationErrors, methodBodyDiagnosticBag, cancellationToken); SetupWin32Resources(moduleBeingBuilt, win32Resources, methodBodyDiagnosticBag); ReportManifestResourceDuplicates( moduleBeingBuilt.ManifestResources, SourceAssembly.Modules.Skip(1).Select((m) => m.Name), //all modules except the first one AddedModulesResourceNames(methodBodyDiagnosticBag), methodBodyDiagnosticBag); bool hasMethodBodyErrorOrWarningAsError = !FilterAndAppendAndFreeDiagnostics(diagnostics, ref methodBodyDiagnosticBag); if (hasDeclarationErrors || hasMethodBodyErrorOrWarningAsError) { return(false); } cancellationToken.ThrowIfCancellationRequested(); // Use a temporary bag so we don't have to refilter pre-existing diagnostics. DiagnosticBag xmlDiagnostics = DiagnosticBag.GetInstance(); //string assemblyName = FileNameUtilities.ChangeExtension(moduleBeingBuilt.EmitOptions.OutputNameOverride, extension: null); //DocumentationCommentCompiler.WriteDocumentationCommentXml(this, assemblyName, xmlDocStream, xmlDiagnostics, cancellationToken); if (!FilterAndAppendAndFreeDiagnostics(diagnostics, ref xmlDiagnostics)) { return(false); } //// Use a temporary bag so we don't have to refilter pre-existing diagnostics. //DiagnosticBag importDiagnostics = DiagnosticBag.GetInstance(); //this.ReportUnusedImports(importDiagnostics, cancellationToken); //if (!FilterAndAppendAndFreeDiagnostics(diagnostics, ref importDiagnostics)) //{ // Debug.Assert(false, "Should never produce an error"); // return false; //} return(true); }
internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingType, Binder binder, SyntaxTokenList modifiers, VariableDeclaratorSyntax declaratorSyntax, DiagnosticBag diagnostics) : base(containingType, declaratorSyntax, modifiers, null, declaratorSyntax.Identifier, diagnostics) { this.name = declaratorSyntax.Identifier.ValueText; var declaratorDiagnostics = DiagnosticBag.GetInstance(); var declarationSyntax = (VariableDeclarationSyntax)declaratorSyntax.Parent; this.type = BindEventType(binder, declarationSyntax.Type, declaratorDiagnostics); // The runtime will not treat the accessors of this event as overrides or implementations // of those of another event unless both the signatures and the custom modifiers match. // Hence, in the case of overrides and *explicit* implementations (not possible for field-like // events), we need to copy the custom modifiers that are in the signatures of the // overridden/implemented event accessors. (From source, we know that there can only be one // overridden/implemented event, so there are no conflicts.) This is unnecessary for implicit // implementations because, if the custom modifiers don't match, we'll insert bridge methods // for the accessors (explicit implementations that delegate to the implicit implementations) // with the correct custom modifiers (see SourceNamedTypeSymbol.ImplementInterfaceMember). // If this event is an override, we may need to copy custom modifiers from // the overridden event (so that the runtime will recognize it as an override). // We check for this case here, while we can still modify the parameters and // return type without losing the appearance of immutability. if (this.IsOverride) { EventSymbol overriddenEvent = this.OverriddenEvent; if ((object)overriddenEvent != null) { CopyEventCustomModifiers(overriddenEvent, ref this.type); } } bool hasInitializer = declaratorSyntax.Initializer != null; bool inInterfaceType = containingType.IsInterfaceType(); if (hasInitializer) { if (inInterfaceType) { diagnostics.Add(ErrorCode.ERR_InterfaceEventInitializer, this.Locations[0], this); } else if (this.IsAbstract) { diagnostics.Add(ErrorCode.ERR_AbstractEventInitializer, this.Locations[0], this); } } // NOTE: if there's an initializer in source, we'd better create a backing field, regardless of // whether or not the initializer is legal. if (hasInitializer || !(inInterfaceType || this.IsExtern || this.IsAbstract)) { this.associatedField = MakeAssociatedField(declaratorSyntax); // Don't initialize this.type - we'll just use the type of the field (which is lazy and handles var) } // Accessors will assume that Type is available. this.addMethod = new SynthesizedFieldLikeEventAccessorSymbol(this, isAdder: true); this.removeMethod = new SynthesizedFieldLikeEventAccessorSymbol(this, isAdder: false); if (declarationSyntax.Variables[0] == declaratorSyntax) { // Don't report these diagnostics for every declarator in this declaration. diagnostics.AddRange(declaratorDiagnostics); } declaratorDiagnostics.Free(); }
void EmitOpCode(ILBuilder il, ILOpCode code) { il.EmitOpCode(code); il.EmitToken(_fieldref, null, DiagnosticBag.GetInstance()); // .{field} }