From 297b0ba5f953cded9e6439afb0a8885674934641 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Mon, 25 Nov 2019 13:17:27 -0800 Subject: [PATCH] Track assemblies declaring well-known types used by a compilation. Related to #37768. --- .../Portable/Binder/Binder.ValueChecks.cs | 2 +- .../CSharp/Portable/Binder/Binder.cs | 3 +- .../Portable/Binder/Binder_Conversions.cs | 2 +- .../Portable/Binder/Binder_Deconstruct.cs | 10 +- .../Portable/Binder/Binder_Expressions.cs | 37 +- .../CSharp/Portable/Binder/Binder_Lookup.cs | 12 +- .../CSharp/Portable/Binder/Binder_Patterns.cs | 11 +- .../Portable/Binder/Binder_QueryErrors.cs | 4 +- .../Portable/Binder/Binder_Statements.cs | 4 +- .../CSharp/Portable/Binder/Binder_Symbols.cs | 29 +- .../Portable/Binder/Binder_TupleOperators.cs | 2 +- .../Portable/Binder/ForEachLoopBinder.cs | 16 +- .../CSharp/Portable/Binder/InMethodBinder.cs | 4 +- .../Semantics/Conversions/Conversions.cs | 6 +- .../Portable/Binder/UsingStatementBinder.cs | 4 +- .../Portable/BoundTree/UnboundLambda.cs | 4 +- .../Portable/CodeGen/EmitArrayInitializer.cs | 22 +- .../CSharp/Portable/CodeGen/EmitExpression.cs | 16 +- .../Portable/Compilation/CSharpCompilation.cs | 67 +- .../Compilation/MemberSemanticModel.cs | 2 +- .../Compiler/MethodBodySynthesizer.cs | 4 +- .../Portable/Compiler/MethodCompiler.cs | 100 ++- .../Emitter/Model/PEAssemblyBuilder.cs | 10 +- .../Portable/Emitter/Model/PEModuleBuilder.cs | 21 +- .../Model/TypeParameterSymbolAdapter.cs | 2 +- .../Emitter/NoPia/EmbeddedTypesManager.cs | 2 +- .../Portable/FlowAnalysis/NullableWalker.cs | 8 +- .../AsyncMethodToStateMachineRewriter.cs | 2 +- .../Lowering/AsyncRewriter/AsyncRewriter.cs | 2 +- .../AsyncRewriter/AsyncStateMachine.cs | 12 +- .../Lowering/DiagnosticsPass_Warnings.cs | 4 +- .../DynamicAnalysisInjector.cs | 2 +- .../Lowering/LocalRewriter/LocalRewriter.cs | 6 +- .../LocalRewriter_AssignmentOperator.cs | 5 +- .../LocalRewriter/LocalRewriter_Call.cs | 8 +- ...writer_DeconstructionAssignmentOperator.cs | 2 +- .../LocalRewriter/LocalRewriter_Field.cs | 8 +- .../LocalRewriter_ForEachStatement.cs | 12 +- .../LocalRewriter_IndexerAccess.cs | 8 +- .../LocalRewriter/LocalRewriter_StackAlloc.cs | 2 +- .../LocalRewriter_TupleCreationExpression.cs | 16 +- .../LocalRewriter_UsingStatement.cs | 4 +- .../LoweredDynamicOperationFactory.cs | 5 +- .../Lowering/SyntheticBoundNodeFactory.cs | 6 +- .../AnonymousTypeManager.SymbolCollection.cs | 10 +- .../Symbols/Attributes/AttributeData.cs | 4 +- .../Attributes/RetargetingAttributeData.cs | 2 +- .../Symbols/Attributes/SourceAttributeData.cs | 2 +- .../Symbols/Compilation_UsedAssemblies.cs | 26 +- .../Symbols/Compilation_WellKnownMembers.cs | 76 +- .../CSharp/Portable/Symbols/MethodSymbol.cs | 4 +- .../Symbols/Source/SourceAssemblySymbol.cs | 38 +- .../Source/SourceComplexParameterSymbol.cs | 4 +- .../Source/SourceEventAccessorSymbol.cs | 2 +- .../Symbols/Source/SourceFixedFieldSymbol.cs | 2 +- .../Symbols/Source/SourceMemberFieldSymbol.cs | 16 +- .../Source/SourceMemberMethodSymbol.cs | 2 +- .../Symbols/Source/SourceModuleSymbol.cs | 2 +- .../Source/SourceOrdinaryMethodSymbol.cs | 7 +- .../Symbols/Source/SourceParameterSymbol.cs | 2 +- .../Source/SourcePropertyAccessorSymbol.cs | 4 +- .../Symbols/Source/SourcePropertySymbol.cs | 2 +- .../SynthesizedEventAccessorSymbol.cs | 2 +- .../Synthesized/SynthesizedFieldSymbolBase.cs | 4 +- ...SynthesizedInteractiveInitializerMethod.cs | 2 +- .../Synthesized/SynthesizedParameterSymbol.cs | 4 +- .../Symbols/Tuples/TupleTypeSymbol.cs | 15 +- .../Portable/Symbols/TypeSymbolExtensions.cs | 13 +- .../Symbols/UsedAssembliesRecorder.cs | 24 + .../Attributes/AttributeTests_Assembly.cs | 4 +- .../Emit/CodeGen/CodeGenAsyncIteratorTests.cs | 7 +- .../Test/Emit/CodeGen/CodeGenMscorlib.cs | 3 +- .../CSharp/Test/Emit/CodeGen/CodeGenTests.cs | 1 + .../Test/Emit/CodeGen/CodeGenTupleTest.cs | 3 +- .../Test/Semantic/Semantics/ForEachTests.cs | 26 + .../Semantics/NullableReferenceTypesTests.cs | 4 +- .../Test/Semantic/Semantics/OperatorTests.cs | 6 +- .../Semantics/RefLocalsAndReturnsTests.cs | 3 +- .../Test/Semantic/Semantics/UnsafeTests.cs | 2 + .../Semantics/UserDefinedConversionTests.cs | 4 +- .../Symbol/Compilation/UsedAssembliesTests.cs | 738 +++++++++++++++++- .../Symbol/Symbols/IndexedPropertyTests.cs | 4 +- .../Symbols/Source/CustomModifierCopyTests.cs | 4 + .../Test/Symbol/Symbols/Source/EventTests.cs | 3 +- .../Test/Syntax/Diagnostics/DiagnosticTest.cs | 3 +- .../Portable/Emit/CommonPEModuleBuilder.cs | 3 +- .../Portable/PEWriter/ReferenceIndexerBase.cs | 4 + .../Test/Utilities/CSharp/CSharpTestBase.cs | 75 +- .../Test/Utilities/CSharp/Extensions.cs | 10 + .../Portable/Emit/PEModuleBuilder.vb | 13 - .../CompilationExtensions.cs | 4 +- .../Rewriters/LocalDeclarationRewriter.cs | 4 +- 92 files changed, 1289 insertions(+), 416 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 3b8ada7e32c95..5246d9161a02c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -396,7 +396,7 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin if (boundAccess.Indices.Length == 1 && TypeSymbol.Equals( boundAccess.Indices[0].Type, - Compilation.GetWellKnownType(WellKnownType.System_Range), + Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything)) { // Range indexer is an rvalue diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 970011bce940a..6849f9e0f5c82 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -669,6 +669,7 @@ internal bool IsSymbolAccessibleConditional( internal static void ReportUseSiteDiagnosticForSynthesizedAttribute( CSharpCompilation compilation, WellKnownMember attributeMember, + bool recordUsage, DiagnosticBag diagnostics, Location location = null, CSharpSyntaxNode syntax = null) @@ -679,7 +680,7 @@ internal static void ReportUseSiteDiagnosticForSynthesizedAttribute( // (comes from an unified assembly). When the symbol is not found no error is reported. See test VersionUnification_UseSiteDiagnostics_OptionalAttributes. bool isOptional = WellKnownMembers.IsSynthesizedAttributeOptional(attributeMember); - GetWellKnownTypeMember(compilation, attributeMember, diagnostics, location, syntax, isOptional); + GetWellKnownTypeMember(compilation, attributeMember, recordUsage, diagnostics, location, syntax, isOptional); } #if DEBUG diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 8942b402d7205..38f9b1ba04150 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -394,7 +394,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre break; case ConversionKind.StackAllocToSpanType: CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefStructs, diagnostics); - stackAllocType = Compilation.GetWellKnownType(WellKnownType.System_Span_T).Construct(elementType); + stackAllocType = Compilation.GetWellKnownType(WellKnownType.System_Span_T, recordUsage: false).Construct(elementType); break; default: throw ExceptionUtilities.UnexpectedValue(conversion.Kind); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs index 9e6dddbb414f0..cee7bdc28bc91 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs @@ -214,7 +214,7 @@ private BoundExpression FixTupleLiteral(ArrayBuilder che // If we already have diagnostics at this point, it is not worth collecting likely duplicate diagnostics from making the merged type bool hadErrors = diagnostics.HasAnyErrors(); - TypeSymbol mergedTupleType = MakeMergedTupleType(checkedVariables, (BoundTupleLiteral)boundRHS, syntax, Compilation, hadErrors ? null : diagnostics); + TypeSymbol mergedTupleType = MakeMergedTupleType(checkedVariables, (BoundTupleLiteral)boundRHS, syntax, hadErrors ? null : diagnostics); if ((object)mergedTupleType != null) { boundRHS = GenerateConversionForAssignment(mergedTupleType, boundRHS, diagnostics); @@ -457,7 +457,7 @@ private string GetDebuggerDisplay() /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type. /// Returns null if a merged tuple type could not be fabricated. /// - private static TypeSymbol MakeMergedTupleType(ArrayBuilder lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics) + private TypeSymbol MakeMergedTupleType(ArrayBuilder lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, DiagnosticBag diagnostics) { int leftLength = lhsVariables.Count; int rightLength = rhsLiteral.Arguments.Length; @@ -477,7 +477,7 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder), - compilation: compilation, + compilation: Compilation, diagnostics: diagnostics, shouldCheckConstraints: true, includeNullability: false, + recordUsage: !IsSemanticModelBinder, errorPositions: default(ImmutableArray), syntax: syntax); } @@ -572,6 +573,7 @@ private BoundTupleExpression DeconstructionVariablesAsTuple(CSharpSyntaxNode syn tupleNames, this.Compilation, shouldCheckConstraints: !ignoreDiagnosticsFromTuple, includeNullability: false, + recordUsage: !(ignoreDiagnosticsFromTuple || IsSemanticModelBinder), errorPositions: disallowInferredNames ? inferredPositions : default, syntax: syntax, diagnostics: ignoreDiagnosticsFromTuple ? null : diagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 6adf2f285e6ac..ee1c5d4c29d6f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -819,6 +819,7 @@ private BoundExpression BindDeclarationVariablesForErrorRecovery(TypeWithAnnotat Compilation, shouldCheckConstraints: false, includeNullability: false, + recordUsage: false, errorPositions: disallowInferredNames ? inferredPositions : default); return new BoundConvertedTupleLiteral(syntax, sourceTuple: null, wasTargetTyped: true, subExpressions, tupleNames, inferredPositions, tupleType); @@ -897,11 +898,11 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost tupleTypeOpt = TupleTypeSymbol.Create(node.Location, elements, locations, elementNames, this.Compilation, syntax: node, diagnostics: diagnostics, shouldCheckConstraints: true, - includeNullability: false, errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray)); + includeNullability: false, recordUsage: !IsSemanticModelBinder, errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray)); } else { - TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, diagnostics); + TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, recordUsage: !IsSemanticModelBinder, diagnostics); } // Always track the inferred positions in the bound node, so that conversions don't produce a warning @@ -1100,7 +1101,7 @@ private BoundExpression BindRefType(RefTypeExpressionSyntax node, DiagnosticBag bool hasErrors = argument.HasAnyErrors; TypeSymbol typedReferenceType = this.Compilation.GetSpecialType(SpecialType.System_TypedReference); - TypeSymbol typeType = this.Compilation.GetWellKnownType(WellKnownType.System_Type); + TypeSymbol typeType = this.GetWellKnownType(WellKnownType.System_Type, diagnostics, node); HashSet useSiteDiagnostics = null; Conversion conversion = this.Conversions.ClassifyConversionFromExpression(argument, typedReferenceType, ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); @@ -2074,7 +2075,7 @@ private BoundExpression BindFromEndIndexExpression(PrefixUnaryExpressionSyntax n } BoundExpression boundConversion = CreateConversion(boundOperand, conversion, intType, diagnostics); - MethodSymbol symbolOpt = GetWellKnownTypeMember(Compilation, WellKnownMember.System_Index__ctor, diagnostics, syntax: node) as MethodSymbol; + MethodSymbol symbolOpt = GetWellKnownTypeMember(WellKnownMember.System_Index__ctor, diagnostics, syntax: node) as MethodSymbol; return new BoundFromEndIndexExpression(node, boundConversion, symbolOpt, indexType); } @@ -2110,7 +2111,6 @@ private BoundExpression BindRangeExpression(RangeExpressionSyntax node, Diagnost if (memberOpt is object) { symbolOpt = (MethodSymbol)GetWellKnownTypeMember( - Compilation, memberOpt.GetValueOrDefault(), diagnostics, syntax: node, @@ -2120,7 +2120,6 @@ private BoundExpression BindRangeExpression(RangeExpressionSyntax node, Diagnost if (symbolOpt is null) { symbolOpt = (MethodSymbol)GetWellKnownTypeMember( - Compilation, WellKnownMember.System_Range__ctor, diagnostics, syntax: node); @@ -6136,10 +6135,10 @@ private bool IsWinRTAsyncInterface(TypeSymbol type) var namedType = ((NamedTypeSymbol)type).ConstructedFrom; return - TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncAction), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncActionWithProgress_T), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperation_T), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperationWithProgress_T2), TypeCompareKind.ConsiderEverything2); + TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncAction, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncActionWithProgress_T, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperation_T, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperationWithProgress_T2, recordUsage: false), TypeCompareKind.ConsiderEverything2); } private BoundExpression BindMemberAccessBadResult(BoundMethodGroup node) @@ -7070,7 +7069,7 @@ private BoundExpression BindArrayAccess(ExpressionSyntax node, BoundExpression e TypeSymbol resultType = rank == 1 && TypeSymbol.Equals( convertedArguments[0].Type, - Compilation.GetWellKnownType(WellKnownType.System_Range), + Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything) ? arrayType : arrayType.ElementType; @@ -7110,7 +7109,6 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no { // This member is needed for lowering and should produce an error if not present _ = GetWellKnownTypeMember( - Compilation, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T, diagnostics, syntax: node); @@ -7120,7 +7118,6 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no { // This member is needed for lowering and should produce an error if not present _ = GetWellKnownTypeMember( - Compilation, WellKnownMember.System_Index__GetOffset, diagnostics, syntax: node); @@ -7146,7 +7143,7 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no private BoundExpression TryImplicitConversionToArrayIndex(BoundExpression expr, WellKnownType wellKnownType, SyntaxNode node, DiagnosticBag diagnostics) { HashSet useSiteDiagnostics = null; - TypeSymbol type = GetWellKnownType(wellKnownType, ref useSiteDiagnostics); + TypeSymbol type = GetWellKnownTypeWithoutRecordingUsage(wellKnownType, ref useSiteDiagnostics); if (type.IsErrorType()) { @@ -7157,6 +7154,12 @@ private BoundExpression TryImplicitConversionToArrayIndex(BoundExpression expr, var result = TryImplicitConversionToArrayIndex(expr, type, node, attemptDiagnostics); if (result is object) { + if (!IsSemanticModelBinder) + { + Compilation.AddUsedAssembly(type.ContainingAssembly); + } + + diagnostics.Add(node, useSiteDiagnostics); diagnostics.AddRange(attemptDiagnostics); } attemptDiagnostics.Free(); @@ -7577,10 +7580,10 @@ private bool TryBindIndexOrRangeIndexer( var argType = arguments[0].Type; bool argIsIndex = TypeSymbol.Equals(argType, - Compilation.GetWellKnownType(WellKnownType.System_Index), + Compilation.GetWellKnownType(WellKnownType.System_Index, recordUsage: false), TypeCompareKind.ConsiderEverything); bool argIsRange = !argIsIndex && TypeSymbol.Equals(argType, - Compilation.GetWellKnownType(WellKnownType.System_Range), + Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything); if ((!argIsIndex && !argIsRange) || @@ -7741,7 +7744,7 @@ void checkWellKnown(WellKnownMember member) // Check required well-known member. They may not be needed // during lowering, but it's simpler to always require them to prevent // the user from getting surprising errors when optimizations fail - _ = GetWellKnownTypeMember(Compilation, member, diagnostics, syntax: syntax); + _ = GetWellKnownTypeMember(member, diagnostics, syntax: syntax); } bool tryLookupLengthOrCount(string propertyName, out PropertySymbol valid) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs index e07f600f2ca01..fec05a429d273 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs @@ -854,12 +854,12 @@ private void AddWinRTMembers( private void GetWellKnownWinRTMemberInterfaces(out NamedTypeSymbol idictSymbol, out NamedTypeSymbol iroDictSymbol, out NamedTypeSymbol iListSymbol, out NamedTypeSymbol iCollectionSymbol, out NamedTypeSymbol inccSymbol, out NamedTypeSymbol inpcSymbol) { - idictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IDictionary_KV); - iroDictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IReadOnlyDictionary_KV); - iListSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_IList); - iCollectionSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection); - inccSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Specialized_INotifyCollectionChanged); - inpcSymbol = Compilation.GetWellKnownType(WellKnownType.System_ComponentModel_INotifyPropertyChanged); + idictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IDictionary_KV, recordUsage: false); + iroDictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IReadOnlyDictionary_KV, recordUsage: false); + iListSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_IList, recordUsage: false); + iCollectionSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection, recordUsage: false); + inccSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Specialized_INotifyCollectionChanged, recordUsage: false); + inpcSymbol = Compilation.GetWellKnownType(WellKnownType.System_ComponentModel_INotifyPropertyChanged, recordUsage: false); } private static bool ShouldAddWinRTMembersForInterface(NamedTypeSymbol iface, NamedTypeSymbol idictSymbol, NamedTypeSymbol iroDictSymbol, NamedTypeSymbol iListSymbol, NamedTypeSymbol iCollectionSymbol, NamedTypeSymbol inccSymbol, NamedTypeSymbol inpcSymbol) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index 5acffe51db662..310e90e375000 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -766,7 +766,7 @@ private bool ShouldUseITuple( return false; } - iTupleType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ITuple); + iTupleType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ITuple, recordUsage: false); if (iTupleType.TypeKind != TypeKind.Interface) { // When compiling to a platform that lacks the interface ITuple (i.e. it is an error type), we simply do not match using it. @@ -784,8 +784,8 @@ private bool ShouldUseITuple( } // Ensure ITuple has a Length and indexer - iTupleGetLength = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length); - iTupleGetItem = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item); + iTupleGetLength = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length, recordUsage: false); + iTupleGetItem = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item, recordUsage: false); if (iTupleGetLength is null || iTupleGetItem is null) { // This might not result in an ideal diagnostic @@ -793,6 +793,11 @@ private bool ShouldUseITuple( } // passed all the filters; permit using ITuple + if (!IsSemanticModelBinder) + { + Compilation.AddUsedAssembly(iTupleType.ContainingAssembly); + } + return true; bool hasBaseInterface(TypeSymbol type, NamedTypeSymbol possibleBaseInterface) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs b/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs index d9dc865f4dbc2..9265423de62b6 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_QueryErrors.cs @@ -83,7 +83,7 @@ private bool ImplementsStandardQueryInterface(TypeSymbol instanceType, string na bool nonUnique = false; var originalType = instanceType.OriginalDefinition; var ienumerable_t = Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); - var iqueryable_t = Compilation.GetWellKnownType(WellKnownType.System_Linq_IQueryable_T); + var iqueryable_t = Compilation.GetWellKnownType(WellKnownType.System_Linq_IQueryable_T, recordUsage: false); bool isIenumerable = TypeSymbol.Equals(originalType, ienumerable_t, TypeCompareKind.ConsiderEverything2) || HasUniqueInterface(instanceType, ienumerable_t, ref nonUnique, ref useSiteDiagnostics); bool isQueryable = TypeSymbol.Equals(originalType, iqueryable_t, TypeCompareKind.ConsiderEverything2) || HasUniqueInterface(instanceType, iqueryable_t, ref nonUnique, ref useSiteDiagnostics); return isIenumerable != isQueryable && !nonUnique; @@ -121,7 +121,7 @@ private bool HasCastToQueryProvider(TypeSymbol instanceType, ref HashSet), syntax: syntax, diagnostics: diagnostics); @@ -861,7 +862,7 @@ private void ReportUseSiteDiagnosticForDynamic(DiagnosticBag diagnostics, Identi if (node.IsTypeInContextWhichNeedsDynamicAttribute()) { - if (!Compilation.HasDynamicEmitAttributes()) + if (!Compilation.HasDynamicEmitAttributes(recordUsage: !IsSemanticModelBinder)) { // CONSIDER: Native compiler reports error CS1980 for each syntax node which binds to dynamic type, we do the same by reporting a diagnostic here. // However, this means we generate multiple duplicate diagnostics, when a single one would suffice. @@ -1411,7 +1412,7 @@ internal static bool ReportUseSiteDiagnostics(Symbol symbol, DiagnosticBag diagn /// internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diagnostics, SyntaxNode node) { - NamedTypeSymbol typeSymbol = this.Compilation.GetWellKnownType(type); + NamedTypeSymbol typeSymbol = this.Compilation.GetWellKnownType(type, recordUsage: !IsSemanticModelBinder); Debug.Assert((object)typeSymbol != null, "Expect an error type if well-known type isn't found"); ReportUseSiteDiagnostics(typeSymbol, diagnostics, node); return typeSymbol; @@ -1421,24 +1422,29 @@ internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diag /// This is a layer on top of the Compilation version that generates a diagnostic if the well-known /// type isn't found. /// - internal NamedTypeSymbol GetWellKnownType(WellKnownType type, ref HashSet useSiteDiagnostics) + internal NamedTypeSymbol GetWellKnownTypeWithoutRecordingUsage(WellKnownType type, ref HashSet useSiteDiagnostics) { - NamedTypeSymbol typeSymbol = this.Compilation.GetWellKnownType(type); + NamedTypeSymbol typeSymbol = this.Compilation.GetWellKnownType(type, recordUsage: false); Debug.Assert((object)typeSymbol != null, "Expect an error type if well-known type isn't found"); HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, typeSymbol.GetUseSiteDiagnostic()); return typeSymbol; } + internal Symbol GetWellKnownTypeMember(WellKnownMember member, DiagnosticBag diagnostics, Location location = null, SyntaxNode syntax = null, bool isOptional = false) + { + return GetWellKnownTypeMember(Compilation, member, recordUsage: !IsSemanticModelBinder, diagnostics, location, syntax, isOptional); + } + /// /// Retrieves a well-known type member and reports diagnostics. /// /// Null if the symbol is missing. - internal static Symbol GetWellKnownTypeMember(CSharpCompilation compilation, WellKnownMember member, DiagnosticBag diagnostics, Location location = null, SyntaxNode syntax = null, bool isOptional = false) + internal static Symbol GetWellKnownTypeMember(CSharpCompilation compilation, WellKnownMember member, bool recordUsage, DiagnosticBag diagnostics, Location location = null, SyntaxNode syntax = null, bool isOptional = false) { Debug.Assert((syntax != null) ^ (location != null)); DiagnosticInfo useSiteDiagnostic; - Symbol memberSymbol = GetWellKnownTypeMember(compilation, member, out useSiteDiagnostic, isOptional); + Symbol memberSymbol = GetWellKnownTypeMemberWithoutRecordingUsage(compilation, member, out useSiteDiagnostic, isOptional); if (useSiteDiagnostic != null) { @@ -1446,12 +1452,17 @@ internal static Symbol GetWellKnownTypeMember(CSharpCompilation compilation, Wel Symbol.ReportUseSiteDiagnostic(useSiteDiagnostic, diagnostics, location ?? syntax.Location); } + if (memberSymbol is object && recordUsage) + { + compilation.AddUsedAssembly(memberSymbol.ContainingAssembly); + } + return memberSymbol; } - internal static Symbol GetWellKnownTypeMember(CSharpCompilation compilation, WellKnownMember member, out DiagnosticInfo diagnosticInfo, bool isOptional = false) + internal static Symbol GetWellKnownTypeMemberWithoutRecordingUsage(CSharpCompilation compilation, WellKnownMember member, out DiagnosticInfo diagnosticInfo, bool isOptional = false) { - Symbol memberSymbol = compilation.GetWellKnownTypeMember(member); + Symbol memberSymbol = compilation.GetWellKnownTypeMember(member, recordUsage: false); if ((object)memberSymbol != null) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs index 61acfef4645f4..9a49f1f66728e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs @@ -397,7 +397,7 @@ private TypeSymbol MakeConvertedType(ImmutableArray convertedTypes, var tuple = TupleTypeSymbol.Create(locationOpt: null, elementTypesWithAnnotations: convertedTypes.SelectAsArray(t => TypeWithAnnotations.Create(t)), elementLocations, elementNames: names, compilation, - shouldCheckConstraints: true, includeNullability: false, errorPositions: default, syntax, diagnostics); + shouldCheckConstraints: true, includeNullability: false, errorPositions: default, recordUsage: !IsSemanticModelBinder, syntax, diagnostics); if (!isNullable) { diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 00d44d6bbcf15..da4947ea903b9 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -759,7 +759,7 @@ private EnumeratorResult GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder bui { diagnostics.Add(isAsync ? ErrorCode.ERR_MultipleIAsyncEnumOfT : ErrorCode.ERR_MultipleIEnumOfT, errorLocationSyntax.Location, collectionExprType, isAsync ? - this.Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T) : + this.Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false) : this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)); return EnumeratorResult.FailedAndReported; } @@ -782,9 +782,9 @@ private EnumeratorResult GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder bui if (isAsync) { - Debug.Assert(enumeratorType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T))); + Debug.Assert(enumeratorType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T, recordUsage: false))); - MethodSymbol moveNextAsync = (MethodSymbol)GetWellKnownTypeMember(Compilation, WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__MoveNextAsync, + MethodSymbol moveNextAsync = (MethodSymbol)GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__MoveNextAsync, diagnostics, errorLocationSyntax.Location, isOptional: false); if ((object)moveNextAsync != null) @@ -794,7 +794,7 @@ private EnumeratorResult GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder bui } MethodSymbol currentPropertyGetter = isAsync ? - (MethodSymbol)GetWellKnownTypeMember(Compilation, WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__get_Current, diagnostics, errorLocationSyntax.Location, isOptional: false) : + (MethodSymbol)GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerator_T__get_Current, diagnostics, errorLocationSyntax.Location, isOptional: false) : (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerator_T__get_Current, diagnostics, errorLocationSyntax); if ((object)currentPropertyGetter != null) @@ -855,7 +855,7 @@ private void GetDisposalInfoForEnumerator(ref ForEachEnumeratorInfo.Builder buil // For async foreach, we don't do the runtime check if ((!enumeratorType.IsSealed && !isAsync) || this.Conversions.ClassifyImplicitConversionFromType(enumeratorType, - isAsync ? this.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) : this.Compilation.GetSpecialType(SpecialType.System_IDisposable), + isAsync ? this.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable, recordUsage: false) : this.Compilation.GetSpecialType(SpecialType.System_IDisposable), ref useSiteDiagnostics).IsImplicit) { builder.NeedsDisposal = true; @@ -885,7 +885,7 @@ private MethodSymbol GetGetEnumeratorMethod(NamedTypeSymbol collectionType, Diag { Debug.Assert(IsIAsyncEnumerable(collectionType.OriginalDefinition)); - getEnumeratorMethod = (MethodSymbol)GetWellKnownTypeMember(Compilation, WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator, + getEnumeratorMethod = (MethodSymbol)GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator, diagnostics, errorLocationSyntax.Location, isOptional: false); } else @@ -1241,7 +1241,7 @@ private static bool IsIEnumerable(TypeSymbol type) private bool IsIAsyncEnumerable(TypeSymbol type) { - return type.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T)); + return type.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false)); } /// @@ -1341,7 +1341,7 @@ internal static bool IsIEnumerableT(TypeSymbol type, bool isAsync, CSharpCompila { if (isAsync) { - return type.Equals(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T)); + return type.Equals(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false)); } else { diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index 4ca2ddcddeece..82dcb8d7765f6 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -202,8 +202,8 @@ internal static (TypeWithAnnotations elementType, bool asyncInterface) GetIterat return (((NamedTypeSymbol)returnType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0], false); } - if (TypeSymbol.Equals(originalDefinition, compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(originalDefinition, compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T), TypeCompareKind.ConsiderEverything2)) + if (TypeSymbol.Equals(originalDefinition, compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(originalDefinition, compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T, recordUsage: false), TypeCompareKind.ConsiderEverything2)) { return (((NamedTypeSymbol)returnType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0], true); } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs index 1de5281d084b1..5c527ccc0f8ff 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs @@ -62,8 +62,8 @@ protected override Conversion GetInterpolatedStringConversion(BoundInterpolatedS { // An interpolated string expression may be converted to the types // System.IFormattable and System.FormattableString - return (TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_IFormattable), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_FormattableString), TypeCompareKind.ConsiderEverything2)) + return (TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_IFormattable, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_FormattableString, recordUsage: false), TypeCompareKind.ConsiderEverything2)) ? Conversion.InterpolatedString : Conversion.NoConversion; } @@ -318,7 +318,7 @@ public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation } else { - var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics); + var spanType = _binder.GetWellKnownTypeWithoutRecordingUsage(WellKnownType.System_Span_T, ref useSiteDiagnostics); if (spanType.TypeKind == TypeKind.Struct && spanType.IsRefLikeType) { var spanType_T = spanType.Construct(sourceExpression.ElementType); diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index 6a85fdbebbc12..b89fbc3e63062 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -183,7 +183,7 @@ bool populateDisposableConversionOrDisposeMethod(bool fromExpression, out Conver { if (hasAwait) { - awaitableTypeOpt = originalBinder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); + awaitableTypeOpt = originalBinder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask, recordUsage: !originalBinder.IsSemanticModelBinder); } return true; } @@ -237,7 +237,7 @@ Conversion classifyConversion(bool fromExpression, TypeSymbol targetInterface, r TypeSymbol getDisposableInterface(bool isAsync) { return isAsync - ? originalBinder.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) + ? originalBinder.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable, recordUsage: !originalBinder.IsSemanticModelBinder) : originalBinder.Compilation.GetSpecialType(SpecialType.System_IDisposable); } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index c5ca7e2dd7247..c95a7cf79957e 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -250,7 +250,7 @@ private static TypeWithAnnotations CalculateReturnType( // or infer type Task if delegate type not available. var resultType = (object)taskType != null && taskType.Arity == 0 ? taskType : - compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task); + compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task, recordUsage: false); return TypeWithAnnotations.Create(resultType); } @@ -265,7 +265,7 @@ private static TypeWithAnnotations CalculateReturnType( // or infer type Task if delegate type not available. var taskTypeT = (object)taskType != null && taskType.Arity == 1 ? taskType : - compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); + compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T, recordUsage: false); return TypeWithAnnotations.Create(taskTypeT.Construct(ImmutableArray.Create(bestResultType))); } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index 6fa25b0f37177..5c917eb696073 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -219,6 +219,24 @@ private static ConstantValue AsConstOrDefault(BoundExpression init) return ConstantValue.Default(type.SpecialType); } + /// + /// Determine if enum arrays can be initialized using block initialization. + /// + /// True if it's safe to use block initialization for enum arrays. + /// + /// In NetFx 4.0, block array initializers do not work on all combinations of {32/64 X Debug/Retail} when array elements are enums. + /// This is fixed in 4.5 thus enabling block array initialization for a very common case. + /// We look for the presence of which was introduced in .NET Framework 4.5 + /// + private bool EnableEnumArrayBlockInitialization + { + get + { + var sustainedLowLatency = _module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_GCLatencyMode__SustainedLowLatency, recordUsage: false); + return sustainedLowLatency != null && sustainedLowLatency.ContainingAssembly == _module.Compilation.Assembly.CorLibrary; + } + } + private ArrayInitializerStyle ShouldEmitBlockInitializer(TypeSymbol elementType, ImmutableArray inits) { if (!_module.SupportsPrivateImplClass) @@ -228,7 +246,7 @@ private ArrayInitializerStyle ShouldEmitBlockInitializer(TypeSymbol elementType, if (elementType.IsEnumType()) { - if (!_module.Compilation.EnableEnumArrayBlockInitialization) + if (!EnableEnumArrayBlockInitialization) { return ArrayInitializerStyle.Element; } @@ -359,7 +377,7 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp return false; } - var ctor = ((MethodSymbol)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor)); + var ctor = ((MethodSymbol)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor, recordUsage: false)); if (ctor == null) { return false; diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 87eb97ff0ea28..814d9bf8ff778 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -1996,14 +1996,14 @@ private bool ConstructorNotSideEffecting(MethodSymbol constructor) } if (originalDef.ContainingType.Name == TupleTypeSymbol.TupleTypeName && - (originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__ctor) || - originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T1__ctor))) + (originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T2__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T3__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T4__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T5__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T6__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T7__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_TRest__ctor, recordUsage: false) || + originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T1__ctor, recordUsage: false))) { return true; } diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index ac4044fc99c9c..f11f6b36a4a6c 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -1756,8 +1757,8 @@ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, DiagnosticBag dia } // Early bail so we only ever check things that are System.Threading.Tasks.Task() - if (!(TypeSymbol.Equals(namedType.ConstructedFrom, GetWellKnownType(WellKnownType.System_Threading_Tasks_Task), TypeCompareKind.ConsiderEverything2) || - TypeSymbol.Equals(namedType.ConstructedFrom, GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T), TypeCompareKind.ConsiderEverything2))) + if (!(TypeSymbol.Equals(namedType.ConstructedFrom, GetWellKnownType(WellKnownType.System_Threading_Tasks_Task, recordUsage: false), TypeCompareKind.ConsiderEverything2) || + TypeSymbol.Equals(namedType.ConstructedFrom, GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T, recordUsage: false), TypeCompareKind.ConsiderEverything2))) { return false; } @@ -2298,6 +2299,15 @@ internal override void GetDiagnostics(CompilationStage stage, bool includeEarlie { var builder = DiagnosticBag.GetInstance(); + GetDiagnosticsWithoutFiltering(stage, includeEarlierStages, builder, cancellationToken); + + // Before returning diagnostics, we filter warnings + // to honor the compiler options (e.g., /nowarn, /warnaserror and /warn) and the pragmas. + FilterAndAppendAndFreeDiagnostics(diagnostics, ref builder); + } + + private void GetDiagnosticsWithoutFiltering(CompilationStage stage, bool includeEarlierStages, DiagnosticBag builder, CancellationToken cancellationToken) + { if (stage == CompilationStage.Parse || (stage > CompilationStage.Parse && includeEarlierStages)) { var syntaxTrees = this.SyntaxTrees; @@ -2375,13 +2385,9 @@ internal override void GetDiagnostics(CompilationStage stage, bool includeEarlie if (stage == CompilationStage.Compile || stage > CompilationStage.Compile && includeEarlierStages) { var methodBodyDiagnostics = DiagnosticBag.GetInstance(); - GetDiagnosticsForAllMethodBodies(methodBodyDiagnostics, cancellationToken); + GetDiagnosticsForAllMethodBodies(methodBodyDiagnostics, doLowering: false, cancellationToken); builder.AddRangeAndFree(methodBodyDiagnostics); } - - // Before returning diagnostics, we filter warnings - // to honor the compiler options (e.g., /nowarn, /warnaserror and /warn) and the pragmas. - FilterAndAppendAndFreeDiagnostics(diagnostics, ref builder); } private static void AppendLoadDirectiveDiagnostics(DiagnosticBag builder, SyntaxAndDeclarationManager syntaxAndDeclarations, SyntaxTree syntaxTree, Func, IEnumerable> locationFilterOpt = null) @@ -2404,14 +2410,24 @@ private static void AppendLoadDirectiveDiagnostics(DiagnosticBag builder, Syntax // Do the steps in compilation to get the method body diagnostics, but don't actually generate // IL or emit an assembly. - private void GetDiagnosticsForAllMethodBodies(DiagnosticBag diagnostics, CancellationToken cancellationToken) + private void GetDiagnosticsForAllMethodBodies(DiagnosticBag diagnostics, bool doLowering, CancellationToken cancellationToken) { MethodCompiler.CompileMethodBodies( compilation: this, - moduleBeingBuiltOpt: null, + moduleBeingBuiltOpt: doLowering ? (PEModuleBuilder)CreateModuleBuilder( + emitOptions: EmitOptions.Default, + debugEntryPoint: null, + manifestResources: null, + sourceLinkStream: null, + embeddedTexts: null, + testData: null, + diagnostics: diagnostics, + cancellationToken: cancellationToken) + : null, emittingPdb: false, emitTestCoverageData: false, hasDeclarationErrors: false, + emitMethodBodies: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken); @@ -2446,6 +2462,7 @@ private ImmutableArray GetDiagnosticsForMethodBodiesInTree(SyntaxTre emittingPdb: false, emitTestCoverageData: false, hasDeclarationErrors: false, + emitMethodBodies: false, diagnostics: diagnostics, filterOpt: s => IsDefinedOrImplementedInSourceTree(s, tree, span), cancellationToken: cancellationToken); @@ -2757,6 +2774,7 @@ internal override bool CompileMethods( emittingPdb, emitTestCoverageData, hasDeclarationErrors, + emitMethodBodies: moduleBeingBuilt is object, diagnostics: methodBodyDiagnosticBag, filterOpt: filterOpt, cancellationToken: cancellationToken); @@ -3144,7 +3162,8 @@ protected override INamedTypeSymbol CommonCreateTupleTypeSymbol( compilation: this, shouldCheckConstraints: false, includeNullability: false, - errorPositions: default(ImmutableArray)).GetPublicSymbol(); + errorPositions: default(ImmutableArray), + recordUsage: false).GetPublicSymbol(); } protected override INamedTypeSymbol CommonCreateTupleTypeSymbol( @@ -3341,15 +3360,15 @@ internal override int CompareSourceLocations(SyntaxReference loc1, SyntaxReferen /// dynamic types. /// /// - internal bool HasDynamicEmitAttributes() + internal bool HasDynamicEmitAttributes(bool recordUsage) { return - (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctor) != null && - (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctorTransformFlags) != null; + (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctor, recordUsage) != null && + (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctorTransformFlags, recordUsage) != null; } - internal bool HasTupleNamesAttributes => - (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames) != null; + internal bool HasTupleNamesAttributes(bool recordUsage) => + (object)GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames, recordUsage) != null; /// /// Returns whether the compilation has the Boolean type and if it's good. @@ -3434,24 +3453,6 @@ internal void SymbolDeclaredEvent(Symbol symbol) EventQueue?.TryEnqueue(new SymbolDeclaredCompilationEvent(this, symbol.GetPublicSymbol())); } - /// - /// Determine if enum arrays can be initialized using block initialization. - /// - /// True if it's safe to use block initialization for enum arrays. - /// - /// In NetFx 4.0, block array initializers do not work on all combinations of {32/64 X Debug/Retail} when array elements are enums. - /// This is fixed in 4.5 thus enabling block array initialization for a very common case. - /// We look for the presence of which was introduced in .NET Framework 4.5 - /// - internal bool EnableEnumArrayBlockInitialization - { - get - { - var sustainedLowLatency = GetWellKnownTypeMember(WellKnownMember.System_Runtime_GCLatencyMode__SustainedLowLatency); - return sustainedLowLatency != null && sustainedLowLatency.ContainingAssembly == Assembly.CorLibrary; - } - } - private abstract class AbstractSymbolSearcher { private readonly PooledDictionary _cache; diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index c7cbcaa5e3d12..c3f528d2e14f9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -951,7 +951,7 @@ public override ForEachStatementInfo GetForEachStatementInfo(CommonForEachStatem else { disposeMethod = enumeratorInfoOpt.IsAsync - ? (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_IAsyncDisposable__DisposeAsync) + ? (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_IAsyncDisposable__DisposeAsync, recordUsage: false) : (MethodSymbol)Compilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose); } } diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs index 75ad34772bede..c6ebe529ca0c3 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs @@ -240,6 +240,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable, + recordUsage: true, diagnostics, syntax: syntax); @@ -258,6 +259,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEvent MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, processHandlerMember, + recordUsage: false, // Recorded above, when looked for WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable diagnostics, syntax: syntax); @@ -381,7 +383,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEve BoundExpression delegateUpdate; - MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); + MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T, recordUsage: true); if ((object)compareExchangeMethod == null) { diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index e25734bc316cd..53e96ea99e2a2 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -28,6 +28,7 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor _filterOpt; // If not null, limit analysis to specific symbols private readonly DebugDocumentProvider _debugDocumentProvider; @@ -77,7 +78,7 @@ private void SetGlobalErrorIfTrue(bool arg) } // Internal for testing only. - internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool emittingPdb, bool emitTestCoverageData, bool hasDeclarationErrors, + internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool emittingPdb, bool emitTestCoverageData, bool hasDeclarationErrors, bool emitMethodBodies, DiagnosticBag diagnostics, Predicate filterOpt, SynthesizedEntryPointSymbol.AsyncForwardEntryPoint entryPointOpt, CancellationToken cancellationToken) { Debug.Assert(compilation != null); @@ -100,6 +101,7 @@ internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBei } _emitTestCoverageData = emitTestCoverageData; + _emitMethodBodies = emitMethodBodies; } public static void CompileMethodBodies( @@ -108,6 +110,7 @@ public static void CompileMethodBodies( bool emittingPdb, bool emitTestCoverageData, bool hasDeclarationErrors, + bool emitMethodBodies, DiagnosticBag diagnostics, Predicate filterOpt, CancellationToken cancellationToken) @@ -129,7 +132,7 @@ public static void CompileMethodBodies( MethodSymbol entryPoint = null; if (filterOpt is null) { - entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, hasDeclarationErrors, diagnostics, cancellationToken); + entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, hasDeclarationErrors, emitMethodBodies, diagnostics, cancellationToken); } var methodCompiler = new MethodCompiler( @@ -138,6 +141,7 @@ public static void CompileMethodBodies( emittingPdb, emitTestCoverageData, hasDeclarationErrors, + emitMethodBodies, diagnostics, filterOpt, entryPoint as SynthesizedEntryPointSymbol.AsyncForwardEntryPoint, @@ -161,8 +165,12 @@ public static void CompileMethodBodies( var embeddedTypes = moduleBeingBuiltOpt.GetEmbeddedTypes(diagnostics); methodCompiler.CompileSynthesizedMethods(embeddedTypes, diagnostics); - // By this time we have processed all types reachable from module's global namespace - compilation.AnonymousTypeManager.AssignTemplatesNamesAndCompile(methodCompiler, moduleBeingBuiltOpt, diagnostics); + if (emitMethodBodies) + { + // By this time we have processed all types reachable from module's global namespace + compilation.AnonymousTypeManager.AssignTemplatesNamesAndCompile(methodCompiler, moduleBeingBuiltOpt, diagnostics); + } + methodCompiler.WaitForWorkers(); var privateImplClass = moduleBeingBuiltOpt.PrivateImplClass; @@ -200,7 +208,7 @@ public static void CompileMethodBodies( // Returns the MethodSymbol for the assembly entrypoint. If the user has a Task returning main, // this function returns the synthesized Main MethodSymbol. - private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, DiagnosticBag diagnostics, CancellationToken cancellationToken) + private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, bool emitMethodBodies, DiagnosticBag diagnostics, CancellationToken cancellationToken) { var entryPointAndDiagnostics = compilation.GetEntryPointAndDiagnostics(cancellationToken); if (entryPointAndDiagnostics == null) @@ -276,23 +284,26 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul lambdaDebugInfoBuilder.Free(); closureDebugInfoBuilder.Free(); - var emittedBody = GenerateMethodBody( - moduleBeingBuilt, - synthesizedEntryPoint, - methodOrdinal, - loweredBody, - ImmutableArray.Empty, - ImmutableArray.Empty, - stateMachineTypeOpt: null, - variableSlotAllocatorOpt: null, - diagnostics: diagnostics, - debugDocumentProvider: null, - importChainOpt: null, - emittingPdb: false, - emitTestCoverageData: false, - dynamicAnalysisSpans: ImmutableArray.Empty, - entryPointOpt: null); - moduleBeingBuilt.SetMethodBody(synthesizedEntryPoint, emittedBody); + if (emitMethodBodies) + { + var emittedBody = GenerateMethodBody( + moduleBeingBuilt, + synthesizedEntryPoint, + methodOrdinal, + loweredBody, + ImmutableArray.Empty, + ImmutableArray.Empty, + stateMachineTypeOpt: null, + variableSlotAllocatorOpt: null, + diagnostics: diagnostics, + debugDocumentProvider: null, + importChainOpt: null, + emittingPdb: false, + emitTestCoverageData: false, + dynamicAnalysisSpans: ImmutableArray.Empty, + entryPointOpt: null); + moduleBeingBuilt.SetMethodBody(synthesizedEntryPoint, emittedBody); + } } return entryPoint; @@ -723,7 +734,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) stateMachine = stateMachine ?? asyncStateMachine; } - if (!diagnosticsThisMethod.HasAnyErrors() && !_globalHasErrors) + if (!diagnosticsThisMethod.HasAnyErrors() && !_globalHasErrors && _emitMethodBodies) { emittedBody = GenerateMethodBody( _moduleBeingBuiltOpt, @@ -828,7 +839,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i // we cannot rely on GlobalHasErrors since that can be changed concurrently by other methods compiling // we however do not want to continue with generating method body if we have errors in this particular method - generating may crash // or if had declaration errors - we will fail anyways, but if some types are bad enough, generating may produce duplicate errors about that. - if (!hasErrors && !_hasDeclarationErrors) + if (!hasErrors && !_hasDeclarationErrors && _emitMethodBodies) { const int accessorOrdinal = -1; @@ -1228,28 +1239,31 @@ private void CompileMethod( } } - CSharpSyntaxNode syntax = methodSymbol.GetNonNullSyntaxNode(); + if (_emitMethodBodies) + { + CSharpSyntaxNode syntax = methodSymbol.GetNonNullSyntaxNode(); - var boundBody = BoundStatementList.Synthesized(syntax, boundStatements); + var boundBody = BoundStatementList.Synthesized(syntax, boundStatements); - var emittedBody = GenerateMethodBody( - _moduleBeingBuiltOpt, - methodSymbol, - methodOrdinal, - boundBody, - lambdaDebugInfoBuilder.ToImmutable(), - closureDebugInfoBuilder.ToImmutable(), - stateMachineTypeOpt, - lazyVariableSlotAllocator, - diagsForCurrentMethod, - _debugDocumentProvider, - importChain, - _emittingPdb, - _emitTestCoverageData, - dynamicAnalysisSpans, - entryPointOpt: null); + var emittedBody = GenerateMethodBody( + _moduleBeingBuiltOpt, + methodSymbol, + methodOrdinal, + boundBody, + lambdaDebugInfoBuilder.ToImmutable(), + closureDebugInfoBuilder.ToImmutable(), + stateMachineTypeOpt, + lazyVariableSlotAllocator, + diagsForCurrentMethod, + _debugDocumentProvider, + importChain, + _emittingPdb, + _emitTestCoverageData, + dynamicAnalysisSpans, + entryPointOpt: null); - _moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody); + _moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody); + } } _diagnostics.AddRange(diagsForCurrentMethod); diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index a0d8bfd74da68..52a9adb5dd194 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -273,7 +273,7 @@ private void CreateEmbeddedAttributesIfNeeded(DiagnosticBag diagnostics) EmbeddableAttributes needsAttributes = GetNeedsGeneratedAttributes(); if (ShouldEmitNullablePublicOnlyAttribute() && - Compilation.CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes.NullablePublicOnlyAttribute, diagnostics, Location.None)) + Compilation.CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes.NullablePublicOnlyAttribute, recordUsage: true, diagnostics, Location.None)) { needsAttributes |= EmbeddableAttributes.NullablePublicOnlyAttribute; } @@ -434,7 +434,7 @@ private NamespaceSymbol GetOrSynthesizeNamespace(string namespaceFullName) private NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diagnostics) { - var result = _sourceAssembly.DeclaringCompilation.GetWellKnownType(type); + var result = _sourceAssembly.DeclaringCompilation.GetWellKnownType(type, recordUsage: true); Binder.ReportUseSiteDiagnostics(result, diagnostics, Location.None); return result; } @@ -449,9 +449,9 @@ private NamedTypeSymbol GetSpecialType(SpecialType type, DiagnosticBag diagnosti private void EnsureAttributeUsageAttributeMembersAvailable(DiagnosticBag diagnostics) { var compilation = _sourceAssembly.DeclaringCompilation; - Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__ctor, diagnostics, Location.None); - Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__AllowMultiple, diagnostics, Location.None); - Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__Inherited, diagnostics, Location.None); + Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__ctor, recordUsage: true, diagnostics, Location.None); + Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__AllowMultiple, recordUsage: true, diagnostics, Location.None); + Binder.GetWellKnownTypeMember(compilation, WellKnownMember.System_AttributeUsageAttribute__Inherited, recordUsage: true, diagnostics, Location.None); } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index aa69d2ea37d32..b5e830bb15d9f 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -655,24 +655,9 @@ internal sealed override Cci.INamedTypeReference GetSpecialType(SpecialType spec needDeclaration: true); } - internal sealed override Cci.INamedTypeReference GetSystemType(SyntaxNode syntaxOpt, DiagnosticBag diagnostics) - { - NamedTypeSymbol systemTypeSymbol = Compilation.GetWellKnownType(WellKnownType.System_Type); - - DiagnosticInfo info = systemTypeSymbol.GetUseSiteDiagnostic(); - if (info != null) - { - Symbol.ReportUseSiteDiagnostic(info, - diagnostics, - syntaxOpt != null ? syntaxOpt.Location : NoLocation.Singleton); - } - - return Translate(systemTypeSymbol, syntaxOpt, diagnostics, needDeclaration: true); - } - public sealed override Cci.IMethodReference GetInitArrayHelper() { - return (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__InitializeArrayArrayRuntimeFieldHandle); + return (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__InitializeArrayArrayRuntimeFieldHandle, recordUsage: false); } public sealed override bool IsPlatformType(Cci.ITypeReference typeRef, Cci.PlatformType platformType) @@ -682,7 +667,7 @@ public sealed override bool IsPlatformType(Cci.ITypeReference typeRef, Cci.Platf { if (platformType == Cci.PlatformType.SystemType) { - return (object)namedType == (object)Compilation.GetWellKnownType(WellKnownType.System_Type); + return (object)namedType == (object)Compilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false); } return namedType.SpecialType == (SpecialType)platformType; @@ -1559,7 +1544,7 @@ private void EnsureEmbeddableAttributeExists(EmbeddableAttributes attribute) } // Don't report any errors. They should be reported during binding. - if (Compilation.CheckIfAttributeShouldBeEmbedded(attribute, diagnosticsOpt: null, locationOpt: null)) + if (Compilation.CheckIfAttributeShouldBeEmbedded(attribute, recordUsage: false, diagnosticsOpt: null, locationOpt: null)) { SetNeedsGeneratedAttributes(attribute); } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/TypeParameterSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/TypeParameterSymbolAdapter.cs index 85357ce3862d9..8f02528763984 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/TypeParameterSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/TypeParameterSymbolAdapter.cs @@ -233,7 +233,7 @@ Cci.ITypeReference Cci.IGenericTypeParameterReference.DefiningType diagnostics: context.Diagnostics); var modifier = CSharpCustomModifier.CreateRequired( - moduleBeingBuilt.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType)); + moduleBeingBuilt.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType, recordUsage: false)); // emit "(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType" pattern as "unmanaged" yield return new Cci.TypeReferenceWithAttributes(new Cci.ModifiedTypeReference(typeRef, ImmutableArray.Create(modifier))); diff --git a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs index 072adaef5596d..067921badd9f9 100644 --- a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs +++ b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs @@ -72,7 +72,7 @@ private MethodSymbol LazyGetWellKnownTypeMethod(ref MethodSymbol lazyMethod, Wel if ((object)lazyMethod == (object)ErrorMethodSymbol.UnknownMethod) { DiagnosticInfo info; - var symbol = (MethodSymbol)Binder.GetWellKnownTypeMember(ModuleBeingBuilt.Compilation, + var symbol = (MethodSymbol)Binder.GetWellKnownTypeMemberWithoutRecordingUsage(ModuleBeingBuilt.Compilation, member, out info, isOptional: false); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 53f2d13f0f274..b93ced77f2bbe 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -2319,7 +2319,7 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node) TypeWithAnnotations result; if (node.Indices.Length == 1 && - TypeSymbol.Equals(node.Indices[0].Type, compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything2)) + TypeSymbol.Equals(node.Indices[0].Type, compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything2)) { result = TypeWithAnnotations.Create(type); } @@ -3221,7 +3221,7 @@ private void LearnFromEqualsMethod(MethodSymbol method, BoundCall node, TypeWith static bool isWellKnownEqualityMethodOrImplementation(CSharpCompilation compilation, MethodSymbol method, WellKnownMember wellKnownMember) { - var wellKnownMethod = compilation.GetWellKnownTypeMember(wellKnownMember); + var wellKnownMethod = compilation.GetWellKnownTypeMember(wellKnownMember, recordUsage: false); if (wellKnownMethod is null) { return false; @@ -3284,8 +3284,8 @@ void learnFromEqualsMethodArguments(BoundExpression left, TypeWithState leftType private void LearnFromCompareExchangeMethod(MethodSymbol method, BoundCall node, ImmutableArray results) { - var isCompareExchangeMethod = method.Equals(compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange), SymbolEqualityComparer.ConsiderEverything.CompareKind) - || method.OriginalDefinition.Equals(compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T), SymbolEqualityComparer.ConsiderEverything.CompareKind); + var isCompareExchangeMethod = method.Equals(compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange, recordUsage: false), SymbolEqualityComparer.ConsiderEverything.CompareKind) + || method.OriginalDefinition.Equals(compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T, recordUsage: false), SymbolEqualityComparer.ConsiderEverything.CompareKind); if (!isCompareExchangeMethod) { return; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index 1d5fdec00cb2e..b2013d43d9dd7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -552,7 +552,7 @@ private BoundStatement GenerateAwaitOnCompleted(TypeSymbol loweredAwaiterType, L HashSet useSiteDiagnostics = null; var useUnsafeOnCompleted = F.Compilation.Conversions.ClassifyImplicitConversionFromType( loweredAwaiterType, - F.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion), + F.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ICriticalNotifyCompletion, recordUsage: false), ref useSiteDiagnostics).IsImplicit; var onCompleted = (useUnsafeOnCompleted ? diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs index f753af0386925..6ae9f94fdae47 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs @@ -114,7 +114,7 @@ protected virtual void VerifyPresenceOfRequiredAPIs(DiagnosticBag bag) private Symbol EnsureWellKnownMember(WellKnownMember member, DiagnosticBag bag) { - return Binder.GetWellKnownTypeMember(F.Compilation, member, bag, body.Syntax.Location); + return Binder.GetWellKnownTypeMember(F.Compilation, member, recordUsage: true, bag, body.Syntax.Location); } protected override bool PreserveInitialParameterValuesAndThreadId diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncStateMachine.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncStateMachine.cs index f7dd29e231e27..935a7f03cb3cd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncStateMachine.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncStateMachine.cs @@ -35,23 +35,23 @@ public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompila if (isEnumerable) { // IAsyncEnumerable - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T).Construct(elementType)); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: true).Construct(elementType)); } // IAsyncEnumerator - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T).Construct(elementType)); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T, recordUsage: true).Construct(elementType)); // IValueTaskSource - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T).Construct(compilation.GetSpecialType(SpecialType.System_Boolean))); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T, recordUsage: true).Construct(compilation.GetSpecialType(SpecialType.System_Boolean))); // IValueTaskSource - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource)); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource, recordUsage: true)); // IAsyncDisposable - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable)); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable, recordUsage: true)); } - interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); + interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine, recordUsage: true)); _interfaces = interfaces.ToImmutableAndFree(); _constructor = isIterator ? (MethodSymbol)new IteratorConstructor(this) : new AsyncConstructor(this); diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs index c0fc6cbd93367..55940f0a0a3cc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_Warnings.cs @@ -107,7 +107,7 @@ internal static bool IsNonAgileFieldAccess(BoundFieldAccess fieldAccess, CSharpC { // NOTE: We're only trying to produce a warning, so there's no point in producing an // error if the well-known type we need for the check is missing. - NamedTypeSymbol marshalByRefType = compilation.GetWellKnownType(WellKnownType.System_MarshalByRefObject); + NamedTypeSymbol marshalByRefType = compilation.GetWellKnownType(WellKnownType.System_MarshalByRefObject, recordUsage: false); TypeSymbol baseType = fieldAccess.FieldSymbol.ContainingType; while ((object)baseType != null) @@ -146,7 +146,7 @@ private static bool IsInstanceFieldAccessWithNonThisReceiver(BoundFieldAccess fi private bool IsInterlockedAPI(Symbol method) { - var interlocked = _compilation.GetWellKnownType(WellKnownType.System_Threading_Interlocked); + var interlocked = _compilation.GetWellKnownType(WellKnownType.System_Threading_Interlocked, recordUsage: false); if ((object)interlocked != null && TypeSymbol.Equals(interlocked, method.ContainingType, TypeCompareKind.ConsiderEverything2)) return true; diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs index f6a79908b13fd..b0a7813456c20 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs @@ -567,7 +567,7 @@ private static SyntaxNode SyntaxForSpan(BoundStatement statement) private static MethodSymbol GetCreatePayloadOverload(CSharpCompilation compilation, WellKnownMember overload, SyntaxNode syntax, DiagnosticBag diagnostics) { - return (MethodSymbol)Binder.GetWellKnownTypeMember(compilation, overload, diagnostics, syntax: syntax); + return (MethodSymbol)Binder.GetWellKnownTypeMember(compilation, overload, recordUsage: true, diagnostics, syntax: syntax); } private static SyntaxNode MethodDeclarationIfAvailable(SyntaxNode body) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index a8a0e1f1f6f12..b8eec121d3865 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -397,7 +397,7 @@ private bool TryGetWellKnownTypeMember(SyntaxNode syntax, WellKnownMemb { Debug.Assert((syntax != null) ^ (location != null)); - symbol = (TSymbol)Binder.GetWellKnownTypeMember(_compilation, member, _diagnostics, syntax: syntax, isOptional: isOptional, location: location); + symbol = (TSymbol)Binder.GetWellKnownTypeMember(_compilation, member, recordUsage: true, _diagnostics, syntax: syntax, isOptional: isOptional, location: location); return ((object)symbol != null); } @@ -578,7 +578,7 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node) BoundNode resultExpr; if (TypeSymbol.Equals( indexType, - _compilation.GetWellKnownType(WellKnownType.System_Index), + _compilation.GetWellKnownType(WellKnownType.System_Index, recordUsage: false), TypeCompareKind.ConsiderEverything)) { // array[Index] is treated like a pattern-based System.Index indexing @@ -603,7 +603,7 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node) } else if (TypeSymbol.Equals( indexType, - _compilation.GetWellKnownType(WellKnownType.System_Range), + _compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything)) { // array[Range] is compiled to: diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs index 08b2f545c98e8..9426d9df784bd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs @@ -294,10 +294,11 @@ private BoundExpression MakePropertyAssignment( if ((object)setMethod == null) { - Debug.Assert((property as SourcePropertySymbol)?.IsAutoProperty == true, + Debug.Assert((property.OriginalDefinition as SourcePropertySymbol)?.IsAutoProperty == true, "only autoproperties can be assignable without having setters"); + Debug.Assert(property.Equals(property.OriginalDefinition, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); - var backingField = (property as SourcePropertySymbol).BackingField; + var backingField = ((SourcePropertySymbol)property.OriginalDefinition).BackingField; return _factory.AssignmentExpression( _factory.Field(rewrittenReceiver, backingField), rewrittenRight); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index 5e93da87d3944..062e3293737f7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -912,7 +912,7 @@ private BoundExpression BuildParamsArray( ArrayTypeSymbol ats = paramArrayType as ArrayTypeSymbol; if ((object)ats != null) // could be null if there's a semantic error, e.g. the params parameter type isn't an array { - MethodSymbol arrayEmpty = _compilation.GetWellKnownTypeMember(WellKnownMember.System_Array__Empty) as MethodSymbol; + MethodSymbol arrayEmpty = _compilation.GetWellKnownTypeMember(WellKnownMember.System_Array__Empty, recordUsage: true) as MethodSymbol; if (arrayEmpty != null) // will be null if Array.Empty doesn't exist in reference assemblies { // return an invocation of "Array.Empty()" @@ -1488,21 +1488,21 @@ private static BoundExpression GetDefaultParameterSpecialNoConversion(SyntaxNode else if (parameter.IsIUnknownConstant) { // new UnknownWrapper(default(object)) - var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor); + var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor, recordUsage: true); var argument = new BoundDefaultExpression(syntax, parameter.Type) { WasCompilerGenerated = true }; defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, null, argument) { WasCompilerGenerated = true }; } else if (parameter.IsIDispatchConstant) { // new DispatchWrapper(default(object)) - var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor); + var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor, recordUsage: true); var argument = new BoundDefaultExpression(syntax, parameter.Type) { WasCompilerGenerated = true }; defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, null, argument) { WasCompilerGenerated = true }; } else { // Type.Missing - var fieldSymbol = (FieldSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Type__Missing); + var fieldSymbol = (FieldSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Type__Missing, recordUsage: true); defaultValue = new BoundFieldAccess(syntax, null, fieldSymbol, ConstantValue.NotAvailable) { WasCompilerGenerated = true }; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs index 9c2b5d23a652f..62b9da8525aff 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs @@ -157,7 +157,7 @@ private BoundExpression ApplyDeconstructionConversion( { var tupleType = TupleTypeSymbol.Create(locationOpt: null, elementTypesWithAnnotations: builder.SelectAsArray(e => TypeWithAnnotations.Create(e.Type)), elementLocations: default, elementNames: default, - compilation: _compilation, shouldCheckConstraints: false, includeNullability: false, errorPositions: default); + compilation: _compilation, shouldCheckConstraints: false, includeNullability: false, errorPositions: default, recordUsage: true); return new BoundConvertedTupleLiteral( right.Syntax, sourceTuple: null, wasTargetTyped: false, arguments: builder.ToImmutableAndFree(), argumentNamesOpt: default, inferredNamesOpt: default, tupleType); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs index f740ba24c4687..7799796c4a72d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs @@ -73,7 +73,7 @@ private BoundExpression MakeTupleFieldAccess( if (!TypeSymbol.Equals(underlyingField.ContainingType, currentLinkType, TypeCompareKind.ConsiderEverything2)) { WellKnownMember wellKnownTupleRest = TupleTypeSymbol.GetTupleTypeMember(TupleTypeSymbol.RestPosition, TupleTypeSymbol.RestPosition); - var tupleRestField = (FieldSymbol)TupleTypeSymbol.GetWellKnownMemberInType(currentLinkType.OriginalDefinition, wellKnownTupleRest, _diagnostics, syntax); + var tupleRestField = (FieldSymbol)GetWellKnownMemberInTuple(currentLinkType.OriginalDefinition, wellKnownTupleRest, _diagnostics, syntax); if ((object)tupleRestField == null) { @@ -96,6 +96,12 @@ private BoundExpression MakeTupleFieldAccess( return _factory.Field(rewrittenReceiver, underlyingField); } + private Symbol GetWellKnownMemberInTuple(NamedTypeSymbol type, WellKnownMember relativeMember, DiagnosticBag diagnostics, SyntaxNode syntax) + { + _compilation.AddUsedAssembly(type.ContainingAssembly); + return TupleTypeSymbol.GetWellKnownMemberInType(type, relativeMember, diagnostics, syntax); + } + private BoundExpression MakeTupleFieldAccessAndReportUseSiteDiagnostics(BoundExpression tuple, SyntaxNode syntax, FieldSymbol field) { // Use default field rather than implicitly named fields since diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs index 3261a30a3c29d..f470fd4a80687 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs @@ -64,13 +64,13 @@ private bool CanRewriteForEachAsFor(SyntaxNode forEachSyntax, TypeSymbol nodeExp lengthGet = UnsafeGetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Length); indexerGet = UnsafeGetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Chars); } - else if ((object)origDefinition == this._compilation.GetWellKnownType(WellKnownType.System_Span_T)) + else if ((object)origDefinition == this._compilation.GetWellKnownType(WellKnownType.System_Span_T, recordUsage: false)) { var spanType = (NamedTypeSymbol)nodeExpressionType; lengthGet = (MethodSymbol)_factory.WellKnownMember(WellKnownMember.System_Span_T__get_Length, isOptional: true)?.SymbolAsMember(spanType); indexerGet = (MethodSymbol)_factory.WellKnownMember(WellKnownMember.System_Span_T__get_Item, isOptional: true)?.SymbolAsMember(spanType); } - else if ((object)origDefinition == this._compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T)) + else if ((object)origDefinition == this._compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T, recordUsage: false)) { var spanType = (NamedTypeSymbol)nodeExpressionType; lengthGet = (MethodSymbol)_factory.WellKnownMember(WellKnownMember.System_ReadOnlySpan_T__get_Length, isOptional: true)?.SymbolAsMember(spanType); @@ -215,7 +215,7 @@ private bool TryGetDisposeMethod(CommonForEachStatementSyntax forEachSyntax, For { if (enumeratorInfo.IsAsync) { - disposeMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(_compilation, WellKnownMember.System_IAsyncDisposable__DisposeAsync, _diagnostics, syntax: forEachSyntax); + disposeMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(_compilation, WellKnownMember.System_IAsyncDisposable__DisposeAsync, recordUsage: true, _diagnostics, syntax: forEachSyntax); return (object)disposeMethod != null; } @@ -241,6 +241,12 @@ private BoundStatement WrapWithTryFinallyDispose(CommonForEachStatementSyntax fo { TryGetDisposeMethod(forEachSyntax, enumeratorInfo, out disposeMethod); // interface-based + // PROTOTYPE(UsedAssemblyReferences): This is a temporary workaround for https://github.com/dotnet/roslyn/issues/39948 + if (disposeMethod is null) + { + return rewrittenBody; + } + idisposableTypeSymbol = disposeMethod.ContainingType; var conversions = new TypeConversions(_factory.CurrentFunction.ContainingAssembly.CorLibrary); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs index 9abaa96f3c3f5..e4c5c34c3f7fb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs @@ -167,7 +167,7 @@ private BoundSequence VisitIndexOrRangePatternIndexerAccess(BoundIndexOrRangePat { if (TypeSymbol.Equals( node.Argument.Type, - _compilation.GetWellKnownType(WellKnownType.System_Index), + _compilation.GetWellKnownType(WellKnownType.System_Index, recordUsage: false), TypeCompareKind.ConsiderEverything)) { return VisitIndexPatternIndexerAccess( @@ -182,7 +182,7 @@ private BoundSequence VisitIndexOrRangePatternIndexerAccess(BoundIndexOrRangePat { Debug.Assert(TypeSymbol.Equals( node.Argument.Type, - _compilation.GetWellKnownType(WellKnownType.System_Range), + _compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false), TypeCompareKind.ConsiderEverything)); return VisitRangePatternIndexerAccess( node.Receiver, @@ -277,7 +277,7 @@ private BoundExpression MakePatternIndexOffsetExpression( { Debug.Assert(TypeSymbol.Equals( unloweredExpr.Type, - _compilation.GetWellKnownType(WellKnownType.System_Index), + _compilation.GetWellKnownType(WellKnownType.System_Index, recordUsage: false), TypeCompareKind.ConsiderEverything)); var F = _factory; @@ -315,7 +315,7 @@ private BoundSequence VisitRangePatternIndexerAccess( { Debug.Assert(TypeSymbol.Equals( rangeArg.Type, - _compilation.GetWellKnownType(WellKnownType.System_Range), + _compilation.GetWellKnownType(WellKnownType.System_Range, false), TypeCompareKind.ConsiderEverything)); // Lowered code without optimizations: diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs index 37e61e66ba416..eb3e108fffc7b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StackAlloc.cs @@ -39,7 +39,7 @@ public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreat var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, stackAllocNode.Type); } - else if (TypeSymbol.Equals(type.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.ConsiderEverything2)) + else if (TypeSymbol.Equals(type.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_Span_T, recordUsage: false), TypeCompareKind.ConsiderEverything2)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var sideEffects = ArrayBuilder.GetInstance(); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs index de12b9cb4c9aa..55c929a3316bd 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs @@ -52,10 +52,10 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType ImmutableArray smallestCtorArguments = ImmutableArray.Create(rewrittenArguments, underlyingTupleTypeChain.Count * (TupleTypeSymbol.RestPosition - 1), smallestType.Arity); - var smallestCtor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition, - TupleTypeSymbol.GetTupleCtor(smallestType.Arity), - _diagnostics, - syntax); + var smallestCtor = (MethodSymbol)GetWellKnownMemberInTuple(smallestType.OriginalDefinition, + TupleTypeSymbol.GetTupleCtor(smallestType.Arity), + _diagnostics, + syntax); if ((object)smallestCtor == null) { return _factory.BadExpression(type); @@ -67,10 +67,10 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType if (underlyingTupleTypeChain.Count > 0) { NamedTypeSymbol tuple8Type = underlyingTupleTypeChain.Peek(); - var tuple8Ctor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition, - TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition), - _diagnostics, - syntax); + var tuple8Ctor = (MethodSymbol)GetWellKnownMemberInTuple(tuple8Type.OriginalDefinition, + TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition), + _diagnostics, + syntax); if ((object)tuple8Ctor == null) { return _factory.BadExpression(type); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs index 8036f94ac0014..e8ae83e724a69 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs @@ -155,7 +155,7 @@ private BoundBlock MakeExpressionUsingStatement(BoundUsingStatement node, BoundB // IAsyncDisposable temp = (IAsyncDisposable) expr; TypeSymbol iDisposableType = node.AwaitOpt is null ? _compilation.GetSpecialType(SpecialType.System_IDisposable) : - _compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable); + _compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable, recordUsage: true); BoundExpression tempInit = MakeConversionNode( expressionSyntax, @@ -221,7 +221,7 @@ private BoundBlock RewriteDeclarationUsingStatement(SyntaxNode usingSyntax, Boun { TypeSymbol iDisposableType = awaitOpt is null ? _compilation.GetSpecialType(SpecialType.System_IDisposable) : - _compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable); + _compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable, recordUsage: true); BoundExpression tempInit = MakeConversionNode( declarationSyntax, diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs index 30f35b6a23488..73b368b26ad2f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LoweredDynamicOperationFactory.cs @@ -706,7 +706,7 @@ internal FieldSymbol DefineCallSiteStorageSymbol(NamedTypeSymbol containerDefini { var fieldName = GeneratedNames.MakeDynamicCallSiteFieldName(_callSiteIdDispenser++); var delegateTypeOverContainerTypeParameters = methodToContainerTypeParametersMap.SubstituteNamedType(delegateTypeOverMethodTypeParameters); - var callSiteType = _factory.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CallSite_T).Construct(new[] { delegateTypeOverContainerTypeParameters }); + var callSiteType = _factory.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CallSite_T, recordUsage: true).Construct(new[] { delegateTypeOverContainerTypeParameters }); var field = new SynthesizedFieldSymbol(containerDefinition, callSiteType, fieldName, isPublic: true, isStatic: true); _factory.AddField(containerDefinition, field); return _currentDynamicCallSiteContainer.IsGenericType ? field.AsMember(_currentDynamicCallSiteContainer) : field; @@ -740,9 +740,10 @@ internal NamedTypeSymbol GetDelegateType( if (wkDelegateType != WellKnownType.Unknown) { - var delegateType = _factory.Compilation.GetWellKnownType(wkDelegateType); + var delegateType = _factory.Compilation.GetWellKnownType(wkDelegateType, recordUsage: false); if (!delegateType.HasUseSiteError) { + _factory.Compilation.AddUsedAssembly(delegateType.ContainingAssembly); return delegateType.Construct(delegateSignature); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 46753d8b090da..06a9c9170dbf8 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -321,7 +321,7 @@ public ArrayTypeSymbol WellKnownArrayType(WellKnownType elementType) public NamedTypeSymbol WellKnownType(WellKnownType wt) { - NamedTypeSymbol wellKnownType = Compilation.GetWellKnownType(wt); + NamedTypeSymbol wellKnownType = Compilation.GetWellKnownType(wt, recordUsage: true); Binder.ReportUseSiteDiagnostics(wellKnownType, Diagnostics, Syntax); return wellKnownType; } @@ -336,7 +336,7 @@ public NamedTypeSymbol WellKnownType(WellKnownType wt) /// A symbol for the well-known member, or null if it is missing and isOptions == true public Symbol WellKnownMember(WellKnownMember wm, bool isOptional = false) { - Symbol wellKnownMember = Binder.GetWellKnownTypeMember(Compilation, wm, Diagnostics, syntax: Syntax, isOptional: true); + Symbol wellKnownMember = Binder.GetWellKnownTypeMember(Compilation, wm, recordUsage: true, Diagnostics, syntax: Syntax, isOptional: true); if (wellKnownMember == null && !isOptional) { RuntimeMembers.MemberDescriptor memberDescriptor = WellKnownMembers.GetDescriptor(wm); @@ -1009,7 +1009,7 @@ public BoundStatement HiddenSequencePoint(BoundStatement statementOpt = null) public BoundStatement ThrowNull() { - return Throw(Null(Compilation.GetWellKnownType(Microsoft.CodeAnalysis.WellKnownType.System_Exception))); + return Throw(Null(Compilation.GetWellKnownType(Microsoft.CodeAnalysis.WellKnownType.System_Exception, recordUsage: true))); } public BoundExpression ThrowExpression(BoundExpression thrown, TypeSymbol type) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.SymbolCollection.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.SymbolCollection.cs index aa6f6eee34301..7fbbbc8f978fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.SymbolCollection.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.SymbolCollection.cs @@ -122,7 +122,7 @@ public NamedTypeSymbol System_Int32 public NamedTypeSymbol System_Diagnostics_DebuggerBrowsableState { - get { return Compilation.GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerBrowsableState); } + get { return Compilation.GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerBrowsableState, recordUsage: false); } } public MethodSymbol System_Object__Equals @@ -142,22 +142,22 @@ public MethodSymbol System_Object__GetHashCode public MethodSymbol System_Collections_Generic_EqualityComparer_T__Equals { - get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__Equals) as MethodSymbol; } + get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__Equals, recordUsage: false) as MethodSymbol; } } public MethodSymbol System_Collections_Generic_EqualityComparer_T__GetHashCode { - get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__GetHashCode) as MethodSymbol; } + get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__GetHashCode, recordUsage: false) as MethodSymbol; } } public MethodSymbol System_Collections_Generic_EqualityComparer_T__get_Default { - get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__get_Default) as MethodSymbol; } + get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_EqualityComparer_T__get_Default, recordUsage: false) as MethodSymbol; } } public MethodSymbol System_String__Format_IFormatProvider { - get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_String__Format_IFormatProvider) as MethodSymbol; } + get { return this.Compilation.GetWellKnownTypeMember(WellKnownMember.System_String__Format_IFormatProvider, recordUsage: false) as MethodSymbol; } } #endregion diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index 9758c47bcb390..2153012e13e01 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -115,7 +115,7 @@ internal bool IsSecurityAttribute(CSharpCompilation compilation) // Well-known type SecurityAttribute is optional. // Native compiler doesn't generate a use-site error if it is not found, we do the same. - var wellKnownType = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAttribute); + var wellKnownType = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAttribute, recordUsage: false); HashSet useSiteDiagnostics = null; _lazyIsSecurityAttribute = AttributeClass.IsDerivedFrom(wellKnownType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref useSiteDiagnostics).ToThreeState(); } @@ -265,7 +265,7 @@ private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSym { TypedConstant firstArg = ctorArgs.First(); TypeSymbol firstArgType = (TypeSymbol)firstArg.TypeInternal; - if ((object)firstArgType != null && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction))) + if ((object)firstArgType != null && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction, recordUsage: false))) { return DecodeSecurityAction(firstArg, targetSymbol, nodeOpt, diagnostics, out hasErrors); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs index 5c194090f7d60..b2aabc4d343c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs @@ -37,7 +37,7 @@ internal override TypeSymbol GetSystemType(Symbol targetSymbol) var underlyingAssembly = (SourceAssemblySymbol)retargetingAssembly.UnderlyingAssembly; // Get the System.Type from the underlying assembly's Compilation - TypeSymbol systemType = underlyingAssembly.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type); + TypeSymbol systemType = underlyingAssembly.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false); // Retarget the type var retargetingModule = (RetargetingModuleSymbol)retargetingAssembly.Modules[0]; diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs index 8d256322375a2..7b115538dac97 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs @@ -383,7 +383,7 @@ internal override int GetTargetAttributeSignatureIndex(Symbol targetSymbol, Attr /// System.Type type symbol. internal virtual TypeSymbol GetSystemType(Symbol targetSymbol) { - return targetSymbol.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type); + return targetSymbol.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Compilation_UsedAssemblies.cs b/src/Compilers/CSharp/Portable/Symbols/Compilation_UsedAssemblies.cs index 7e575434c8bdb..02310d76d17b4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Compilation_UsedAssemblies.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Compilation_UsedAssemblies.cs @@ -29,10 +29,13 @@ internal override ImmutableArray GetUsedAssemblyReferences(Ca foreach (var reference in References) { - if (reference.Properties.Kind == MetadataImageKind.Assembly && - usedAssemblies.Contains((AssemblySymbol)GetAssemblyOrModuleSymbol(reference))) + if (reference.Properties.Kind == MetadataImageKind.Assembly) { - builder.Add(reference); + Symbol symbol = GetAssemblyOrModuleSymbol(reference); + if (symbol is object && usedAssemblies.Contains((AssemblySymbol)symbol)) + { + builder.Add(reference); + } } } @@ -47,9 +50,18 @@ private ConcurrentSet GetCompleteSetOfUsedAssemblies(Cancellatio // and we either already encountered errors, or have done all the work // to record usage. var diagnostics = DiagnosticBag.GetInstance(); - GetDiagnostics(CompilationStage.Compile, includeEarlierStages: true, diagnostics, cancellationToken); + GetDiagnosticsWithoutFiltering(CompilationStage.Declare, includeEarlierStages: true, diagnostics, cancellationToken); + + bool seenErrors = diagnostics.HasAnyErrors(); + if (!seenErrors) + { + diagnostics.Clear(); + // PROTOTYPE(UsedAssemblyReferences): Might want to suppress nullable analysis for this call. + GetDiagnosticsForAllMethodBodies(diagnostics, doLowering: true, cancellationToken); + seenErrors = diagnostics.HasAnyErrors(); + } - completeTheSetOfUsedAssemblies(diagnostics, cancellationToken); + completeTheSetOfUsedAssemblies(seenErrors, cancellationToken); diagnostics.Free(); } @@ -75,14 +87,14 @@ void addReferencedAssemblies(AssemblySymbol assembly, bool includeMainModule, Ar } } - void completeTheSetOfUsedAssemblies(DiagnosticBag diagnostics, CancellationToken cancellationToken) + void completeTheSetOfUsedAssemblies(bool seenErrors, CancellationToken cancellationToken) { if (_usedAssemblyReferencesFrozen || Volatile.Read(ref _usedAssemblyReferencesFrozen)) { return; } - if (diagnostics.HasAnyErrors()) + if (seenErrors) { // Add all referenced assemblies foreach (var assembly in SourceModule.ReferencedAssemblySymbols) diff --git a/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs b/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs index ace67aa5ebda0..9353f3b982043 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Compilation_WellKnownMembers.cs @@ -69,7 +69,7 @@ private void SetUsesNullableAttributes() /// If a well-known member of a generic type instantiation is needed use this method to get the corresponding generic definition and /// to construct an instantiation. /// - internal Symbol GetWellKnownTypeMember(WellKnownMember member) + internal Symbol GetWellKnownTypeMember(WellKnownMember member, bool recordUsage) { Debug.Assert(member >= 0 && member < WellKnownMember.Count); @@ -93,7 +93,7 @@ internal Symbol GetWellKnownTypeMember(WellKnownMember member) MemberDescriptor descriptor = WellKnownMembers.GetDescriptor(member); NamedTypeSymbol type = descriptor.DeclaringTypeId <= (int)SpecialType.Count ? this.GetSpecialType((SpecialType)descriptor.DeclaringTypeId) - : this.GetWellKnownType((WellKnownType)descriptor.DeclaringTypeId); + : this.GetWellKnownType((WellKnownType)descriptor.DeclaringTypeId, recordUsage: false); Symbol result = null; if (!type.IsErrorType()) @@ -104,7 +104,14 @@ internal Symbol GetWellKnownTypeMember(WellKnownMember member) Interlocked.CompareExchange(ref _lazyWellKnownTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType); } - return _lazyWellKnownTypeMembers[(int)member]; + Symbol memberSymbol = _lazyWellKnownTypeMembers[(int)member]; + + if (memberSymbol is object && recordUsage) + { + AddUsedAssembly(memberSymbol.ContainingAssembly); + } + + return memberSymbol; } /// @@ -113,7 +120,7 @@ internal Symbol GetWellKnownTypeMember(WellKnownMember member) /// - 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) /// - internal NamedTypeSymbol GetWellKnownType(WellKnownType type) + internal NamedTypeSymbol GetWellKnownType(WellKnownType type, bool recordUsage) { Debug.Assert(type.IsValid()); @@ -184,7 +191,14 @@ internal NamedTypeSymbol GetWellKnownType(WellKnownType type) warnings.Free(); } - return _lazyWellKnownTypes[index]; + NamedTypeSymbol typeSymbol = _lazyWellKnownTypes[index]; + + if (recordUsage) + { + AddUsedAssembly(typeSymbol.ContainingAssembly); + } + + return typeSymbol; } internal bool IsAttributeType(TypeSymbol type) @@ -205,7 +219,7 @@ internal bool IsExceptionType(TypeSymbol type, ref HashSet useSi internal bool IsReadOnlySpanType(TypeSymbol type) { - return TypeSymbol.Equals(type.OriginalDefinition, GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.ConsiderEverything2); + return TypeSymbol.Equals(type.OriginalDefinition, GetWellKnownType(WellKnownType.System_ReadOnlySpan_T, recordUsage: false), TypeCompareKind.ConsiderEverything2); } internal bool IsEqualOrDerivedFromWellKnownClass(TypeSymbol type, WellKnownType wellKnownType, ref HashSet useSiteDiagnostics) @@ -218,23 +232,23 @@ internal bool IsEqualOrDerivedFromWellKnownClass(TypeSymbol type, WellKnownType return false; } - var wkType = GetWellKnownType(wellKnownType); + var wkType = GetWellKnownType(wellKnownType, recordUsage: false); return type.Equals(wkType, TypeCompareKind.ConsiderEverything) || type.IsDerivedFrom(wkType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref useSiteDiagnostics); } internal override bool IsSystemTypeReference(ITypeSymbolInternal type) { - return TypeSymbol.Equals((TypeSymbol)type, GetWellKnownType(WellKnownType.System_Type), TypeCompareKind.ConsiderEverything2); + return TypeSymbol.Equals((TypeSymbol)type, GetWellKnownType(WellKnownType.System_Type, recordUsage: false), TypeCompareKind.ConsiderEverything2); } internal override ISymbolInternal CommonGetWellKnownTypeMember(WellKnownMember member) { - return GetWellKnownTypeMember(member); + return GetWellKnownTypeMember(member, recordUsage: false); } internal override ITypeSymbolInternal CommonGetWellKnownType(WellKnownType wellknownType) { - return GetWellKnownType(wellknownType); + return GetWellKnownType(wellknownType, recordUsage: false); } internal static Symbol GetRuntimeMember(NamedTypeSymbol declaringType, ref MemberDescriptor descriptor, SignatureComparer comparer, AssemblySymbol accessWithinOpt) @@ -377,7 +391,7 @@ internal SynthesizedAttributeData TrySynthesizeAttribute( bool isOptionalUse = false) { DiagnosticInfo diagnosticInfo; - var ctorSymbol = (MethodSymbol)Binder.GetWellKnownTypeMember(this, constructor, out diagnosticInfo, isOptional: true); + var ctorSymbol = (MethodSymbol)Binder.GetWellKnownTypeMemberWithoutRecordingUsage(this, constructor, out diagnosticInfo, isOptional: true); if ((object)ctorSymbol == null) { @@ -401,7 +415,7 @@ internal SynthesizedAttributeData TrySynthesizeAttribute( var builder = new ArrayBuilder>(namedArguments.Length); foreach (var arg in namedArguments) { - var wellKnownMember = Binder.GetWellKnownTypeMember(this, arg.Key, out diagnosticInfo, isOptional: true); + var wellKnownMember = Binder.GetWellKnownTypeMemberWithoutRecordingUsage(this, arg.Key, out diagnosticInfo, isOptional: true); if (wellKnownMember == null || wellKnownMember is ErrorTypeSymbol) { // if this assert fails, UseSiteErrors for "member" have not been checked before emitting ... @@ -452,7 +466,7 @@ internal SynthesizedAttributeData SynthesizeDebuggerBrowsableNeverAttribute() return TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerBrowsableAttribute__ctor, ImmutableArray.Create(new TypedConstant( - GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerBrowsableState), + GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerBrowsableState, recordUsage: false), TypedConstantKind.Enum, DebuggerBrowsableState.Never))); } @@ -471,7 +485,7 @@ private void EnsureEmbeddableAttributeExists(EmbeddableAttributes attribute, Dia { Debug.Assert(!modifyCompilation || !_needsGeneratedAttributes_IsFrozen); - if (CheckIfAttributeShouldBeEmbedded(attribute, diagnostics, location) && modifyCompilation) + if (CheckIfAttributeShouldBeEmbedded(attribute, recordUsage: modifyCompilation, diagnostics, location) && modifyCompilation) { SetNeedsGeneratedAttributes(attribute); } @@ -508,7 +522,7 @@ internal void EnsureNullableContextAttributeExists(DiagnosticBag diagnostics, Lo EnsureEmbeddableAttributeExists(EmbeddableAttributes.NullableContextAttribute, diagnostics, location, modifyCompilation); } - internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, DiagnosticBag diagnosticsOpt, Location locationOpt) + internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, bool recordUsage, DiagnosticBag diagnosticsOpt, Location locationOpt) { switch (attribute) { @@ -517,6 +531,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor); case EmbeddableAttributes.IsByRefLikeAttribute: @@ -524,6 +539,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_IsByRefLikeAttribute__ctor); case EmbeddableAttributes.IsUnmanagedAttribute: @@ -531,6 +547,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_IsUnmanagedAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor); case EmbeddableAttributes.NullableAttribute: @@ -539,6 +556,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_NullableAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_NullableAttribute__ctorByte, WellKnownMember.System_Runtime_CompilerServices_NullableAttribute__ctorTransformFlags); @@ -547,6 +565,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_NullableContextAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_NullableContextAttribute__ctor); case EmbeddableAttributes.NullablePublicOnlyAttribute: @@ -554,6 +573,7 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D diagnosticsOpt, locationOpt, WellKnownType.System_Runtime_CompilerServices_NullablePublicOnlyAttribute, + recordUsage, WellKnownMember.System_Runtime_CompilerServices_NullablePublicOnlyAttribute__ctor); default: @@ -561,9 +581,9 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, D } } - private bool CheckIfAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Location locationOpt, WellKnownType attributeType, WellKnownMember attributeCtor, WellKnownMember? secondAttributeCtor = null) + private bool CheckIfAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Location locationOpt, WellKnownType attributeType, bool recordUsage, WellKnownMember attributeCtor, WellKnownMember? secondAttributeCtor = null) { - var userDefinedAttribute = GetWellKnownType(attributeType); + var userDefinedAttribute = GetWellKnownType(attributeType, recordUsage); if (userDefinedAttribute is MissingMetadataTypeSymbol) { @@ -583,10 +603,12 @@ private bool CheckIfAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Loca else if (diagnosticsOpt != null) { // This should produce diagnostics if the member is missing or bad - var member = Binder.GetWellKnownTypeMember(this, attributeCtor, diagnosticsOpt, locationOpt); + var member = Binder.GetWellKnownTypeMember(this, attributeCtor, + recordUsage: false, // recorded above if requested so + diagnosticsOpt, locationOpt); if (member != null && secondAttributeCtor != null) { - Binder.GetWellKnownTypeMember(this, secondAttributeCtor.Value, diagnosticsOpt, locationOpt); + Binder.GetWellKnownTypeMember(this, secondAttributeCtor.Value, recordUsage: false, diagnosticsOpt, locationOpt); } } @@ -595,14 +617,14 @@ private bool CheckIfAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Loca internal SynthesizedAttributeData SynthesizeDebuggableAttribute() { - TypeSymbol debuggableAttribute = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute); + TypeSymbol debuggableAttribute = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute, recordUsage: false); Debug.Assert((object)debuggableAttribute != null, "GetWellKnownType unexpectedly returned null"); if (debuggableAttribute is MissingMetadataTypeSymbol) { return null; } - TypeSymbol debuggingModesType = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute__DebuggingModes); + TypeSymbol debuggingModesType = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute__DebuggingModes, recordUsage: false); Debug.Assert((object)debuggingModesType != null, "GetWellKnownType unexpectedly returned null"); if (debuggingModesType is MissingMetadataTypeSymbol) { @@ -615,7 +637,7 @@ internal SynthesizedAttributeData SynthesizeDebuggableAttribute() // on exception stack traces. We always set this flag to avoid overhead of JIT loading the PDB. // The theoretical scenario for not setting it would be a language compiler that wants their sequence points // at specific places, but those places don't match what CLR's heuristics calculate when scanning the IL. - var ignoreSymbolStoreDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__IgnoreSymbolStoreSequencePoints); + var ignoreSymbolStoreDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__IgnoreSymbolStoreSequencePoints, recordUsage: false); if ((object)ignoreSymbolStoreDebuggingMode == null || !ignoreSymbolStoreDebuggingMode.HasConstantValue) { return null; @@ -631,13 +653,13 @@ internal SynthesizedAttributeData SynthesizeDebuggableAttribute() // Default | DisableOptimizations JIT optimizations disabled if (_options.OptimizationLevel == OptimizationLevel.Debug) { - var defaultDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__Default); + var defaultDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__Default, recordUsage: false); if ((object)defaultDebuggingMode == null || !defaultDebuggingMode.HasConstantValue) { return null; } - var disableOptimizationsDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__DisableOptimizations); + var disableOptimizationsDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__DisableOptimizations, recordUsage: false); if ((object)disableOptimizationsDebuggingMode == null || !disableOptimizationsDebuggingMode.HasConstantValue) { return null; @@ -649,7 +671,7 @@ internal SynthesizedAttributeData SynthesizeDebuggableAttribute() if (_options.EnableEditAndContinue) { - var enableEncDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__EnableEditAndContinue); + var enableEncDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__EnableEditAndContinue, recordUsage: false); if ((object)enableEncDebuggingMode == null || !enableEncDebuggingMode.HasConstantValue) { return null; @@ -708,7 +730,7 @@ internal SynthesizedAttributeData SynthesizeTupleNamesAttribute(TypeSymbol type) internal SynthesizedAttributeData SynthesizeAttributeUsageAttribute(AttributeTargets targets, bool allowMultiple, bool inherited) { - var attributeTargetsType = GetWellKnownType(WellKnownType.System_AttributeTargets); + var attributeTargetsType = GetWellKnownType(WellKnownType.System_AttributeTargets, recordUsage: false); var boolType = GetSpecialType(SpecialType.System_Boolean); var arguments = ImmutableArray.Create( new TypedConstant(attributeTargetsType, TypedConstantKind.Enum, targets)); @@ -1083,7 +1105,7 @@ protected override bool MatchTypeToTypeId(TypeSymbol type, int typeId) WellKnownType wellKnownId = (WellKnownType)typeId; if (wellKnownId.IsWellKnownType()) { - return type.Equals(_compilation.GetWellKnownType(wellKnownId), TypeCompareKind.IgnoreNullableModifiersForReferenceTypes); + return type.Equals(_compilation.GetWellKnownType(wellKnownId, recordUsage: false), TypeCompareKind.IgnoreNullableModifiersForReferenceTypes); } return base.MatchTypeToTypeId(type, typeId); diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index 9a7386ad7c888..bd7e0577c4de3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -1003,12 +1003,12 @@ internal virtual void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleB var compilation = this.DeclaringCompilation; var type = this.ReturnTypeWithAnnotations; - if (type.Type.ContainsDynamic() && compilation.HasDynamicEmitAttributes()) + if (type.Type.ContainsDynamic() && compilation.HasDynamicEmitAttributes(recordUsage: false)) { AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.Type, type.CustomModifiers.Length + this.RefCustomModifiers.Length, this.RefKind)); } - if (type.Type.ContainsTupleNames() && compilation.HasTupleNamesAttributes) + if (type.Type.ContainsTupleNames() && compilation.HasTupleNamesAttributes(recordUsage: false)) { AddSynthesizedAttribute(ref attributes, compilation.SynthesizeTupleNamesAttribute(type.Type)); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index 28ee3ee78136f..6f58f244e62d3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -627,25 +627,25 @@ private static void ReportDiagnosticsForSynthesizedAttributes(CSharpCompilation CSharpCompilationOptions compilationOptions = compilation.Options; if (!compilationOptions.OutputKind.IsNetModule()) { - TypeSymbol compilationRelaxationsAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute); + TypeSymbol compilationRelaxationsAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute, recordUsage: false); Debug.Assert((object)compilationRelaxationsAttribute != null, "GetWellKnownType unexpectedly returned null"); if (!(compilationRelaxationsAttribute is MissingMetadataTypeSymbol)) { // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if CompilationRelaxationsAttribute is found. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Runtime_CompilerServices_CompilationRelaxationsAttribute__ctorInt32, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Runtime_CompilerServices_CompilationRelaxationsAttribute__ctorInt32, recordUsage: true, diagnostics, NoLocation.Singleton); } - TypeSymbol runtimeCompatibilityAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute); + TypeSymbol runtimeCompatibilityAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute, recordUsage: false); Debug.Assert((object)runtimeCompatibilityAttribute != null, "GetWellKnownType unexpectedly returned null"); if (!(runtimeCompatibilityAttribute is MissingMetadataTypeSymbol)) { // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if RuntimeCompatibilityAttribute is found. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__ctor, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__ctor, recordUsage: true, diagnostics, NoLocation.Singleton); Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__WrapNonExceptionThrows, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__WrapNonExceptionThrows, recordUsage: true, diagnostics, NoLocation.Singleton); } } } @@ -669,7 +669,7 @@ private static void ReportDiagnosticsForUnsafeSynthesizedAttributes(CSharpCompil return; } - TypeSymbol unverifiableCodeAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute); + TypeSymbol unverifiableCodeAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute, recordUsage: false); Debug.Assert((object)unverifiableCodeAttribute != null, "GetWellKnownType unexpectedly returned null"); if (unverifiableCodeAttribute is MissingMetadataTypeSymbol) { @@ -679,17 +679,17 @@ private static void ReportDiagnosticsForUnsafeSynthesizedAttributes(CSharpCompil // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if // UnverifiableCodeAttribute is found. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Security_UnverifiableCodeAttribute__ctor, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Security_UnverifiableCodeAttribute__ctor, recordUsage: true, diagnostics, NoLocation.Singleton); - TypeSymbol securityPermissionAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute); + TypeSymbol securityPermissionAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute, recordUsage: false); Debug.Assert((object)securityPermissionAttribute != null, "GetWellKnownType unexpectedly returned null"); if (securityPermissionAttribute is MissingMetadataTypeSymbol) { return; } - TypeSymbol securityAction = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction); + TypeSymbol securityAction = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction, recordUsage: false); Debug.Assert((object)securityAction != null, "GetWellKnownType unexpectedly returned null"); if (securityAction is MissingMetadataTypeSymbol) { @@ -699,11 +699,11 @@ private static void ReportDiagnosticsForUnsafeSynthesizedAttributes(CSharpCompil // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if // UnverifiableCodeAttribute, SecurityAction, and SecurityPermissionAttribute are found. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__ctor, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__ctor, recordUsage: true, diagnostics, NoLocation.Singleton); // Not actually an attribute, but the same logic applies. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation, - WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__SkipVerification, diagnostics, NoLocation.Singleton); + WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__SkipVerification, recordUsage: true, diagnostics, NoLocation.Singleton); } private void ValidateIVTPublicKeys(DiagnosticBag diagnostics) @@ -773,7 +773,7 @@ private void DetectAttributeAndOptionConflicts(DiagnosticBag diagnostics) // We need to synthesize this attribute for .NET module, // touch the constructor in order to generate proper use-site diagnostics Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(_compilation, - WellKnownMember.System_Reflection_AssemblyKeyNameAttribute__ctor, + WellKnownMember.System_Reflection_AssemblyKeyNameAttribute__ctor, recordUsage: true, diagnostics, NoLocation.Singleton); } @@ -820,7 +820,7 @@ private void DetectAttributeAndOptionConflicts(DiagnosticBag diagnostics) // We need to synthesize this attribute for .NET module, // touch the constructor in order to generate proper use-site diagnostics Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(_compilation, - WellKnownMember.System_Reflection_AssemblyKeyFileAttribute__ctor, + WellKnownMember.System_Reflection_AssemblyKeyFileAttribute__ctor, recordUsage: true, diagnostics, NoLocation.Singleton); } @@ -1623,13 +1623,13 @@ private bool IsPossibleForwardedTypesAttribute(AttributeSyntax node) if (_compilation.Options.AllowUnsafe) { // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available. - if (!(_compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute) is MissingMetadataTypeSymbol) && - !(_compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute) is MissingMetadataTypeSymbol)) + if (!(_compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute, recordUsage: false) is MissingMetadataTypeSymbol) && + !(_compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute, recordUsage: false) is MissingMetadataTypeSymbol)) { - var securityActionType = _compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction); + var securityActionType = _compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction, recordUsage: false); if (!(securityActionType is MissingMetadataTypeSymbol)) { - var fieldRequestMinimum = (FieldSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Security_Permissions_SecurityAction__RequestMinimum); + var fieldRequestMinimum = (FieldSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Security_Permissions_SecurityAction__RequestMinimum, recordUsage: false); // NOTE: Dev10 handles missing enum value. object constantValue = (object)fieldRequestMinimum == null || fieldRequestMinimum.HasUseSiteError ? 0 : fieldRequestMinimum.ConstantValue; @@ -1765,7 +1765,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r // Synthesize attribute: [CompilationRelaxationsAttribute(CompilationRelaxations.NoStringInterning)] // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available. - if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute) is MissingMetadataTypeSymbol)) + if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute, recordUsage: false) is MissingMetadataTypeSymbol)) { var int32Type = _compilation.GetSpecialType(SpecialType.System_Int32); Debug.Assert(!int32Type.HasUseSiteError, @@ -1785,7 +1785,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r // Synthesize attribute: [RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)] // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available. - if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute) is MissingMetadataTypeSymbol)) + if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute, recordUsage: false) is MissingMetadataTypeSymbol)) { var boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); Debug.Assert(!boolType.HasUseSiteError, "Use site errors should have been checked ahead of time (type bool)."); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 01356d560d733..7ebc0815229c3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -996,13 +996,13 @@ private void ValidateCancellationTokenAttribute(AttributeSyntax node, Diagnostic bool needsReporting() { - if (!Type.Equals(this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken))) + if (!Type.Equals(this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken, recordUsage: false))) { return true; } else if (this.ContainingSymbol is MethodSymbol method && method.IsAsync && - method.ReturnType.OriginalDefinition.Equals(this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T))) + method.ReturnType.OriginalDefinition.Equals(this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false))) { // Note: async methods that return this type must be iterators. This is enforced elsewhere return false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs index 983312b3339e3..ca6023d7a7728 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs @@ -103,7 +103,7 @@ protected sealed override void MethodChecks(DiagnosticBag diagnostics) // rather than Interlocked.CompareExchange. if (_event.IsWindowsRuntimeEvent) { - TypeSymbol eventTokenType = compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken); + TypeSymbol eventTokenType = compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken, recordUsage: true); Binder.ReportUseSiteDiagnostics(eventTokenType, diagnostics, this.Location); if (this.MethodKind == MethodKind.EventAdd) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs index 0255e03cc4139..c7c7df4685f0a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFixedFieldSymbol.cs @@ -38,7 +38,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r base.AddSynthesizedAttributes(moduleBuilder, ref attributes); var compilation = this.DeclaringCompilation; - var systemType = compilation.GetWellKnownType(WellKnownType.System_Type); + var systemType = compilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false); var intType = compilation.GetSpecialType(SpecialType.System_Int32); var item1 = new TypedConstant(systemType, TypedConstantKind.Type, ((PointerTypeSymbol)this.Type).PointedAtType); var item2 = new TypedConstant(intType, TypedConstantKind.Primitive, this.FixedSize); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 18919081c678a..83c1d2564240a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -390,17 +390,7 @@ private bool IsPointerFieldSyntactically() return true; } - foreach (var singleVariable in declaration.Variables) - { - var argList = singleVariable.ArgumentList; - if (argList != null && argList.Arguments.Count != 0) - { - // public int Blah[10]; // fixed buffer - return true; - } - } - - return false; + return IsFixedSizeBuffer; } internal sealed override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) @@ -430,7 +420,7 @@ internal sealed override TypeWithAnnotations GetFieldType(ConsList EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { - NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); + NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T, recordUsage: true); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable @@ -529,6 +519,8 @@ internal sealed override TypeWithAnnotations GetFieldType(ConsList } } + Debug.Assert(type.DefaultType.IsPointerType() == IsPointerFieldSyntactically()); + // update the lazyType only if it contains value last seen by the current thread: if (Interlocked.CompareExchange(ref _lazyType, new TypeWithAnnotations.Boxed(type.WithModifiers(this.RequiredCustomModifiers)), null) == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 3678a08473510..92a922995e5ab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1783,7 +1783,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r // type will not have been created. In this case, omit the attribute. if (moduleBuilder.CompilationState.TryGetStateMachineType(this, out NamedTypeSymbol stateMachineType)) { - var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), + var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false), TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf()); if (isAsync && isIterator) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs index 1f507d2100750..6cd509f306499 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs @@ -529,7 +529,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r if (compilation.Options.AllowUnsafe) { // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known type isn't available. - if (!(compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute) is MissingMetadataTypeSymbol)) + if (!(compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute, recordUsage: false) is MissingMetadataTypeSymbol)) { AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute( WellKnownMember.System_Security_UnverifiableCodeAttribute__ctor)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 3bbae663c09ce..95fec2845c1c1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -185,12 +185,13 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB var location = this.Locations[0]; if (IsAsync) { - var cancellationTokenType = DeclaringCompilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken); - var iAsyncEnumerableType = DeclaringCompilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T); + var iAsyncEnumerableType = DeclaringCompilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false); var enumeratorCancellationCount = Parameters.Count(p => p is SourceComplexParameterSymbol { HasEnumeratorCancellationAttribute: true }); if (ReturnType.OriginalDefinition.Equals(iAsyncEnumerableType) && (Bodies.blockBody != null || Bodies.arrowBody != null)) { + var cancellationTokenType = DeclaringCompilation.GetWellKnownType(WellKnownType.System_Threading_CancellationToken, recordUsage: false); + if (enumeratorCancellationCount == 0 && ParameterTypesWithAnnotations.Any(p => p.Type.Equals(cancellationTokenType))) { @@ -296,7 +297,7 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB else { // Verify ExtensionAttribute is available. - var attributeConstructor = withTypeParamsBinder.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); + var attributeConstructor = withTypeParamsBinder.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor, recordUsage: true); if ((object)attributeConstructor == null) { var memberDescriptor = WellKnownMembers.GetDescriptor(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs index d01d3683b55c0..d4fd03fc7abe6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceParameterSymbol.cs @@ -44,7 +44,7 @@ public static SourceParameterSymbol Create( { // touch the constructor in order to generate proper use-site diagnostics Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(context.Compilation, - WellKnownMember.System_ParamArrayAttribute__ctor, + WellKnownMember.System_ParamArrayAttribute__ctor, recordUsage: !context.IsSemanticModelBinder, declarationDiagnostics, identifier.Parent.GetLocation()); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index 3b71768d3c5ba..4f4ac923ff361 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -480,9 +480,9 @@ internal override bool IsDeclaredReadOnly } // If we have IsReadOnly..ctor, we can use the attribute. Otherwise, we need to NOT be a netmodule and the type must not already exist in order to synthesize it. - var isReadOnlyAttributeUsable = DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor) != null || + var isReadOnlyAttributeUsable = DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor, recordUsage: false) != null || (DeclaringCompilation.Options.OutputKind != OutputKind.NetModule && - DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute) is MissingMetadataTypeSymbol); + DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, recordUsage: false) is MissingMetadataTypeSymbol); if (!isReadOnlyAttributeUsable) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index c50a3164cd5f9..437d7200b755f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -183,7 +183,7 @@ private SourcePropertySymbol( { //issue a diagnostic if the compiler generated attribute ctor is not found. Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(bodyBinder.Compilation, - WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor, diagnostics, syntax: syntax); + WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor, recordUsage: !bodyBinder.IsSemanticModelBinder, diagnostics, syntax: syntax); if (this._refKind != RefKind.None && !_containingType.IsInterface) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs index bdfed0484c84e..d101b7d334df7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEventAccessorSymbol.cs @@ -81,7 +81,7 @@ internal override MethodImplAttributes ImplementationAttributes MethodImplAttributes result = base.ImplementationAttributes; if (!IsAbstract && !AssociatedEvent.IsWindowsRuntimeEvent && !ContainingType.IsStructType() && - (object)DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T) == null) + (object)DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T, recordUsage: false) == null) { // Under these conditions, this method needs to be synchronized. result |= MethodImplAttributes.Synchronized; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs index d3fd795cb5f23..f73e895a16ad9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs @@ -55,14 +55,14 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r if (!this.SuppressDynamicAttribute && type.ContainsDynamic() && - compilation.HasDynamicEmitAttributes() && + compilation.HasDynamicEmitAttributes(recordUsage: false) && compilation.CanEmitBoolean()) { AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type, typeWithAnnotations.CustomModifiers.Length)); } if (type.ContainsTupleNames() && - compilation.HasTupleNamesAttributes && + compilation.HasTupleNamesAttributes(recordUsage: false) && compilation.CanEmitSpecialType(SpecialType.System_String)) { AddSynthesizedAttribute(ref attributes, diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs index fe3657b4076c7..081776c256f79 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs @@ -242,7 +242,7 @@ private static void CalculateReturnType( { CSharpCompilation compilation = containingType.DeclaringCompilation; var submissionReturnTypeOpt = compilation.ScriptCompilationInfo?.ReturnTypeOpt; - var taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); + var taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T, recordUsage: true); var useSiteDiagnostic = taskT.GetUseSiteDiagnostic(); if (useSiteDiagnostic != null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index 3505bb7c810f3..c7764a134b4f6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -145,13 +145,13 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r // adversely effect the compilation or potentially change overload resolution. var compilation = this.DeclaringCompilation; var type = this.TypeWithAnnotations; - if (type.Type.ContainsDynamic() && compilation.HasDynamicEmitAttributes() && compilation.CanEmitBoolean()) + if (type.Type.ContainsDynamic() && compilation.HasDynamicEmitAttributes(recordUsage: false) && compilation.CanEmitBoolean()) { AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.Type, type.CustomModifiers.Length + this.RefCustomModifiers.Length, this.RefKind)); } if (type.Type.ContainsTupleNames() && - compilation.HasTupleNamesAttributes && + compilation.HasTupleNamesAttributes(recordUsage: false) && compilation.CanEmitSpecialType(SpecialType.System_String)) { AddSynthesizedAttribute(ref attributes, diff --git a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs index fad1b674761ca..6abba87d54e0a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs @@ -82,6 +82,7 @@ internal static NamedTypeSymbol Create( bool shouldCheckConstraints, bool includeNullability, ImmutableArray errorPositions, + bool recordUsage, CSharpSyntaxNode syntax = null, DiagnosticBag diagnostics = null) { @@ -96,7 +97,7 @@ internal static NamedTypeSymbol Create( throw ExceptionUtilities.Unreachable; } - NamedTypeSymbol underlyingType = GetTupleUnderlyingType(elementTypesWithAnnotations, syntax, compilation, diagnostics); + NamedTypeSymbol underlyingType = GetTupleUnderlyingType(elementTypesWithAnnotations, syntax, compilation, recordUsage, diagnostics); if (numElements >= RestPosition && diagnostics != null && !underlyingType.IsErrorType()) { @@ -350,13 +351,13 @@ private static int NumberOfValueTuples(int numElements, out int remainder) /// /// Pass a null diagnostic bag and syntax node if you don't care about diagnostics. /// - private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray elementTypes, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics) + private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray elementTypes, CSharpSyntaxNode syntax, CSharpCompilation compilation, bool recordUsage, DiagnosticBag diagnostics) { int numElements = elementTypes.Length; int remainder; int chainLength = NumberOfValueTuples(numElements, out remainder); - NamedTypeSymbol firstTupleType = compilation.GetWellKnownType(GetTupleType(remainder)); + NamedTypeSymbol firstTupleType = compilation.GetWellKnownType(GetTupleType(remainder), recordUsage); if ((object)diagnostics != null && (object)syntax != null) { ReportUseSiteAndObsoleteDiagnostics(syntax, diagnostics, firstTupleType); @@ -365,7 +366,7 @@ private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray 1) { - chainedTupleType = compilation.GetWellKnownType(GetTupleType(RestPosition)); + chainedTupleType = compilation.GetWellKnownType(GetTupleType(RestPosition), recordUsage); if ((object)diagnostics != null && (object)syntax != null) { ReportUseSiteAndObsoleteDiagnostics(syntax, diagnostics, chainedTupleType); @@ -404,19 +405,19 @@ private static void ReportUseSiteAndObsoleteDiagnostics(CSharpSyntaxNode syntax, /// /// For tuples with no natural type, we still need to verify that an underlying type of proper arity exists, and report if otherwise. /// - internal static void VerifyTupleTypePresent(int cardinality, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics) + internal static void VerifyTupleTypePresent(int cardinality, CSharpSyntaxNode syntax, CSharpCompilation compilation, bool recordUsage, DiagnosticBag diagnostics) { Debug.Assert((object)diagnostics != null && (object)syntax != null); int remainder; int chainLength = NumberOfValueTuples(cardinality, out remainder); - NamedTypeSymbol firstTupleType = compilation.GetWellKnownType(GetTupleType(remainder)); + NamedTypeSymbol firstTupleType = compilation.GetWellKnownType(GetTupleType(remainder), recordUsage); ReportUseSiteAndObsoleteDiagnostics(syntax, diagnostics, firstTupleType); if (chainLength > 1) { - NamedTypeSymbol chainedTupleType = compilation.GetWellKnownType(GetTupleType(RestPosition)); + NamedTypeSymbol chainedTupleType = compilation.GetWellKnownType(GetTupleType(RestPosition), recordUsage); ReportUseSiteAndObsoleteDiagnostics(syntax, diagnostics, chainedTupleType); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 088d2e49ecfdc..44d1ddb719fcc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1468,7 +1468,7 @@ internal static bool IsNonGenericTaskType(this TypeSymbol type, CSharpCompilatio { return false; } - if ((object)namedType == compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task)) + if ((object)namedType == compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task, recordUsage: false)) { return true; } @@ -1487,7 +1487,7 @@ internal static bool IsGenericTaskType(this TypeSymbol type, CSharpCompilation c { return false; } - if ((object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) + if ((object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T, recordUsage: false)) { return true; } @@ -1503,7 +1503,7 @@ internal static bool IsIAsyncEnumerableType(this TypeSymbol type, CSharpCompilat return false; } - return (object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T); + return (object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T, recordUsage: false); } internal static bool IsIAsyncEnumeratorType(this TypeSymbol type, CSharpCompilation compilation) @@ -1514,7 +1514,7 @@ internal static bool IsIAsyncEnumeratorType(this TypeSymbol type, CSharpCompilat return false; } - return (object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T); + return (object)namedType.ConstructedFrom == compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T, recordUsage: false); } /// @@ -1644,8 +1644,9 @@ private static bool NormalizeTaskTypesInNamedType(CSharpCompilation compilation, Debug.Assert(arity < 2); var taskType = compilation.GetWellKnownType( arity == 0 ? - WellKnownType.System_Threading_Tasks_Task : - WellKnownType.System_Threading_Tasks_Task_T); + WellKnownType.System_Threading_Tasks_Task : + WellKnownType.System_Threading_Tasks_Task_T, + recordUsage: false); if (taskType.TypeKind == TypeKind.Error) { // Skip if Task types are not available. diff --git a/src/Compilers/CSharp/Portable/Symbols/UsedAssembliesRecorder.cs b/src/Compilers/CSharp/Portable/Symbols/UsedAssembliesRecorder.cs index 769f4c34af47d..7f3c0d51f9c98 100644 --- a/src/Compilers/CSharp/Portable/Symbols/UsedAssembliesRecorder.cs +++ b/src/Compilers/CSharp/Portable/Symbols/UsedAssembliesRecorder.cs @@ -48,12 +48,36 @@ public override BoundNode VisitFieldAccess(BoundFieldAccess node) return base.VisitFieldAccess(node); } + public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) + { + AddAssembliesUsedBySymbolReference(node.ReceiverOpt, node.PropertySymbol); + return base.VisitPropertyAccess(node); + } + + public override BoundNode VisitIndexerAccess(BoundIndexerAccess node) + { + AddAssembliesUsedBySymbolReference(node.ReceiverOpt, node.Indexer); + return base.VisitIndexerAccess(node); + } + public override BoundNode VisitCall(BoundCall node) { AddAssembliesUsedBySymbolReference(node.ReceiverOpt, node.Method); return base.VisitCall(node); } + public override BoundNode VisitEventAccess(BoundEventAccess node) + { + AddAssembliesUsedBySymbolReference(node.ReceiverOpt, node.EventSymbol); + return base.VisitEventAccess(node); + } + + public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOperator node) + { + AddAssembliesUsedBySymbolReference(node.ReceiverOpt, node.Event); + return base.VisitEventAssignmentOperator(node); + } + public override BoundNode VisitNameOfOperator(BoundNameOfOperator node) { if (node.Argument is BoundNamespaceExpression nsExpr) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs index fd17c33c073a6..45acb3dbb5797 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs @@ -1659,7 +1659,9 @@ static void Main(string[] args) { } attrTypeName: "UserDefinedAssemblyAttrAllowMultipleAttribute"); } - [Fact, WorkItem(546825, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546825")] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39969")] + [WorkItem(546825, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546825")] + [WorkItem(39969, "https://github.com/dotnet/roslyn/issues/39969")] public void Bug16910() { string mod = diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 7ae5dfe43188b..af89ab2b9a5bd 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -1879,8 +1879,9 @@ public static async System.Collections.Generic.IAsyncEnumerable M() CompileAndVerify(comp, expectedOutput: "1 END DISPOSAL DONE"); } - [Fact] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39970")] [WorkItem(31608, "https://github.com/dotnet/roslyn/issues/31608")] + [WorkItem(39970, "https://github.com/dotnet/roslyn/issues/39970")] public void AsyncIterator_WithoutAwait_WithoutAsync() { string source = @" @@ -6486,7 +6487,9 @@ static async System.Collections.Generic.IAsyncEnumerable Iter([EnumeratorCa CompileAndVerify(comp, expectedOutput: "1"); } - [Fact, WorkItem(34407, "https://github.com/dotnet/roslyn/issues/34407")] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39961")] + [WorkItem(34407, "https://github.com/dotnet/roslyn/issues/34407")] + [WorkItem(39961, "https://github.com/dotnet/roslyn/issues/39961")] public void CancellationTokenParameter_WrongParameterType() { string source = @" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs index c1d1d81b2c9c4..80690f597c608 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs @@ -223,7 +223,8 @@ public class Object { } /// Report CS0656 for missing Decimal to int conversion. /// [WorkItem(530860, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530860")] - [Fact] + [WorkItem(39962, "https://github.com/dotnet/roslyn/issues/39962")] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39962")] public void NoDecimalConversion() { var source1 = diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs index 78a6ec89c5f97..8400ca7e4a14f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs @@ -13231,6 +13231,7 @@ static System.Action M() emittingPdb: false, emitTestCoverageData: false, hasDeclarationErrors: false, + emitMethodBodies: true, diagnostics: diagnostics, filterOpt: null, entryPointOpt: null, diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 05b8f986126e2..7552a9c0cbee6 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -3123,7 +3123,8 @@ static void Main() verifier.VerifyDiagnostics(); } - [ConditionalFact(typeof(NoIOperationValidation))] + [ConditionalFact(typeof(NoIOperationValidation), AlwaysSkip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39976")] + [WorkItem(39976, "https://github.com/dotnet/roslyn/issues/39976")] public void HugeTupleCreationParses() { StringBuilder b = new StringBuilder(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs index b02b4b36c5793..647226e9f06a8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs @@ -2203,6 +2203,7 @@ class Element } [WorkItem(798000, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/798000")] + [WorkItem(39948, "https://github.com/dotnet/roslyn/issues/39948")] [Fact] public void MissingNullableValue() { @@ -2245,6 +2246,31 @@ void Goo(System.Collections.Generic.IEnumerable? e) // void Goo(System.Collections.Generic.IEnumerable? e) Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(28, 55) ); + comp.VerifyEmitDiagnostics( + // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. + Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1), + // error CS0518: Predefined type 'System.Attribute' is not defined or imported + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Attribute").WithLocation(1, 1), + // error CS0518: Predefined type 'System.Attribute' is not defined or imported + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Attribute").WithLocation(1, 1), + // error CS0518: Predefined type 'System.Byte' is not defined or imported + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Byte").WithLocation(1, 1), + // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute..ctor' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", ".ctor").WithLocation(1, 1), + // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.AllowMultiple' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "AllowMultiple").WithLocation(1, 1), + // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.Inherited' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "Inherited").WithLocation(1, 1), + // (28,55): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + // void Goo(System.Collections.Generic.IEnumerable? e) + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(28, 55), + + // The following error is unexpected - https://github.com/dotnet/roslyn/issues/39948 + + // (30,9): error CS0656: Missing compiler required member 'System.IDisposable.Dispose' + // foreach (var c in e) { } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "foreach (var c in e) { }").WithArguments("System.IDisposable", "Dispose").WithLocation(30, 9) + ); } [WorkItem(798000, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/798000")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index b06486354a380..546c7b7444b02 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -89315,8 +89315,8 @@ static Goo() public static int Y { get; } }"; - CreateCompilation(text, options: WithNonNullTypesTrue(TestOptions.ReleaseDll)).VerifyDiagnostics(); - CreateCompilation(text, options: WithNonNullTypesTrue(TestOptions.ReleaseDll), parseOptions: TestOptions.Regular.WithStrictFeature()).VerifyDiagnostics(); + CreateCompilation(text, options: WithNonNullTypesTrue(TestOptions.ReleaseDll)).VerifyEmitDiagnostics(); + CreateCompilation(text, options: WithNonNullTypesTrue(TestOptions.ReleaseDll), parseOptions: TestOptions.Regular.WithStrictFeature()).VerifyEmitDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index 5551c717805fe..263ed380dfdf4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -7237,7 +7237,8 @@ ExpressionSyntax node4 Assert.Null(symbol2); } - [Fact()] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39975")] + [WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")] public void CheckedUnaryIntrinsicSymbols() { var source = @@ -7456,7 +7457,8 @@ public void BinaryIntrinsicSymbols1() Assert.Equal(n, nodes.Length); } - [ConditionalFact(typeof(NoIOperationValidation))] + [ConditionalFact(typeof(NoIOperationValidation), AlwaysSkip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39975")] + [WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")] public void BinaryIntrinsicSymbols2() { BinaryOperatorKind[] operators = diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index f6aa0059e3ca4..d8059f81a8f27 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -3434,7 +3434,8 @@ static ref int M(ref int i) ); } - [Fact] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39971")] + [WorkItem(39971, "https://github.com/dotnet/roslyn/issues/39971")] public void BadIteratorReturnInRefReturningMethod() { var text = @" diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index b9b6b442d2ab9..d3ad077c06a00 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -8913,6 +8913,8 @@ unsafe struct S if (field != null) { Assert.Equal(0, field.FixedSize); + Assert.True(field.Type.IsPointerType()); + Assert.True(field.HasPointerType); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UserDefinedConversionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UserDefinedConversionTests.cs index 1a52a80ebc6ed..97100ea442ef0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UserDefinedConversionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UserDefinedConversionTests.cs @@ -774,7 +774,8 @@ public F(string str) : base(str) {} CompileAndVerify(source: source, expectedOutput: output); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/39959")] + [WorkItem(39959, "https://github.com/dotnet/roslyn/issues/39959")] public void TestIntPtrUserDefinedConversions() { // IntPtr and UIntPtr violate the rules of user-defined conversions for @@ -1145,6 +1146,7 @@ public static void Main() // All of the cases above should pass semantic analysis: var comp = CreateCompilation(source1 + source2 + source3 + source4 + source5, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics(); // However, we have not yet implemented lowering and code generation for decimal, // lifted operators, nullable conversions and unsafe code so only generate code for diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs index b5e4213df9c27..94c004426b8c5 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs @@ -65,20 +65,18 @@ public static void Main(I1 x) verify(source2, comp1.ToMetadataReference()); Assert.Empty(comp1.GetUsedAssemblyReferences()); - static void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = AssertUsedAssemblyReferences(source2, reference); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference)); } } - private static void AssertUsedAssemblyReferences(Compilation comp, MetadataReference[] expected, DiagnosticDescription[] before, DiagnosticDescription[] after) + private void AssertUsedAssemblyReferences(Compilation comp, MetadataReference[] expected, DiagnosticDescription[] before, DiagnosticDescription[] after) { comp.VerifyDiagnostics(before); bool hasCoreLibraryRef = !comp.ObjectType.IsErrorType(); - Assert.True(comp.References.Count() > expected.Length + (hasCoreLibraryRef ? 1 : 0)); - var used = comp.GetUsedAssemblyReferences(); if (hasCoreLibraryRef) @@ -93,22 +91,31 @@ private static void AssertUsedAssemblyReferences(Compilation comp, MetadataRefer Assert.Empty(used.Where(r => r.Properties.Kind == MetadataImageKind.Module)); - comp.RemoveAllReferences().AddReferences(used.Concat(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Module))).VerifyDiagnostics(after); + var comp2 = comp.RemoveAllReferences().AddReferences(used.Concat(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Module))); + + if (!after.Any(d => ErrorFacts.GetSeverity((ErrorCode)d.Code) == DiagnosticSeverity.Error)) + { + CompileAndVerify(comp2, verify: Verification.Skipped).Diagnostics.Where(d => d.Code != (int)ErrorCode.WRN_NoRuntimeMetadataVersion).Verify(after); + } + else + { + comp2.VerifyDiagnostics(after); + } } - private static void AssertUsedAssemblyReferences(Compilation comp, params MetadataReference[] expected) + private void AssertUsedAssemblyReferences(Compilation comp, params MetadataReference[] expected) { AssertUsedAssemblyReferences(comp, expected, new DiagnosticDescription[] { }, new DiagnosticDescription[] { }); } - private static Compilation AssertUsedAssemblyReferences(string source, MetadataReference[] references, params MetadataReference[] expected) + private Compilation AssertUsedAssemblyReferences(string source, MetadataReference[] references, params MetadataReference[] expected) { Compilation comp = CreateCompilation(source, references: references); AssertUsedAssemblyReferences(comp, expected); return comp; } - private static Compilation AssertUsedAssemblyReferences(string source, params MetadataReference[] references) + private Compilation AssertUsedAssemblyReferences(string source, params MetadataReference[] references) { return AssertUsedAssemblyReferences(source, references, references); } @@ -123,6 +130,24 @@ private static void AssertUsedAssemblyReferences(string source, MetadataReferenc AssertEx.Equal(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Assembly), comp.GetUsedAssemblyReferences()); } + private void CompileWithUsedAssemblyReferences(string source, TargetFramework targetFramework, params MetadataReference[] references) + { + Compilation comp = CreateCompilation(source, targetFramework: targetFramework, references: references); + CompileWithUsedAssemblyReferences(comp); + } + + private void CompileWithUsedAssemblyReferences(Compilation comp, string expectedOutput = null) + { + var used = comp.GetUsedAssemblyReferences(); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: expectedOutput).VerifyDiagnostics(); + + Assert.Empty(used.Where(r => r.Properties.Kind == MetadataImageKind.Module)); + + var comp2 = comp.RemoveAllReferences().AddReferences(used.Concat(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Module))); + comp2.VerifyDiagnostics(); + CompileAndVerify(comp2, verify: Verification.Skipped, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + [Fact] public void NoReferences_03() { @@ -162,7 +187,7 @@ public static object Main(I1 x) verify(source2, comp1.ToMetadataReference()); Assert.Empty(comp1.GetUsedAssemblyReferences()); - static void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = CreateEmptyCompilation(source2, references: new[] { reference, SystemCoreRef, SystemDrawingRef }); AssertUsedAssemblyReferences(comp2); @@ -195,7 +220,7 @@ public interface I2 verify(source2, comp1.ToMetadataReference()); Assert.Empty(comp1.GetUsedAssemblyReferences()); - static void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = CreateEmptyCompilation(source2, references: new[] { reference, SystemCoreRef, SystemDrawingRef }); AssertUsedAssemblyReferences(comp2, reference); @@ -247,7 +272,7 @@ public static void Main() verify(source3, comp1ImageRef); verify(source3, comp1Ref); - static void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = AssertUsedAssemblyReferences(source2, reference); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference)); @@ -300,7 +325,7 @@ public static void Main() verify(source2, comp0Ref, comp1Ref); verify(source2, comp0ImageRef, comp1Ref); - static void verify(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = AssertUsedAssemblyReferences(source2, reference0, reference1); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference1)); @@ -398,14 +423,14 @@ public static void Main() verify3(source3, comp2ImageRef); verify3(source3, comp2Ref); - static Compilation verify2(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol + Compilation verify2(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol { var comp2 = AssertUsedAssemblyReferences(source2, new[] { reference0, reference1 }, reference0); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference0)); return comp2; } - static void verify3(string source3, params MetadataReference[] references) where TAssemblySymbol : AssemblySymbol + void verify3(string source3, params MetadataReference[] references) where TAssemblySymbol : AssemblySymbol { Compilation comp3 = AssertUsedAssemblyReferences(source3, references: references); Assert.IsType(((CSharpCompilation)comp3).GetAssemblyOrModuleSymbol(references.Last())); @@ -475,7 +500,7 @@ public static void Main() } "); - static void verify(MetadataReference reference, string source) + void verify(MetadataReference reference, string source) { AssertUsedAssemblyReferences(source, reference); } @@ -675,7 +700,7 @@ public static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source) + void verify(MetadataReference reference0, MetadataReference reference1, string source) { AssertUsedAssemblyReferences(source, reference0, reference1); } @@ -836,7 +861,7 @@ static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) + void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) { var references = new[] { reference0, reference1 }; Compilation comp2 = CreateCompilation(source, references: references, parseOptions: TestOptions.Regular.WithDocumentationMode(DocumentationMode.None)); @@ -1006,7 +1031,7 @@ public static void Main() } " + attribute); - static void verify(MetadataReference reference0, MetadataReference reference1, string source) + void verify(MetadataReference reference0, MetadataReference reference1, string source) { AssertUsedAssemblyReferences(source, reference0, reference1); } @@ -1090,7 +1115,7 @@ public static void Main(int p = (int)alias.E1.F1 + 1) } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source) + void verify(MetadataReference reference0, MetadataReference reference1, string source) { AssertUsedAssemblyReferences(source, reference0, reference1); } @@ -1122,7 +1147,7 @@ public static void Main() verify(source2, comp1.EmitToImageReference()); verify(source2, comp1.ToMetadataReference()); - static void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = AssertUsedAssemblyReferences(source2, reference); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference)); @@ -1520,7 +1545,7 @@ public class C2 } "); - static void verify(MetadataReference reference, string source2) + void verify(MetadataReference reference, string source2) { AssertUsedAssemblyReferences(source2, reference); } @@ -1674,7 +1699,7 @@ static void verify1(MetadataReference reference, string source, params Diagnosti Assert.Same(comp.ObjectType.ContainingAssembly, comp.GetAssemblyOrModuleSymbol(used[0])); } - static void verify2(MetadataReference reference, string source, string @using) + void verify2(MetadataReference reference, string source, string @using) { AssertUsedAssemblyReferences(CreateCompilation(Parse(source, options: TestOptions.Script), references: new[] { reference }, options: TestOptions.DebugDll.WithUsings(@using)), reference); @@ -1739,7 +1764,7 @@ public class C2 } "); - static void verify(MetadataReference reference, string source2) + void verify(MetadataReference reference, string source2) { AssertUsedAssemblyReferences(source2, reference); } @@ -1797,7 +1822,7 @@ public static void Main() verify(source2, comp0Ref, comp1Ref); verify(source2, comp0ImageRef, comp1Ref); - static void verify(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol + void verify(string source2, MetadataReference reference0, MetadataReference reference1) where TAssemblySymbol : AssemblySymbol { Compilation comp2 = AssertUsedAssemblyReferences(source2, new[] { reference0, reference1 }, reference1); Assert.IsType(((CSharpCompilation)comp2).GetAssemblyOrModuleSymbol(reference1)); @@ -1890,7 +1915,7 @@ public static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source) + void verify(MetadataReference reference0, MetadataReference reference1, string source) { AssertUsedAssemblyReferences(source, reference0, reference1); } @@ -1966,7 +1991,7 @@ public static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source) + void verify(MetadataReference reference0, MetadataReference reference1, string source) { AssertUsedAssemblyReferences(source, reference0, reference1); } @@ -2071,7 +2096,7 @@ static void Main1() options: TestOptions.DebugDll.WithUsings("C0")), comp0Ref); - static void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) + void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) { var references = new[] { reference0, reference1 }; Compilation comp2 = CreateCompilation(source, references: references, parseOptions: TestOptions.Regular.WithDocumentationMode(DocumentationMode.None)); @@ -2174,7 +2199,7 @@ void M(int x) {} } "); - static void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) + void verify(MetadataReference reference0, MetadataReference reference1, string source, bool hasTypeReferensesInUsing = true) { var references = new[] { reference0, reference1 }; Compilation comp2 = CreateCompilation(source, references: references, parseOptions: TestOptions.Regular.WithDocumentationMode(DocumentationMode.None)); @@ -2261,7 +2286,7 @@ public static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source) + void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source) { AssertUsedAssemblyReferences(source, new[] { reference0, reference1, reference2 }, reference0, reference1); } @@ -2380,7 +2405,7 @@ public static void Main() } "); - static void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source) + void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source) { AssertUsedAssemblyReferences(source, new[] { reference0, reference1, reference2 }, reference0); } @@ -2558,7 +2583,7 @@ static void Main1() options: TestOptions.DebugDll.WithUsings("N1")), references); - static void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source, int namespaceOrdinalReferencedInUsings = 0) + void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source, int namespaceOrdinalReferencedInUsings = 0) { var references = new[] { reference0, reference1, reference2 }; var expected = new[] { reference0, reference1 }; @@ -2741,7 +2766,7 @@ static void Main1() options: TestOptions.DebugDll.WithUsings("N1.N2.E0")), comp0Ref); - static void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source, int namespaceOrdinalReferencedInUsings = 0) + void verify(MetadataReference reference0, MetadataReference reference1, MetadataReference reference2, string source, int namespaceOrdinalReferencedInUsings = 0) { var references = new[] { reference0, reference1, reference2 }; Compilation comp2 = CreateCompilation(source, references: references, parseOptions: TestOptions.Regular.WithDocumentationMode(DocumentationMode.None)); @@ -2907,5 +2932,654 @@ public class C2 }); } + [Fact] + public void EventReference_01() + { + var source0 = +@" +public delegate void D0(); +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +public class C1 +{ + public static event D0 E1; + + void Use() + { + E1(); + } +} +"; + var comp1 = CreateCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main() + { + C1.E1 += null; + } +} +"; + + AssertUsedAssemblyReferences(source2, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source2, comp0Ref, comp1ImageRef); + + var source3 = +@" +public class C3 +{ + public static void Main() + { + C1.E1 -= null; + } +} +"; + + AssertUsedAssemblyReferences(source3, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source3, comp0Ref, comp1ImageRef); + + var source4 = +@" +using static C1; + +public class C2 +{ + public static void Main() + { + E1 += null; + } +} +"; + + AssertUsedAssemblyReferences(source4, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source4, comp0Ref, comp1ImageRef); + + var source5 = +@" +using static C1; + +public class C3 +{ + public static void Main() + { + E1 -= null; + } +} +"; + + AssertUsedAssemblyReferences(source5, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source5, comp0Ref, comp1ImageRef); + } + + [Fact] + public void EventReference_02() + { + var source0 = +@" +public delegate void D0(); +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +public class C1 +{ + public event D0 E1; + + void Use() + { + E1(); + } +} +"; + var comp1 = CreateCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main(C1 x) + { + x.E1 += null; + } +} +"; + + AssertUsedAssemblyReferences(source2, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source2, comp0Ref, comp1ImageRef); + + var source3 = +@" +public class C3 +{ + public static void Main(C1 x) + { + x.E1 -= null; + } +} +"; + + AssertUsedAssemblyReferences(source3, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source3, comp0Ref, comp1ImageRef); + } + + [Fact] + public void PropertyReference_01() + { + var source0 = +@" +public class C0 +{ +} +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +public class C1 +{ + public static C0 P1 {get; set;} +} +"; + var comp1 = CreateCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main() + { + C1.P1 = null; + } +} +"; + + AssertUsedAssemblyReferences(source2, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source2, comp0Ref, comp1ImageRef); + + var source3 = +@" +public class C3 +{ + public static void Main() + { + _ = C1.P1; + } +} +"; + + AssertUsedAssemblyReferences(source3, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source3, comp0Ref, comp1ImageRef); + + var source4 = +@" +using static C1; + +public class C2 +{ + public static void Main() + { + P1 = null; + } +} +"; + + AssertUsedAssemblyReferences(source4, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source4, comp0Ref, comp1ImageRef); + + var source5 = +@" +using static C1; + +public class C3 +{ + public static void Main() + { + _ = P1; + } +} +"; + + AssertUsedAssemblyReferences(source5, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source5, comp0Ref, comp1ImageRef); + } + + [Fact] + public void PropertyReference_02() + { + var source0 = +@" +public class C0 +{ +} +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +public class C1 +{ + public C0 P1 {get; set;} +} +"; + var comp1 = CreateCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main(C1 x) + { + x.P1 = null; + } +} +"; + + AssertUsedAssemblyReferences(source2, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source2, comp0Ref, comp1ImageRef); + + var source3 = +@" +public class C3 +{ + public static void Main(C1 x) + { + _ = x.P1; + } +} +"; + + AssertUsedAssemblyReferences(source3, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source3, comp0Ref, comp1ImageRef); + } + + [Fact] + public void IndexerReference_01() + { + var source0 = +@" +public class C0 +{ +} +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0ImageRef = comp0.EmitToImageReference(); + + var source1 = +@" +Public Class C1 + Public Shared Property P1(x As Integer) As C0 + Get + Return Nothing + End Get + Set + End Set + End Property +End Class +"; + var comp1 = CreateVisualBasicCompilation(source1, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard, new[] { comp0ImageRef })); + comp1.VerifyDiagnostics(); + + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main() + { + C1.P1[0] = null; + } +} +"; + var references = new[] { comp0ImageRef, comp1ImageRef }; + AssertUsedAssemblyReferences(source2, references, + // (6,12): error CS1545: Property, indexer, or event 'C1.P1[int]' is not supported by the language; try directly calling accessor methods 'C1.get_P1(int)' or 'C1.set_P1(int, C0)' + // C1.P1[0] = null; + Diagnostic(ErrorCode.ERR_BindToBogusProp2, "P1").WithArguments("C1.P1[int]", "C1.get_P1(int)", "C1.set_P1(int, C0)").WithLocation(6, 12) + ); + + var source3 = +@" +public class C3 +{ + public static void Main() + { + _ = C1.P1[0]; + } +} +"; + + AssertUsedAssemblyReferences(source3, references, + // (6,16): error CS1545: Property, indexer, or event 'C1.P1[int]' is not supported by the language; try directly calling accessor methods 'C1.get_P1(int)' or 'C1.set_P1(int, C0)' + // _ = C1.P1[0]; + Diagnostic(ErrorCode.ERR_BindToBogusProp2, "P1").WithArguments("C1.P1[int]", "C1.get_P1(int)", "C1.set_P1(int, C0)").WithLocation(6, 16) + ); + + var source4 = +@" +using static C1; + +public class C2 +{ + public static void Main() + { + P1[0] = null; + } +} +"; + + AssertUsedAssemblyReferences(source4, references, + // (2,1): hidden CS8019: Unnecessary using directive. + // using static C1; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static C1;").WithLocation(2, 1), + // (8,9): error CS1545: Property, indexer, or event 'C1.P1[int]' is not supported by the language; try directly calling accessor methods 'C1.get_P1(int)' or 'C1.set_P1(int, C0)' + // P1[0] = null; + Diagnostic(ErrorCode.ERR_BindToBogusProp2, "P1").WithArguments("C1.P1[int]", "C1.get_P1(int)", "C1.set_P1(int, C0)").WithLocation(8, 9) + ); + + var source5 = +@" +using static C1; + +public class C3 +{ + public static void Main() + { + _ = P1[0]; + } +} +"; + + AssertUsedAssemblyReferences(source5, references, + // (2,1): hidden CS8019: Unnecessary using directive. + // using static C1; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static C1;").WithLocation(2, 1), + // (8,13): error CS1545: Property, indexer, or event 'C1.P1[int]' is not supported by the language; try directly calling accessor methods 'C1.get_P1(int)' or 'C1.set_P1(int, C0)' + // _ = P1[0]; + Diagnostic(ErrorCode.ERR_BindToBogusProp2, "P1").WithArguments("C1.P1[int]", "C1.get_P1(int)", "C1.set_P1(int, C0)").WithLocation(8, 13) + ); + } + + [Fact] + public void IndexerReference_02() + { + var source0 = +@" +public class C0 +{ +} +"; + var comp0 = CreateCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +public class C1 +{ + public C0 this[int x] {get => default; set {}} +} +"; + var comp1 = CreateCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + var comp1ImageRef = comp1.EmitToImageReference(); + + var source2 = +@" +public class C2 +{ + public static void Main(C1 x) + { + x[0] = null; + } +} +"; + + AssertUsedAssemblyReferences(source2, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source2, comp0Ref, comp1ImageRef); + + var source3 = +@" +public class C3 +{ + public static void Main(C1 x) + { + _ = x[0]; + } +} +"; + + AssertUsedAssemblyReferences(source3, comp0Ref, comp1Ref); + AssertUsedAssemblyReferences(source3, comp0Ref, comp1ImageRef); + } + + [Fact] + public void WellKnownTypeReference_01() + { + var source0 = +@" +namespace System +{ + public class Object {} + public class ValueType {} + public struct Void {} +} +"; + var comp0 = CreateEmptyCompilation(source0); + comp0.VerifyDiagnostics(); + var comp0Ref = comp0.ToMetadataReference(); + + var source1 = +@" +namespace System +{ + public class Type + { + public static Type GetTypeFromHandle(RuntimeTypeHandle handle) => default; + } + + public struct RuntimeTypeHandle {} +} +"; + var comp1 = CreateEmptyCompilation(source1, references: new[] { comp0Ref }); + comp1.VerifyDiagnostics(); + + var comp1Ref = comp1.ToMetadataReference(); + + var source2 = +@" +public class Type +{ +} +"; + var comp2 = CreateEmptyCompilation(source2, references: new[] { comp0Ref }); + comp2.VerifyDiagnostics(); + + var comp2Ref = comp2.ToMetadataReference(); + + var source3 = +@" +public class C2 +{ + public static void Main() + { + _ = typeof(C2); + } +} +"; + + var comp3 = CreateEmptyCompilation(source3, references: new[] { comp0Ref, comp1Ref, comp2Ref }); + + AssertUsedAssemblyReferences(comp3, comp1Ref); + + var source4 = +@" +public class C2 +{ + public static void Main() + { + _ = typeof(Type); + } +} +"; + + var comp4 = CreateEmptyCompilation(source4, references: new[] { comp0Ref, comp1Ref, comp2Ref }); + + AssertUsedAssemblyReferences(comp4, comp1Ref, comp2Ref); + } + + [Fact] + public void WellKnownTypeReference_02() + { + var source3 = +@" +public class C2 +{ + public static void Main() + { + dynamic x = new C1(); + x.M1(); + } +} + +class C1 +{ + public void M1() {} +} +"; + + CompileWithUsedAssemblyReferences(source3, targetFramework: TargetFramework.StandardAndCSharp); + } + + [Fact] + public void WellKnownTypeReference_03() + { + var source3 = +@" +public class C2 +{ + public static void Main() + { + var x = new {a = 1}; + x.ToString(); + } +} +"; + + CompileWithUsedAssemblyReferences(source3, targetFramework: TargetFramework.StandardAndCSharp); + } + + [Fact] + public void WellKnownTypeReference_04() + { + string source = @" +using System; +class C +{ + int x { set { Console.WriteLine($""setX""); } } + int y { set { Console.WriteLine($""setY""); } } + int z { set { Console.WriteLine($""setZ""); } } + + C getHolderForX() { Console.WriteLine(""getHolderforX""); return this; } + C getHolderForY() { Console.WriteLine(""getHolderforY""); return this; } + C getHolderForZ() { Console.WriteLine(""getHolderforZ""); return this; } + C getDeconstructReceiver() { Console.WriteLine(""getDeconstructReceiver""); return this; } + + static void Main() + { + C c = new C(); + bool b = false; + (c.getHolderForX().x, (c.getHolderForY().y, c.getHolderForZ().z)) = b ? default : c.getDeconstructReceiver(); + } + public void Deconstruct(out D1 x, out C1 t) { x = new D1(); t = new C1(); Console.WriteLine(""Deconstruct1""); } +} +class C1 +{ + public void Deconstruct(out D2 y, out D3 z) { y = new D2(); z = new D3(); Console.WriteLine(""Deconstruct2""); } +} +class D1 +{ + public static implicit operator int(D1 d) { Console.WriteLine(""Conversion1""); return 1; } +} +class D2 +{ + public static implicit operator int(D2 d) { Console.WriteLine(""Conversion2""); return 2; } +} +class D3 +{ + public static implicit operator int(D3 d) { Console.WriteLine(""Conversion3""); return 3; } +} +"; + + string expected = +@"getHolderforX +getHolderforY +getHolderforZ +getDeconstructReceiver +Deconstruct1 +Deconstruct2 +Conversion1 +Conversion2 +Conversion3 +setX +setY +setZ +"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + CompileWithUsedAssemblyReferences(comp, expectedOutput: expected); + } + + [Fact] + public void UseMissingAccessor() + { + var text = @" +class C +{ + event System.Action E { remove { } } //CS0065 + + void Goo() + { + E += null; //no separate error + } +} +"; + CreateCompilation(text).VerifyEmitDiagnostics( + // (4,25): error CS0065: 'C.E': event property must have both add and remove accessors + // event System.Action E { remove { } } + Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("C.E")).GetUsedAssemblyReferences(); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/IndexedPropertyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/IndexedPropertyTests.cs index 282f0f3514c9f..0dbc38f5e21b4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/IndexedPropertyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/IndexedPropertyTests.cs @@ -1402,7 +1402,8 @@ static void M(IC c) compilation2.VerifyDiagnostics(); } - [ClrOnlyFact] + [ClrOnlyFact(Skip = "https://github.com/dotnet/roslyn/issues/39934")] + [WorkItem(39934, "https://github.com/dotnet/roslyn/issues/39934")] public void OverloadResolutionWithSimpleProperty() { var source1 = @@ -1486,6 +1487,7 @@ static void M(IC c) }"; var compilation2 = CreateCompilation(source2, new[] { reference1 }); compilation2.VerifyDiagnostics(); + CompileAndVerify(compilation2); } [ClrOnlyFact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs index 4daa9c046308e..82169ec29885f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs @@ -1750,6 +1750,8 @@ class Derived : Base Assert.Equal(int16Type, baseIndexer.Parameters.Single().TypeWithAnnotations.CustomModifiers.Single().Modifier()); Assert.Equal(int16Type, derivedIndexer.Parameters.Single().TypeWithAnnotations.CustomModifiers.Single().Modifier()); + + CompileAndVerify(comp); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] @@ -1947,6 +1949,8 @@ class Implementation : I Assert.Equal(int16Type, interfaceIndexer.Parameters.Single().TypeWithAnnotations.CustomModifiers.Single().Modifier()); Assert.Equal(int16Type, implementationIndexer.Parameters.Single().TypeWithAnnotations.CustomModifiers.Single().Modifier()); + + CompileAndVerify(comp); } private static Func IsPropertyWithSingleParameter(SpecialType paramSpecialType, bool isArrayType = false) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs index 54735fe5d6435..8fa874b64102b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/EventTests.cs @@ -848,7 +848,8 @@ class C #endregion #region Error cases - [Fact] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39979")] + [WorkItem(39979, "https://github.com/dotnet/roslyn/issues/39979")] public void VoidEvent() { var text = diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index edcf4ae1f223d..5c06d4ad6e5da 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -2224,7 +2224,8 @@ private TextSpan GetSpanIn(SyntaxTree syntaxTree, string textToFind) } [WorkItem(543705, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543705")] - [Fact] + [WorkItem(39992, "https://github.com/dotnet/roslyn/issues/39992")] + [Fact(Skip = "PROTOTYPE(UsedAssemblyReferences): The test hook is blocked by https://github.com/dotnet/roslyn/issues/39992")] public void GetDiagnosticsCalledTwice() { var text = @" diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 05627a10af148..db99d196b9595 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -496,7 +496,6 @@ internal sealed override void CompilationFinished() internal override IAssemblySymbolInternal CommonCorLibrary => CorLibrary; internal abstract TAssemblySymbol CorLibrary { get; } - internal abstract Cci.INamedTypeReference GetSystemType(TSyntaxNode syntaxOpt, DiagnosticBag diagnostics); internal abstract Cci.INamedTypeReference GetSpecialType(SpecialType specialType, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); internal sealed override Cci.ITypeReference EncTranslateType(ITypeSymbolInternal type, DiagnosticBag diagnostics) @@ -953,7 +952,7 @@ public sealed override Cci.ITypeReference GetPlatformType(Cci.PlatformType platf switch (platformType) { case Cci.PlatformType.SystemType: - return GetSystemType((TSyntaxNode)context.SyntaxNodeOpt, context.Diagnostics); + throw ExceptionUtilities.UnexpectedValue(platformType); default: return GetSpecialType((SpecialType)platformType, (TSyntaxNode)context.SyntaxNodeOpt, context.Diagnostics); diff --git a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexerBase.cs b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexerBase.cs index 43017309dfd34..bd72e1df7c65c 100644 --- a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexerBase.cs +++ b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexerBase.cs @@ -232,6 +232,10 @@ public override void Visit(INestedTypeReference nestedTypeReference) public override void Visit(IPropertyDefinition propertyDefinition) { + this.Visit(propertyDefinition.RefCustomModifiers); + this.Visit(propertyDefinition.ReturnValueCustomModifiers); + this.Visit(propertyDefinition.GetType(Context)); + this.Visit(propertyDefinition.Parameters); } diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index f2b8391eae425..1f502cfc1ecb6 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -12,6 +12,7 @@ using System.Reflection.Metadata.Ecma335; using System.Text; using System.Threading; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -1046,9 +1047,49 @@ private static CSharpCompilation CreateCompilationCore( { VerifyUsesOfNullability(createCompilationLambda().SourceModule.GlobalNamespace, expectedUsesOfNullable: ImmutableArray.Empty); } + +#if false // PROTOTYPE(UsedAssemblyReferences): Temporary test hook + VerifyUsedAssemblyReferences(createCompilationLambda); +#endif return compilation; } +#if false // PROTOTYPE(UsedAssemblyReferences): Temporary test hook + private static void VerifyUsedAssemblyReferences(Func createCompilationLambda) + { + var comp = createCompilationLambda(); + var used = comp.GetUsedAssemblyReferences(); + + var compileDiagnostics = comp.GetDiagnostics(); + var emitDiagnostics = comp.GetEmitDiagnostics(); + + if (!compileDiagnostics.Any(d => d.DefaultSeverity == DiagnosticSeverity.Error) && + comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Assembly).Count() > used.Length) + { + if (!compileDiagnostics.Any(d => d.Code == (int)ErrorCode.HDN_UnusedExternAlias || d.Code == (int)ErrorCode.HDN_UnusedUsingDirective)) + { + var comp2 = comp.RemoveAllReferences().AddReferences(used.Concat(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Module))); + comp2.GetEmitDiagnostics().Where(d => shouldCompare(d)).Verify( + emitDiagnostics.Where(d => shouldCompare(d)). + Select(d => new DiagnosticDescription(d, errorCodeOnly: false, includeDefaultSeverity: false, includeEffectiveSeverity: false)).ToArray()); + } + } + else + { + AssertEx.Equal(comp.References.Where(r => r.Properties.Kind == MetadataImageKind.Assembly && comp.GetAssemblyOrModuleSymbol(r) is object), used); + } + + static bool shouldCompare(Diagnostic d) + { + return d.Code != (int)ErrorCode.WRN_SameFullNameThisAggAgg && + d.Code != (int)ErrorCode.WRN_SameFullNameThisNsAgg && + d.Code != (int)ErrorCode.WRN_AmbiguousXMLReference && + d.Code != (int)ErrorCode.WRN_MultiplePredefTypes && + d.Code != (int)ErrorCode.WRN_SameFullNameThisAggNs; + } + } +#endif + internal static bool IsNullableEnabled(CSharpCompilation compilation) { // This method should not cause any binding, including resolving references, etc. @@ -1280,9 +1321,9 @@ protected static TNode GetSyntaxNodeOfTypeForBinding(List syn return null; } - #endregion +#endregion - #region Semantic Model Helpers +#region Semantic Model Helpers public Tuple GetBindingNodeAndModel(CSharpCompilation compilation, int treeIndex = 0) where TNode : SyntaxNode { @@ -1417,9 +1458,9 @@ private static TNode FindBindingNode(SyntaxTree tree, string startTag, st Assert.Equal(bindText, node.ToString()); return ((TNode)node); } - #endregion +#endregion - #region Attributes +#region Attributes internal IEnumerable GetAttributeNames(ImmutableArray attributes) { @@ -1436,9 +1477,9 @@ internal IEnumerable GetAttributeStrings(ImmutableArray a.ToString()); } - #endregion +#endregion - #region Documentation Comments +#region Documentation Comments internal static string GetDocumentationCommentText(CSharpCompilation compilation, params DiagnosticDescription[] expectedDiagnostics) { @@ -1500,9 +1541,9 @@ internal static string GetDocumentationCommentText(CSharpCompilation compilation } } - #endregion +#endregion - #region IL Validation +#region IL Validation internal override string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary markers) { @@ -1634,9 +1675,9 @@ public override string VisualizeLocalType(object type) } } - #endregion +#endregion - #region IOperation tree validation +#region IOperation tree validation protected static (IOperation operation, SyntaxNode node) GetOperationAndSyntaxForTest(CSharpCompilation compilation) where TSyntaxNode : SyntaxNode @@ -1853,9 +1894,9 @@ protected static MetadataReference VerifyOperationTreeAndDiagnosticsForTestWithI return ilReference; } - #endregion +#endregion - #region Span +#region Span protected static CSharpCompilation CreateCompilationWithSpan(SyntaxTree tree, CSharpCompilationOptions options = null) { @@ -2109,9 +2150,9 @@ public static T[] ToArray(void* ptr, int count) } } }"; - #endregion +#endregion - #region Index and Range +#region Index and Range protected static CSharpCompilation CreateCompilationWithIndex(CSharpTestSource text, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) { var reference = CreateCompilation(TestSources.Index).VerifyDiagnostics(); @@ -2144,9 +2185,9 @@ protected static CSharpCompilation CreateCompilationWithIndexAndRangeAndSpan(CSh options: options, parseOptions: parseOptions); } - #endregion +#endregion - #region Theory Helpers +#region Theory Helpers public static IEnumerable NonNullTypesTrueAndFalseDebugDll { @@ -2171,7 +2212,7 @@ public static IEnumerable NonNullTypesTrueAndFalseReleaseDll }; } } - #endregion +#endregion protected static readonly string s_IAsyncEnumerable = @" namespace System.Collections.Generic diff --git a/src/Compilers/Test/Utilities/CSharp/Extensions.cs b/src/Compilers/Test/Utilities/CSharp/Extensions.cs index f7b519976541c..29e855a05bbbc 100644 --- a/src/Compilers/Test/Utilities/CSharp/Extensions.cs +++ b/src/Compilers/Test/Utilities/CSharp/Extensions.cs @@ -827,4 +827,14 @@ public static INamespaceSymbol GetNestedNamespace(this INamespaceSymbol ns, stri { return method.TypeArguments.Select(t => t.NullableAnnotation); } + + public static NamedTypeSymbol GetWellKnownType(this CSharpCompilation compilation, WellKnownType type) + { + return compilation.GetWellKnownType(type, recordUsage: false); + } + + public static Symbol GetWellKnownTypeMember(this CSharpCompilation compilation, WellKnownMember member) + { + return compilation.GetWellKnownTypeMember(member, recordUsage: false); + } } diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index a59fde938bf0d..b1c6984a78a72 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -563,19 +563,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Next End Function - Friend NotOverridable Overrides Function GetSystemType(syntaxOpt As SyntaxNode, diagnostics As DiagnosticBag) As Cci.INamedTypeReference - Dim systemTypeSymbol As NamedTypeSymbol = SourceModule.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type) - - Dim useSiteError = Binder.GetUseSiteErrorForWellKnownType(systemTypeSymbol) - If useSiteError IsNot Nothing Then - Binder.ReportDiagnostic(diagnostics, - If(syntaxOpt IsNot Nothing, syntaxOpt.GetLocation(), NoLocation.Singleton), - useSiteError) - End If - - Return Translate(systemTypeSymbol, syntaxOpt, diagnostics, needDeclaration:=True) - End Function - Friend NotOverridable Overrides Function GetSpecialType(specialType As SpecialType, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As Cci.INamedTypeReference Return Translate(GetUntranslatedSpecialType(specialType, syntaxNodeOpt, diagnostics), needDeclaration:=True, diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs index d51938cdb51d4..dc3c78029959c 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs @@ -125,7 +125,7 @@ private static ReadOnlyCollection GetDynamicTransforms( { var builder = ArrayBuilder.GetInstance(); CSharpCompilation.DynamicTransformsEncoder.Encode(type, customModifiersCount, refKind, builder, addCustomModifierFlags: true); - var bytes = builder.Count > 0 && compilation.HasDynamicEmitAttributes() ? + var bytes = builder.Count > 0 && compilation.HasDynamicEmitAttributes(recordUsage: false) ? DynamicFlagsCustomTypeInfo.ToBytes(builder) : null; builder.Free(); @@ -137,7 +137,7 @@ private static ReadOnlyCollection GetTupleElementNames( TypeSymbol type) { var builder = ArrayBuilder.GetInstance(); - var names = CSharpCompilation.TupleNamesEncoder.TryGetNames(type, builder) && compilation.HasTupleNamesAttributes ? + var names = CSharpCompilation.TupleNamesEncoder.TryGetNames(type, builder) && compilation.HasTupleNamesAttributes(recordUsage: false) ? new ReadOnlyCollection(builder.ToArray()) : null; builder.Free(); diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs index 889927504d3c2..f4f919447b46f 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Rewriters/LocalDeclarationRewriter.cs @@ -100,9 +100,9 @@ private static void CreateLocal( declaredLocals.Add(local); - var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); + var typeType = compilation.GetWellKnownType(WellKnownType.System_Type, recordUsage: false); var stringType = compilation.GetSpecialType(SpecialType.System_String); - var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor); + var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor, recordUsage: false); var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType); bool hasCustomTypeInfoPayload;