diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs index 72c45b797d8a..bb61efe332c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs @@ -642,5 +642,40 @@ public static AnnotatedTypeSymbol GetType(this Context cx, Microsoft.CodeAnalysi /// public static IEnumerable GetAnnotatedTypeArguments(this INamedTypeSymbol symbol) => symbol.TypeArguments.Zip(symbol.TypeArgumentNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); + + /// + /// Returns true if the symbol is public, protected or protected internal. + /// + public static bool IsPublicOrProtected(this ISymbol symbol) => + symbol.DeclaredAccessibility == Accessibility.Public + || symbol.DeclaredAccessibility == Accessibility.Protected + || symbol.DeclaredAccessibility == Accessibility.ProtectedOrInternal; + + /// + /// Returns true if the given symbol should be extracted. + /// + public static bool ShouldExtractSymbol(this ISymbol symbol) + { + // Extract all source symbols and public/protected metadata symbols. + if (symbol.Locations.Any(x => !x.IsInMetadata) || symbol.IsPublicOrProtected()) + { + return true; + } + if (symbol is IMethodSymbol method) + { + return method.ExplicitInterfaceImplementations.Any(m => m.ContainingType.ShouldExtractSymbol()); + } + if (symbol is IPropertySymbol property) + { + return property.ExplicitInterfaceImplementations.Any(m => m.ContainingType.ShouldExtractSymbol()); + } + return false; + } + + /// + /// Returns the symbols that should be extracted. + /// + public static IEnumerable ExtractionCandidates(this IEnumerable symbols) where T : ISymbol => + symbols.Where(symbol => symbol.ShouldExtractSymbol()); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 6890ca490847..6ba5cca01cf6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -101,7 +101,7 @@ public void Overrides(TextWriter trapFile) } } - if (Symbol.OverriddenMethod is not null) + if (Symbol.OverriddenMethod is not null && Symbol.OverriddenMethod.ShouldExtractSymbol()) { trapFile.overrides(this, Method.Create(Context, Symbol.OverriddenMethod)); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 56382923a480..efd09409afd8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -225,7 +225,7 @@ private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSy } /// - /// Called to extract all members and nested types. + /// Called to extract members and nested types. /// This is called on each member of a namespace, /// in either source code or an assembly. /// @@ -236,7 +236,7 @@ public void ExtractRecursive() Context.BindComments(this, l); } - foreach (var member in Symbol.GetMembers()) + foreach (var member in Symbol.GetMembers().ExtractionCandidates()) { switch (member.Kind) { @@ -262,16 +262,16 @@ public void PopulateGenerics() var members = new List(); - foreach (var member in Symbol.GetMembers()) + foreach (var member in Symbol.GetMembers().ExtractionCandidates()) members.Add(member); - foreach (var member in Symbol.GetTypeMembers()) + foreach (var member in Symbol.GetTypeMembers().ExtractionCandidates()) members.Add(member); // Mono extractor puts all BASE interface members as members of the current interface. if (Symbol.TypeKind == TypeKind.Interface) { - foreach (var baseInterface in Symbol.Interfaces) + foreach (var baseInterface in Symbol.Interfaces.ExtractionCandidates()) { foreach (var member in baseInterface.GetMembers()) members.Add(member); @@ -288,7 +288,7 @@ public void PopulateGenerics() if (Symbol.BaseType is not null) Create(Context, Symbol.BaseType).PopulateGenerics(); - foreach (var i in Symbol.Interfaces) + foreach (var i in Symbol.Interfaces.ExtractionCandidates()) { Create(Context, i).PopulateGenerics(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs index b839d2c976a3..3ea99a0d772c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs @@ -269,7 +269,7 @@ private static void AnalyseNamespace(Context cx, INamespaceSymbol ns) AnalyseNamespace(cx, memberNamespace); } - foreach (var memberType in ns.GetTypeMembers()) + foreach (var memberType in ns.GetTypeMembers().ExtractionCandidates()) { Entities.Type.Create(cx, memberType).ExtractRecursive(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs index 50f673a71581..3c01893dd89c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs @@ -549,7 +549,6 @@ private static ExitCode AnalyseTracing( compilerArguments.CompilationOptions .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) .WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths)) - .WithMetadataImportOptions(MetadataImportOptions.All) ); }, (compilation, options) => analyser.EndInitialize(compilerArguments, options, compilation, cwd, args), diff --git a/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md b/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md new file mode 100644 index 000000000000..7b284df36526 --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Only extract *public* and *protected* members from reference assemblies. This yields an approximate average speed-up of around 10% for extraction and query execution. Custom MaD rows using `Field`-based summaries may need to be changed to `SyntheticField`-based flows if they reference private fields. diff --git a/csharp/ql/test/library-tests/conversion/operator/Operator.expected b/csharp/ql/test/library-tests/conversion/operator/Operator.expected index dd11565ad2a9..b0dcfc54260d 100644 --- a/csharp/ql/test/library-tests/conversion/operator/Operator.expected +++ b/csharp/ql/test/library-tests/conversion/operator/Operator.expected @@ -21,7 +21,6 @@ | Int32 | Decimal | | Int32 | Index | | Int32 | Int128 | -| Int32 | MetadataToken | | Int32 | NFloat | | Int64 | Decimal | | Int64 | Int128 | @@ -29,7 +28,6 @@ | IntPtr | Int128 | | IntPtr | NFloat | | Memory`1 | ReadOnlyMemory | -| MetadataToken | Int32 | | NFloat | Double | | SByte | Decimal | | SByte | Half | @@ -59,4 +57,3 @@ | UIntPtr | Int128 | | UIntPtr | NFloat | | UIntPtr | UInt128 | -| UnixFileMode | Nullable | diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected index ab433d458963..ff2c9da9ea39 100644 --- a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected +++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected @@ -183,8 +183,6 @@ | IReadOnlyList | dynamic | | Int16[] | Object | | Int16[] | dynamic | -| Int32[,] | Object | -| Int32[,] | dynamic | | Int32[] | Object | | Int32[] | dynamic | | Int64[] | Object | @@ -223,8 +221,6 @@ | T5 | C1 | | T5 | Object | | T5 | dynamic | -| UInt16[][] | Object | -| UInt16[][] | dynamic | | UInt32[] | Object | | UInt32[] | dynamic | | UInt64[] | Object | @@ -283,7 +279,6 @@ | null | IReadOnlyList | | null | IReadOnlyList | | null | Int16[] | -| null | Int32[,] | | null | Int32[] | | null | Int64[] | | null | Object | @@ -294,7 +289,6 @@ | null | T4 | | null | T4[] | | null | T5 | -| null | UInt16[][] | | null | UInt32[] | | null | UInt64[] | | null | dynamic | diff --git a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected index d2617be088bc..1bf279341ce8 100644 --- a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected +++ b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected @@ -1,68 +1,33 @@ type | file://:0:0:0:0 | delegate* default | B | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | A | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | ref int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | readonly int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | Void* | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int* | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | object | DefaultCallingConvention | | file://:0:0:0:0 | delegate* stdcall | Void | StdCallCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | int | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | int | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | unmanagedCallingConvention parameter | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | A | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | B | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref byte! | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* default | 2 | file://:0:0:0:0 | `2 | readonly int! | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | int*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | IntPtr! | -| file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | ref byte! | -| file://:0:0:0:0 | delegate* default | 2 | file://:0:0:0:0 | `2 | PortableTailCallFrame*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | object | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | T | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | Void*! | | file://:0:0:0:0 | delegate* stdcall | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* stdcall | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* stdcall | 2 | file://:0:0:0:0 | `2 | T | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | byte*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | int! | -| file://:0:0:0:0 | delegate* unmanaged | 2 | file://:0:0:0:0 | `2 | byte! | -| file://:0:0:0:0 | delegate* unmanaged | 3 | file://:0:0:0:0 | `3 | long! | -| file://:0:0:0:0 | delegate* unmanaged | 4 | file://:0:0:0:0 | `4 | long! | -| file://:0:0:0:0 | delegate* unmanaged | 5 | file://:0:0:0:0 | `5 | EVENT_FILTER_DESCRIPTOR*! | -| file://:0:0:0:0 | delegate* unmanaged | 6 | file://:0:0:0:0 | `6 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | char*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | IntPtr! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | int! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | PosixSignal! | | file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | IntPtr! | | file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | IntPtr! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | NoGCRegionCallbackFinalizerWorkItem*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | byte*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 2 | file://:0:0:0:0 | `2 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 3 | file://:0:0:0:0 | `3 | GCConfigurationType! | -| file://:0:0:0:0 | delegate* unmanaged | 4 | file://:0:0:0:0 | `4 | long! | invocation | FunctionPointer.cs:17:21:17:43 | function pointer call | | FunctionPointer.cs:23:13:23:44 | function pointer call | diff --git a/csharp/ql/test/library-tests/tuples/tuples.expected b/csharp/ql/test/library-tests/tuples/tuples.expected index c2042bfb14ac..cb39eb0ca3b8 100644 --- a/csharp/ql/test/library-tests/tuples/tuples.expected +++ b/csharp/ql/test/library-tests/tuples/tuples.expected @@ -8,13 +8,11 @@ members2 | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item1 | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item2 | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item[int] | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Length | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ValueTuple(int, int) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int)) | @@ -25,7 +23,6 @@ members2 | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -36,7 +33,6 @@ members2 | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item[int] | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int, int)) | @@ -47,7 +43,6 @@ members2 | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -60,7 +55,6 @@ members2 | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Rest | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int, (int)) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int, int, int, int)) | @@ -71,7 +65,6 @@ members2 | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -86,6 +79,5 @@ members2 | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Rest | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int, (int, int, int)) |