From 7b57680087ed20def067a64da5c45aef0facd4bd Mon Sep 17 00:00:00 2001 From: Dennis Fischer Date: Tue, 3 Feb 2015 15:23:46 +0100 Subject: [PATCH 01/16] Fix SimpleDiagnostic GetHashCode is more specific than Equals --- .../Diagnostic/Diagnostic_SimpleDiagnostic.cs | 16 ++++++++----- .../Core/Portable/InternalUtilities/Hash.cs | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs b/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs index 4d36f6c3db7c7..e5c370a9c0ff1 100644 --- a/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs +++ b/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs @@ -34,13 +34,18 @@ private SimpleDiagnostic( if ((warningLevel == 0 && severity != DiagnosticSeverity.Error) || (warningLevel != 0 && severity == DiagnosticSeverity.Error)) { - throw new ArgumentException("warningLevel"); + throw new ArgumentException(nameof(warningLevel)); + } + + if(descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); } _descriptor = descriptor; _severity = severity; _warningLevel = warningLevel; - _location = location; + _location = location ?? Location.None; _additionalLocations = additionalLocations == null ? SpecializedCollections.EmptyReadOnlyList() : additionalLocations.ToImmutableArray(); _messageArgs = messageArgs ?? SpecializedCollections.EmptyArray(); } @@ -131,10 +136,9 @@ public override bool Equals(object obj) public override int GetHashCode() { return Hash.Combine(_descriptor, - Hash.Combine(_messageArgs.GetHashCode(), - Hash.Combine(_location.GetHashCode(), - Hash.Combine(_severity.GetHashCode(), _warningLevel) - ))); + Hash.CombineValues(_messageArgs, + Hash.Combine(_warningLevel, + Hash.Combine(_location, (int)_severity)))); } internal override Diagnostic WithLocation(Location location) diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index 4dfeff33829be..1bb82411f4323 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -66,6 +66,30 @@ internal static int CombineValues(IEnumerable values, int maxItemsToHash = return hashCode; } + internal static int CombineValues(T[] values, int maxItemsToHash = int.MaxValue) + { + if (values == null) + { + return 0; + } + + var maxSize = Math.Min(maxItemsToHash, values.Length); + var hashCode = 0; + + for (int i = 0; i < maxSize; i++) + { + T value = values[i]; + + // Should end up with a constrained virtual call to object.GetHashCode (i.e. avoid boxing where possible). + if (value != null) + { + hashCode = Hash.Combine(value.GetHashCode(), hashCode); + } + } + + return hashCode; + } + internal static int CombineValues(ImmutableArray values, int maxItemsToHash = int.MaxValue) { if (values.IsDefaultOrEmpty) From 3a54c09188fd60ba62b16c79f85824d7c3e228a4 Mon Sep 17 00:00:00 2001 From: Srivatsn Narayanan Date: Fri, 6 Feb 2015 17:47:50 -0800 Subject: [PATCH 02/16] Create new projects for System.Runtime.Analyzers Move rule CA1001 to this project. Rewrite the codefixer for it to be based on DocumentEditor and hence language agnostic. Fix for CA1001 shouldn't generate a dispose method if there is already one in the type. Instead modify that method to make it the interface implementation. Adding some tests. --- ...CSharpFxCopRulesDiagnosticAnalyzers.csproj | 3 +- .../CodeFixes/CA1001CSharpCodeFixProvider.cs | 83 ------ .../CodeFixes/CA1001CodeFixProviderBase.cs | 25 -- .../Core/FxCopRulesDiagnosticAnalyzers.csproj | 4 +- .../CSharpSystemRuntimeAnalyzers.csproj | 82 ++++++ .../CSharp/packages.config | 6 + .../Core/CodeFixProviderBase.cs | 51 ++++ ...isposableFieldsShouldBeDisposable.Fixer.cs | 85 ++++++ ...tOwnDisposableFieldsShouldBeDisposable.cs} | 25 +- .../Core/DiagnosticCategory.cs | 15 + .../Core/DiagnosticExtensions.cs | 135 +++++++++ .../Core/DocumentChangeAction.cs | 31 +++ .../Core/SystemRuntimeAnalyzers.csproj | 81 ++++++ ...ystemRuntimeAnalyzersResources.Designer.cs | 154 +++++++++++ .../Core/SystemRuntimeAnalyzersResources.resx | 150 ++++++++++ .../Core/WellKnownTypes.cs | 174 ++++++++++++ .../Core/packages.config | 6 + .../Test/SystemRuntimeAnalyzersTest.csproj | 105 +++++++ ...ableFieldsShouldBeDisposableTests.Fixer.cs | 256 ++++++++++++++++++ ...isposableFieldsShouldBeDisposableTests.cs} | 8 +- .../Test/packages.config | 6 + .../BasicSystemRuntimeAnalyzers.vbproj | 79 ++++++ .../VisualBasic/packages.config | 6 + .../Test/Design/CodeFixes/CA1001FixerTests.cs | 114 -------- .../FxCopRulesDiagnosticAnalyzersTest.csproj | 4 +- .../BasicFxCopRulesDiagnosticAnalyzers.vbproj | 3 +- .../CodeFixes/CA1001BasicCodeFixProvider.vb | 82 ------ src/Roslyn.sln | 31 +++ .../Editing/SyntaxEditorExtensions.cs | 4 +- 29 files changed, 1479 insertions(+), 329 deletions(-) delete mode 100644 src/Diagnostics/FxCop/CSharp/Design/CodeFixes/CA1001CSharpCodeFixProvider.cs delete mode 100644 src/Diagnostics/FxCop/Core/Design/CodeFixes/CA1001CodeFixProviderBase.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/packages.config create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/CodeFixProviderBase.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.Fixer.cs rename src/Diagnostics/FxCop/{Core/Design/CA1001DiagnosticAnalyzer.cs => System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.cs} (65%) create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticCategory.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticExtensions.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DocumentChangeAction.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/WellKnownTypes.cs create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/packages.config create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs rename src/Diagnostics/FxCop/{Test/Design/CA1001Tests.cs => System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs} (96%) create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/packages.config create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj create mode 100644 src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/packages.config delete mode 100644 src/Diagnostics/FxCop/Test/Design/CodeFixes/CA1001FixerTests.cs delete mode 100644 src/Diagnostics/FxCop/VisualBasic/Design/CodeFixes/CA1001BasicCodeFixProvider.vb diff --git a/src/Diagnostics/FxCop/CSharp/CSharpFxCopRulesDiagnosticAnalyzers.csproj b/src/Diagnostics/FxCop/CSharp/CSharpFxCopRulesDiagnosticAnalyzers.csproj index adc536d2335ff..090116bd30e01 100644 --- a/src/Diagnostics/FxCop/CSharp/CSharpFxCopRulesDiagnosticAnalyzers.csproj +++ b/src/Diagnostics/FxCop/CSharp/CSharpFxCopRulesDiagnosticAnalyzers.csproj @@ -73,7 +73,6 @@ - @@ -107,4 +106,4 @@ - + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/CSharp/Design/CodeFixes/CA1001CSharpCodeFixProvider.cs b/src/Diagnostics/FxCop/CSharp/Design/CodeFixes/CA1001CSharpCodeFixProvider.cs deleted file mode 100644 index 0c115068b41e1..0000000000000 --- a/src/Diagnostics/FxCop/CSharp/Design/CodeFixes/CA1001CSharpCodeFixProvider.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.FxCopAnalyzers.Design; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers.Design -{ - /// - /// CA1001: Types that own disposable fields should be disposable - /// - [ExportCodeFixProvider(LanguageNames.CSharp, Name = CA1001DiagnosticAnalyzer.RuleId), Shared] - public class CA1001CSharpCodeFixProvider : CA1001CodeFixProviderBase - { - internal override Task GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, Diagnostic diagnostic, CancellationToken cancellationToken) - { - //// We are going to implement IDisposable interface: - //// - //// public void Dispose() - //// { - //// throw new NotImplementedException(); - //// } - - var syntaxNode = nodeToFix as ClassDeclarationSyntax; - if (syntaxNode == null) - { - return Task.FromResult(document); - } - - var statement = CreateThrowNotImplementedStatement(model); - if (statement == null) - { - return Task.FromResult(document); - } - - var member = CreateSimpleMethodDeclaration(CA1001DiagnosticAnalyzer.Dispose, statement); - var newNode = - syntaxNode.BaseList != null ? - syntaxNode.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(CA1001DiagnosticAnalyzer.IDisposable))).AddMembers(new[] { member }) : - syntaxNode.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(CA1001DiagnosticAnalyzer.IDisposable))).AddMembers(new[] { member }).WithIdentifier(syntaxNode.Identifier.WithTrailingTrivia(SyntaxFactory.Space)); - newNode = newNode.WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation); - return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(nodeToFix, newNode))); - } - - protected StatementSyntax CreateThrowNotImplementedStatement(SemanticModel model) - { - var exceptionType = model.Compilation.GetTypeByMetadataName(NotImplementedExceptionName); - if (exceptionType == null) - { - // If we can't find the exception, we can't generate anything. - return null; - } - - return SyntaxFactory.ThrowStatement( - SyntaxFactory.ObjectCreationExpression( - SyntaxFactory.Token(SyntaxKind.NewKeyword), - SyntaxFactory.IdentifierName(exceptionType.Name), - SyntaxFactory.ArgumentList(), - null)); - } - - protected MethodDeclarationSyntax CreateSimpleMethodDeclaration(string name, StatementSyntax statement) - { - return SyntaxFactory.MethodDeclaration( - new SyntaxList(), - SyntaxFactory.TokenList(new SyntaxToken[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword) }), - SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), - null, - SyntaxFactory.Identifier(name), - null, - SyntaxFactory.ParameterList(), - new SyntaxList(), - SyntaxFactory.Block(statement), - new SyntaxToken()); - } - } -} diff --git a/src/Diagnostics/FxCop/Core/Design/CodeFixes/CA1001CodeFixProviderBase.cs b/src/Diagnostics/FxCop/Core/Design/CodeFixes/CA1001CodeFixProviderBase.cs deleted file mode 100644 index 620ef3d6b546e..0000000000000 --- a/src/Diagnostics/FxCop/Core/Design/CodeFixes/CA1001CodeFixProviderBase.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design -{ - /// - /// CA1001: Types that own disposable fields should be disposable - /// - public abstract class CA1001CodeFixProviderBase : CodeFixProviderBase - { - protected const string NotImplementedExceptionName = "System.NotImplementedException"; - protected const string IDisposableName = "System.IDisposable"; - - public sealed override ImmutableArray FixableDiagnosticIds - { - get { return ImmutableArray.Create(CA1001DiagnosticAnalyzer.RuleId); } - } - - protected sealed override string GetCodeFixDescription(Diagnostic diagnostic) - { - return FxCopFixersResources.ImplementIDisposableInterface; - } - } -} diff --git a/src/Diagnostics/FxCop/Core/FxCopRulesDiagnosticAnalyzers.csproj b/src/Diagnostics/FxCop/Core/FxCopRulesDiagnosticAnalyzers.csproj index d6e63e8122de2..36d58d9908f4f 100644 --- a/src/Diagnostics/FxCop/Core/FxCopRulesDiagnosticAnalyzers.csproj +++ b/src/Diagnostics/FxCop/Core/FxCopRulesDiagnosticAnalyzers.csproj @@ -103,7 +103,6 @@ - @@ -112,7 +111,6 @@ - @@ -195,4 +193,4 @@ - + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj new file mode 100644 index 0000000000000..2822e9322a7c5 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj @@ -0,0 +1,82 @@ + + + + + + + + + 12.0 + Debug + AnyCPU + {921B412A-5551-4853-82B4-46AD5A05A03E} + Library + true + System.Runtime.CSharp.Analyzers + System.Runtime.CSharp.Analyzers + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + .NETPortable + true + + + + + + + + + {1ee8cad3-55f9-4d91-96b2-084641da9a6c} + CodeAnalysis + + + {b501a547-c911-4a05-ac6e-274a50dff30e} + CSharpCodeAnalysis + + + {5f8d2414-064a-4b3a-9b42-8e2a04246be5} + Workspaces + + + {d8762a0a-3832-47be-bcf6-8b1060be6b28} + SystemRuntimeAnalyzers + + + + + False + ..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/packages.config b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/packages.config new file mode 100644 index 0000000000000..7a5f834c82a3f --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/packages.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/CodeFixProviderBase.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/CodeFixProviderBase.cs new file mode 100644 index 0000000000000..2e914bff0087e --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/CodeFixProviderBase.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; + +namespace System.Runtime.Analyzers +{ + public abstract class CodeFixProviderBase : CodeFixProvider + { + protected abstract string GetCodeFixDescription(Diagnostic diagnostic); + + internal abstract Task GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, Diagnostic diagnostic, CancellationToken cancellationToken); + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var document = context.Document; + var cancellationToken = context.CancellationToken; + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + foreach (var diagnostic in context.Diagnostics) + { + cancellationToken.ThrowIfCancellationRequested(); + + var nodeToFix = root.FindNode(diagnostic.Location.SourceSpan); + + var newDocument = await GetUpdatedDocumentAsync(document, model, root, nodeToFix, diagnostic, cancellationToken).ConfigureAwait(false); + + Debug.Assert(newDocument != null); + if (newDocument != document) + { + var codeFixDescription = GetCodeFixDescription(diagnostic); + context.RegisterCodeFix(new MyCodeAction(codeFixDescription, newDocument), diagnostic); + } + } + } + + private class MyCodeAction : DocumentChangeAction + { + public MyCodeAction(string title, Document newDocument) : + base(title, c => Task.FromResult(newDocument)) + { + } + } + } +} diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.Fixer.cs new file mode 100644 index 0000000000000..24cf7c5f0331f --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.Fixer.cs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; + +namespace System.Runtime.Analyzers +{ + /// + /// CA1001: Types that own disposable fields should be disposable + /// + [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared] + public class TypesThatOwnDisposableFieldsShouldBeDisposableFixer : CodeFixProvider + { + protected const string NotImplementedExceptionName = "System.NotImplementedException"; + protected const string IDisposableName = "System.IDisposable"; + + public sealed override ImmutableArray FixableDiagnosticIds + { + get { return ImmutableArray.Create(TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer.RuleId); } + } + + protected string GetCodeFixDescription(Diagnostic diagnostic) + { + return SystemRuntimeAnalyzersResources.ImplementIDisposableInterface; + } + + public async override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var generator = SyntaxGenerator.GetGenerator(context.Document); + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + var declaration = root.FindNode(context.Span); + declaration = generator.GetDeclaration(declaration); + + if (declaration == null) + { + return; + } + + // We cannot have multiple overlapping diagnostics of this id. + var diagnostic = context.Diagnostics.Single(); + + context.RegisterCodeFix(new DocumentChangeAction(SystemRuntimeAnalyzersResources.ImplementIDisposableInterface, + async ct => await ImplementIDisposable(context.Document, declaration, ct).ConfigureAwait(false)), + diagnostic); + } + + private async Task ImplementIDisposable(Document document, SyntaxNode declaration, CancellationToken cancellationToken) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); + var generator = editor.Generator; + var model = editor.SemanticModel; + + // Add the interface to the baselist. + var interfaceType = generator.TypeExpression(WellKnownTypes.IDisposable(model.Compilation)); + editor.AddInterfaceType(declaration, interfaceType); + + // Find a Dispose method. If one exists make that implement IDisposable, else generate a new method. + var typeSymbol = model.GetDeclaredSymbol(declaration) as INamedTypeSymbol; + var disposeMethod = (typeSymbol?.GetMembers("Dispose"))?.OfType()?.Where(m => m.Parameters.Length == 0).FirstOrDefault(); + if (disposeMethod != null && disposeMethod.DeclaringSyntaxReferences.Length == 1) + { + var memberPartNode = await disposeMethod.DeclaringSyntaxReferences.Single().GetSyntaxAsync(cancellationToken).ConfigureAwait(false); + memberPartNode = generator.GetDeclaration(memberPartNode); + editor.ReplaceNode(memberPartNode, generator.AsPublicInterfaceImplementation(memberPartNode, interfaceType)); + } + else + { + var throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(WellKnownTypes.NotImplementedException(model.Compilation))); + var member = generator.MethodDeclaration(TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer.Dispose, statements: new[] { throwStatement }); + member = generator.AsPublicInterfaceImplementation(member, interfaceType); + editor.AddMember(declaration, member); + } + + return editor.GetChangedDocument(); + } + } +} diff --git a/src/Diagnostics/FxCop/Core/Design/CA1001DiagnosticAnalyzer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.cs similarity index 65% rename from src/Diagnostics/FxCop/Core/Design/CA1001DiagnosticAnalyzer.cs rename to src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.cs index be6c510698e20..0ac28edff1993 100644 --- a/src/Diagnostics/FxCop/Core/Design/CA1001DiagnosticAnalyzer.cs +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/TypesThatOwnDisposableFieldsShouldBeDisposable.cs @@ -1,34 +1,32 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FxCopAnalyzers.Utilities; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design +namespace System.Runtime.Analyzers { /// /// CA1001: Types that own disposable fields should be disposable /// [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] - public sealed class CA1001DiagnosticAnalyzer : AbstractNamedTypeAnalyzer + public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : DiagnosticAnalyzer { internal const string RuleId = "CA1001"; internal const string Dispose = "Dispose"; internal const string IDisposable = "System.IDisposable"; internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, - new LocalizableResourceString(nameof(FxCopRulesResources.TypesThatOwnDisposableFieldsShouldBeDisposable), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources)), - new LocalizableResourceString(nameof(FxCopRulesResources.TypeOwnsDisposableFieldButIsNotDisposable), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources)), - FxCopDiagnosticCategory.Design, + new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.TypesThatOwnDisposableFieldsShouldBeDisposable), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources)), + new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.TypeOwnsDisposableFieldButIsNotDisposable), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources)), + DiagnosticCategory.Design, DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: "http://msdn.microsoft.com/library/ms182172.aspx", - customTags: DiagnosticCustomTags.Microsoft); + customTags: WellKnownDiagnosticTags.Telemetry); public override ImmutableArray SupportedDiagnostics { @@ -38,7 +36,16 @@ public override ImmutableArray SupportedDiagnostics } } - protected override void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) + public override void Initialize(AnalysisContext analysisContext) + { + analysisContext.RegisterSymbolAction(context => + { + AnalyzeSymbol((INamedTypeSymbol)context.Symbol, context.Compilation, context.ReportDiagnostic, context.Options, context.CancellationToken); + }, + SymbolKind.NamedType); + } + + private static void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) { var disposableType = WellKnownTypes.IDisposable(compilation); if (disposableType != null && !symbol.AllInterfaces.Contains(disposableType)) diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticCategory.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticCategory.cs new file mode 100644 index 0000000000000..e67dfb9b94e99 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticCategory.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace System.Runtime.Analyzers +{ + internal static class DiagnosticCategory + { + public static readonly string Design = SystemRuntimeAnalyzersResources.CategoryDesign; + public static readonly string Globalization = SystemRuntimeAnalyzersResources.CategoryGlobalization; + public static readonly string Interoperability = SystemRuntimeAnalyzersResources.CategoryInteroperability; + public static readonly string Performance = SystemRuntimeAnalyzersResources.CategoryPerformance; + public static readonly string Reliability = SystemRuntimeAnalyzersResources.CategoryReliability; + public static readonly string Usage = SystemRuntimeAnalyzersResources.CategoryUsage; + public static readonly string Naming = SystemRuntimeAnalyzersResources.CategoryNaming; + } +} diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticExtensions.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticExtensions.cs new file mode 100644 index 0000000000000..14385329d7868 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DiagnosticExtensions.cs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace System.Runtime.Analyzers +{ + internal static class DiagnosticExtensions + { + public static IEnumerable CreateDiagnostics( + this IEnumerable nodes, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var node in nodes) + { + yield return node.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this SyntaxNode node, + DiagnosticDescriptor rule, + params object[] args) + { + return node.GetLocation().CreateDiagnostic(rule, args); + } + + public static IEnumerable CreateDiagnostics( + this IEnumerable tokens, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var token in tokens) + { + yield return token.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this SyntaxToken token, + DiagnosticDescriptor rule, + params object[] args) + { + return token.GetLocation().CreateDiagnostic(rule, args); + } + + public static IEnumerable CreateDiagnostics( + this IEnumerable nodesOrTokens, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var nodeOrToken in nodesOrTokens) + { + yield return nodeOrToken.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this SyntaxNodeOrToken nodeOrToken, + DiagnosticDescriptor rule, + params object[] args) + { + return nodeOrToken.GetLocation().CreateDiagnostic(rule, args); + } + + public static IEnumerable CreateDiagnostics( + this IEnumerable symbols, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var symbol in symbols) + { + yield return symbol.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this ISymbol symbol, + DiagnosticDescriptor rule, + params object[] args) + { + return symbol.Locations.CreateDiagnostic(rule, args); + } + + public static IEnumerable CreateDiagnostics( + this IEnumerable locations, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var location in locations) + { + yield return location.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this Location location, + DiagnosticDescriptor rule, + params object[] args) + { + if (!location.IsInSource) + { + return Diagnostic.Create(rule, null, args); + } + + return Diagnostic.Create(rule, location, args); + } + + public static IEnumerable CreateDiagnostics( + this IEnumerable> setOfLocations, + DiagnosticDescriptor rule, + params object[] args) + { + foreach (var locations in setOfLocations) + { + yield return locations.CreateDiagnostic(rule, args); + } + } + + public static Diagnostic CreateDiagnostic( + this IEnumerable locations, + DiagnosticDescriptor rule, + params object[] args) + { + var location = locations.First(l => l.IsInSource); + var additionalLocations = locations.Where(l => l.IsInSource).Skip(1); + return Diagnostic.Create(rule, + location: location, + additionalLocations: additionalLocations, + messageArgs: args); + } + } +} diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DocumentChangeAction.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DocumentChangeAction.cs new file mode 100644 index 0000000000000..903f096b846ee --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/DocumentChangeAction.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; + +namespace Microsoft.CodeAnalysis +{ + internal class DocumentChangeAction : CodeAction + { + private readonly string _title; + private readonly Func> _createChangedDocument; + + public DocumentChangeAction(string title, Func> createChangedDocument) + { + _title = title; + _createChangedDocument = createChangedDocument; + } + + public override string Title + { + get { return _title; } + } + + protected override Task GetChangedDocumentAsync(CancellationToken cancellationToken) + { + return _createChangedDocument(cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj new file mode 100644 index 0000000000000..a0fefdfb6527e --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj @@ -0,0 +1,81 @@ + + + + + + + + + 12.0 + Debug + AnyCPU + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28} + Library + true + System.Runtime.Analyzers + System.Runtime.Analyzers + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + .NETPortable + true + + + + + + + + + {1ee8cad3-55f9-4d91-96b2-084641da9a6c} + CodeAnalysis + + + {5f8d2414-064a-4b3a-9b42-8e2a04246be5} + Workspaces + + + + + False + ..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll + + + + + + + + + + + + + + + + + + + True + True + SystemRuntimeAnalyzersResources.resx + + + + + + ResXFileCodeGenerator + SystemRuntimeAnalyzersResources.Designer.cs + + + + + + + + + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs new file mode 100644 index 0000000000000..b0f895fa2f7d9 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace System.Runtime.Analyzers { + using System; + using System.Reflection; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SystemRuntimeAnalyzersResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SystemRuntimeAnalyzersResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.Runtime.Analyzers.SystemRuntimeAnalyzersResources", typeof(SystemRuntimeAnalyzersResources).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Design. + /// + internal static string CategoryDesign { + get { + return ResourceManager.GetString("CategoryDesign", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Globalization. + /// + internal static string CategoryGlobalization { + get { + return ResourceManager.GetString("CategoryGlobalization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Interoperability. + /// + internal static string CategoryInteroperability { + get { + return ResourceManager.GetString("CategoryInteroperability", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Naming. + /// + internal static string CategoryNaming { + get { + return ResourceManager.GetString("CategoryNaming", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performance. + /// + internal static string CategoryPerformance { + get { + return ResourceManager.GetString("CategoryPerformance", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reliability. + /// + internal static string CategoryReliability { + get { + return ResourceManager.GetString("CategoryReliability", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Usage. + /// + internal static string CategoryUsage { + get { + return ResourceManager.GetString("CategoryUsage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Implement IDisposable Interface. + /// + internal static string ImplementIDisposableInterface { + get { + return ResourceManager.GetString("ImplementIDisposableInterface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' owns disposable fields but is not disposable. + /// + internal static string TypeOwnsDisposableFieldButIsNotDisposable { + get { + return ResourceManager.GetString("TypeOwnsDisposableFieldButIsNotDisposable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Types that own disposable fields should be disposable. + /// + internal static string TypesThatOwnDisposableFieldsShouldBeDisposable { + get { + return ResourceManager.GetString("TypesThatOwnDisposableFieldsShouldBeDisposable", resourceCulture); + } + } + } +} diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx new file mode 100644 index 0000000000000..ceac435cd70bf --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Types that own disposable fields should be disposable + + + Design + + + Globalization + + + Interoperability + + + Naming + + + Performance + + + Reliability + + + Usage + + + Implement IDisposable Interface + + + Type '{0}' owns disposable fields but is not disposable + + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/WellKnownTypes.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/WellKnownTypes.cs new file mode 100644 index 0000000000000..5676c11a1af43 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/WellKnownTypes.cs @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis; + +namespace System.Runtime.Analyzers +{ + internal static class WellKnownTypes + { + public static INamedTypeSymbol FlagsAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.FlagsAttribute"); + } + + public static INamedTypeSymbol StringComparison(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.StringComparison"); + } + + public static INamedTypeSymbol CharSet(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.CharSet"); + } + + public static INamedTypeSymbol DllImportAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.DllImportAttribute"); + } + + public static INamedTypeSymbol MarshalAsAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.MarshalAsAttribute"); + } + + public static INamedTypeSymbol StringBuilder(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Text.StringBuilder"); + } + + public static INamedTypeSymbol UnmanagedType(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedType"); + } + + public static INamedTypeSymbol MarshalByRefObject(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.MarshalByRefObject"); + } + + public static INamedTypeSymbol ExecutionEngineException(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.ExecutionEngineException"); + } + + public static INamedTypeSymbol OutOfMemoryException(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.OutOfMemoryException"); + } + + public static INamedTypeSymbol StackOverflowException(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.StackOverflowException"); + } + + public static INamedTypeSymbol MemberInfo(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Reflection.MemberInfo"); + } + + public static INamedTypeSymbol ParameterInfo(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Reflection.ParameterInfo"); + } + + public static INamedTypeSymbol Thread(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Threading.Thread"); + } + + public static INamedTypeSymbol WebUIControl(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Web.UI.Control"); + } + + public static INamedTypeSymbol WinFormsUIControl(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Windows.Forms.Control"); + } + + public static INamedTypeSymbol IDisposable(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.IDisposable"); + } + + public static INamedTypeSymbol ISerializable(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.Serialization.ISerializable"); + } + + public static INamedTypeSymbol SerializationInfo(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.Serialization.SerializationInfo"); + } + + public static INamedTypeSymbol StreamingContext(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.Serialization.StreamingContext"); + } + + public static INamedTypeSymbol SerializableAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.SerializableAttribute"); + } + + public static INamedTypeSymbol NonSerializedAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.NonSerializedAttribute"); + } + + public static INamedTypeSymbol AttributeUsageAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.AttributeUsageAttribute"); + } + + public static INamedTypeSymbol AssemblyVersionAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Reflection.AssemblyVersionAttribute"); + } + + public static INamedTypeSymbol CLSCompliantAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.CLSCompliantAttribute"); + } + + public static INamedTypeSymbol ConditionalAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Diagnostics.ConditionalAttribute"); + } + + public static INamedTypeSymbol IComparable(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.IComparable"); + } + + public static INamedTypeSymbol ComSourceInterfaceAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.ComSourceInterfacesAttribute"); + } + + public static INamedTypeSymbol EventHandler(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.EventHandler"); + } + + public static INamedTypeSymbol GenericEventHandler(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.EventHandler`1"); + } + + public static INamedTypeSymbol EventArgs(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.EventArgs"); + } + + public static INamedTypeSymbol ComVisibleAttribute(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.ComVisibleAttribute"); + } + + public static INamedTypeSymbol NotImplementedException(Compilation compilation) + { + return compilation.GetTypeByMetadataName("System.NotImplementedException"); + } + } +} diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/packages.config b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/packages.config new file mode 100644 index 0000000000000..7a5f834c82a3f --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/packages.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj new file mode 100644 index 0000000000000..1a9e8344b9670 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj @@ -0,0 +1,105 @@ + + + + + + + + + Debug + AnyCPU + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} + Library + System.Runtime.Analyzers.UnitTests + System.Runtime.Analyzers.UnitTests + true + ..\..\..\..\ + true + + + + {dfa21ca1-7f96-47ee-940c-069858e81727} + CodeAnalysis.Desktop + + + {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C} + CodeAnalysis + + + {B501A547-C911-4A05-AC6E-274A50DFF30E} + CSharpCodeAnalysis + + + {73f3e2c5-d742-452e-b9e1-20732ddbc75d} + BasicCodeAnalysis.Desktop + + + {2523D0E6-DF32-4A3E-8AE0-A19BFFAE2EF6} + BasicCodeAnalysis + + + {76C6F005-C89D-4348-BB4A-391898DBEB52} + TestUtilities + + + {21B239D0-D144-430F-A394-C066D58EE267} + CSharpWorkspace + + + {57CA988D-F010-4BF2-9A2E-07D6DCD2FF2C} + BasicWorkspace + + + {5F8D2414-064A-4B3A-9B42-8E2A04246BE5} + Workspaces + + + {0A0621F2-D1DC-47FF-B643-C6646557505E} + DiagnosticsTestUtilities + + + {7FE6B002-89D8-4298-9B1B-0B5C247DD1FD} + CompilerTestResources + false + + + {d8762a0a-3832-47be-bcf6-8b1060be6b28} + SystemRuntimeAnalyzers + + + {921b412a-5551-4853-82b4-46ad5a05a03e} + CSharpSystemRuntimeAnalyzers + + + + + + + + + + False + ..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + ..\..\..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs new file mode 100644 index 0000000000000..eccb7c9f1df34 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.UnitTests; +using Roslyn.Test.Utilities; +using Xunit; + +namespace System.Runtime.Analyzers.UnitTests +{ + public partial class CA1001FixerTests : CodeFixTestBase + { + protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() + { + return new TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer(); + } + + protected override CodeFixProvider GetBasicCodeFixProvider() + { + return new TypesThatOwnDisposableFieldsShouldBeDisposableFixer(); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer(); + } + + protected override CodeFixProvider GetCSharpCodeFixProvider() + { + return new TypesThatOwnDisposableFieldsShouldBeDisposableFixer(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001CSharpCodeFixNoDispose() + { + VerifyCSharpFix(@" +using System; +using System.IO; + +// This class violates the rule. +public class NoDisposeClass +{ + FileStream newFile; + + public NoDisposeClass() + { + newFile = new FileStream("""", FileMode.Append); + } +} +", +@" +using System; +using System.IO; + +// This class violates the rule. +public class NoDisposeClass +: IDisposable +{ + FileStream newFile; + + public NoDisposeClass() + { + newFile = new FileStream("""", FileMode.Append); + } + + public void Dispose() + { + throw new NotImplementedException(); + } +} +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001BasicCodeFixNoDispose() + { + VerifyBasicFix(@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + + Dim newFile As FileStream + + Sub New() + newFile = New FileStream("""", FileMode.Append) + End Sub + +End Class +", +@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + Implements IDisposable + + Dim newFile As FileStream + + Sub New() + newFile = New FileStream("""", FileMode.Append) + End Sub + + Sub Dispose() Implements IDisposable.Dispose + Throw New NotImplementedException() + End Sub +End Class +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001CSharpCodeFixHasDispose() + { + VerifyCSharpFix(@" +using System; +using System.IO; + +// This class violates the rule. +public class NoDisposeClass +{ + FileStream newFile; + + void Dispose() { +// Some content +} +} +", +@" +using System; +using System.IO; + +// This class violates the rule. +public class NoDisposeClass +: IDisposable +{ + FileStream newFile; + + public void Dispose() { +// Some content +} +} +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001CSharpCodeFixHasWrongDispose() + { + VerifyCSharpFix(@" +using System; +using System.IO; + +// This class violates the rule. +public partial class NoDisposeClass +{ + FileStream newFile; + + void Dispose(int x) { +// Some content +} +} +", +@" +using System; +using System.IO; + +// This class violates the rule. +public partial class NoDisposeClass +: IDisposable +{ + FileStream newFile; + + void Dispose(int x) { +// Some content +} + + public void Dispose() + { + throw new NotImplementedException(); + } +} +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001BasicCodeFixHasDispose() + { + VerifyBasicFix(@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + + Dim newFile As FileStream + + Sub Dispose() + + End Sub +End Class +", +@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + Implements IDisposable + + Dim newFile As FileStream + + Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void CA1001BasicCodeFixHasWrongDispose() + { + VerifyBasicFix(@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + + Dim newFile As FileStream + + Sub Dispose(x As Integer) + End Sub +End Class +", +@" +Imports System +Imports System.IO + +' This class violates the rule. +Public Class NoDisposeMethod + Implements IDisposable + + Dim newFile As FileStream + + Sub Dispose(x As Integer) + End Sub + + Sub Dispose() Implements IDisposable.Dispose + Throw New NotImplementedException() + End Sub +End Class +"); + } + } +} diff --git a/src/Diagnostics/FxCop/Test/Design/CA1001Tests.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs similarity index 96% rename from src/Diagnostics/FxCop/Test/Design/CA1001Tests.cs rename to src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs index 611f9f82aa54b..540ca3d31fc44 100644 --- a/src/Diagnostics/FxCop/Test/Design/CA1001Tests.cs +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs @@ -1,22 +1,22 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FxCopAnalyzers.Design; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.UnitTests; using Xunit; -namespace Microsoft.CodeAnalysis.UnitTests +namespace System.Runtime.Analyzers.UnitTests { public partial class CA1001Tests : DiagnosticAnalyzerTestBase { protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() { - return new CA1001DiagnosticAnalyzer(); + return new TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer(); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() { - return new CA1001DiagnosticAnalyzer(); + return new TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer(); } [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/packages.config b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/packages.config new file mode 100644 index 0000000000000..a972616f20fdd --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/packages.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj new file mode 100644 index 0000000000000..1ccd0322a0a38 --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj @@ -0,0 +1,79 @@ + + + + + + + + + 12.0 + Debug + AnyCPU + {B1A6A74B-E484-48FB-8745-7A30A06DB631} + Library + true + Microsoft.CodeAnalysis.VisualBasic.Analyzers + {14182A97-F7F0-4C62-8B27-98AA8AE2109A};{F184B08F-C81C-45F6-A57F-5ABD9991F28F} + Profile7 + .NETPortable + true + + + + + + + + + {1ee8cad3-55f9-4d91-96b2-084641da9a6c} + CodeAnalysis + + + {2523d0e6-df32-4a3e-8ae0-a19bffae2ef6} + BasicCodeAnalysis + + + {5f8d2414-064a-4b3a-9b42-8e2a04246be5} + Workspaces + + + {d8762a0a-3832-47be-bcf6-8b1060be6b28} + CodeAnalysisDiagnosticAnalyzers + + + + + False + ..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll + + + False + ..\..\..\..\..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/packages.config b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/packages.config new file mode 100644 index 0000000000000..7a5f834c82a3f --- /dev/null +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/packages.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Diagnostics/FxCop/Test/Design/CodeFixes/CA1001FixerTests.cs b/src/Diagnostics/FxCop/Test/Design/CodeFixes/CA1001FixerTests.cs deleted file mode 100644 index 8cc96629caea9..0000000000000 --- a/src/Diagnostics/FxCop/Test/Design/CodeFixes/CA1001FixerTests.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers.Design; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FxCopAnalyzers.Design; -using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design; -using Xunit; - -namespace Microsoft.CodeAnalysis.UnitTests -{ - public partial class CA1001FixerTests : CodeFixTestBase - { - protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() - { - return new CA1001DiagnosticAnalyzer(); - } - - protected override CodeFixProvider GetBasicCodeFixProvider() - { - return new CA1001BasicCodeFixProvider(); - } - - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() - { - return new CA1001DiagnosticAnalyzer(); - } - - protected override CodeFixProvider GetCSharpCodeFixProvider() - { - return new CA1001CSharpCodeFixProvider(); - } - - [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] - public void CA1001CSharpCodeFixNoEqualsOperator() - { - VerifyCSharpFix(@" -using System; -using System.IO; - -// This class violates the rule. -public class NoDisposeClass -{ - FileStream newFile; - - public NoDisposeClass() - { - newFile = new FileStream("""", FileMode.Append); - } -} -", -@" -using System; -using System.IO; - -// This class violates the rule. -public class NoDisposeClass : IDisposable -{ - FileStream newFile; - - public NoDisposeClass() - { - newFile = new FileStream("""", FileMode.Append); - } - - public void Dispose() - { - throw new NotImplementedException(); - } -} -"); - } - - [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] - public void CA1001BasicCodeFixNoEqualsOperator() - { - VerifyBasicFix(@" -Imports System -Imports System.IO - -' This class violates the rule. -Public Class NoDisposeMethod - - Dim newFile As FileStream - - Sub New() - newFile = New FileStream("""", FileMode.Append) - End Sub - -End Class -", -@" -Imports System -Imports System.IO - -' This class violates the rule. -Public Class NoDisposeMethod - Implements IDisposable - - Dim newFile As FileStream - - Sub New() - newFile = New FileStream("""", FileMode.Append) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - Throw New NotImplementedException() - End Sub -End Class -"); - } - } -} diff --git a/src/Diagnostics/FxCop/Test/FxCopRulesDiagnosticAnalyzersTest.csproj b/src/Diagnostics/FxCop/Test/FxCopRulesDiagnosticAnalyzersTest.csproj index 60d2af1789593..5e4f45f6d0694 100644 --- a/src/Diagnostics/FxCop/Test/FxCopRulesDiagnosticAnalyzersTest.csproj +++ b/src/Diagnostics/FxCop/Test/FxCopRulesDiagnosticAnalyzersTest.csproj @@ -80,7 +80,6 @@ - @@ -93,7 +92,6 @@ - @@ -150,4 +148,4 @@ - + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/VisualBasic/BasicFxCopRulesDiagnosticAnalyzers.vbproj b/src/Diagnostics/FxCop/VisualBasic/BasicFxCopRulesDiagnosticAnalyzers.vbproj index 13959b07250cb..90c94cb6f9b52 100644 --- a/src/Diagnostics/FxCop/VisualBasic/BasicFxCopRulesDiagnosticAnalyzers.vbproj +++ b/src/Diagnostics/FxCop/VisualBasic/BasicFxCopRulesDiagnosticAnalyzers.vbproj @@ -99,7 +99,6 @@ - @@ -132,4 +131,4 @@ - + \ No newline at end of file diff --git a/src/Diagnostics/FxCop/VisualBasic/Design/CodeFixes/CA1001BasicCodeFixProvider.vb b/src/Diagnostics/FxCop/VisualBasic/Design/CodeFixes/CA1001BasicCodeFixProvider.vb deleted file mode 100644 index 3a07a99fea72d..0000000000000 --- a/src/Diagnostics/FxCop/VisualBasic/Design/CodeFixes/CA1001BasicCodeFixProvider.vb +++ /dev/null @@ -1,82 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports System.Composition -Imports System.Threading -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.FxCopAnalyzers.Design -Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design - ' - ' CA1001: Types that own disposable fields should be disposable - ' - - Public Class CA1001BasicCodeFixProvider - Inherits CA1001CodeFixProviderBase - - Friend Overrides Function GetUpdatedDocumentAsync(document As Document, model As SemanticModel, root As SyntaxNode, nodeToFix As SyntaxNode, diagnostic As Diagnostic, cancellationToken As CancellationToken) As Task(Of Document) - ' We are going to implement IDisposable interface - ' - ' Public Sub Dispose() Implements IDisposable.Dispose - ' Throw New NotImplementedException() - ' End Sub - - Dim syntaxNode = TryCast(nodeToFix, ClassStatementSyntax) - If syntaxNode Is Nothing Then - Return Task.FromResult(document) - End If - - Dim statement = CreateThrowNotImplementedStatement(model) - If statement Is Nothing Then - Return Task.FromResult(document) - End If - - Dim member = CreateSimpleSubBlockDeclaration(CA1001DiagnosticAnalyzer.Dispose, statement) - Dim parent = DirectCast(syntaxNode.Parent, ClassBlockSyntax) - Dim implementsStatement = SyntaxFactory.ImplementsStatement( - SyntaxFactory.ParseTypeName(CA1001DiagnosticAnalyzer.IDisposable) _ - .WithAdditionalAnnotations(Simplifier.Annotation)) _ - .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) - - Dim newNode = parent.AddMembers(New MethodBlockSyntax() {member}).AddImplements(implementsStatement).WithAdditionalAnnotations(Formatter.Annotation) - Return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(parent, newNode))) - End Function - - Protected Function CreateThrowNotImplementedStatement(model As SemanticModel) As StatementSyntax - Dim exceptionType = model.Compilation.GetTypeByMetadataName(NotImplementedExceptionName) - If exceptionType Is Nothing Then - ' If we can't find the exception, we can't generate anything. - Return Nothing - End If - - Return SyntaxFactory.ThrowStatement( - SyntaxFactory.ObjectCreationExpression( - Nothing, - SyntaxFactory.ParseTypeName(exceptionType.Name), - SyntaxFactory.ArgumentList(), - Nothing)) - End Function - - Protected Function CreateSimpleSubBlockDeclaration(name As String, statement As StatementSyntax) As MethodBlockSyntax - Return SyntaxFactory.SubBlock( - SyntaxFactory.SubStatement( - Nothing, - SyntaxFactory.TokenList(New SyntaxToken() {SyntaxFactory.Token(SyntaxKind.PublicKeyword)}), - SyntaxFactory.Token(SyntaxKind.SubKeyword), - SyntaxFactory.Identifier(name), - Nothing, - SyntaxFactory.ParameterList(), - Nothing, - Nothing, - SyntaxFactory.ImplementsClause( - SyntaxFactory.QualifiedName( - SyntaxFactory.ParseName(CA1001DiagnosticAnalyzer.IDisposable), - SyntaxFactory.IdentifierName(CA1001DiagnosticAnalyzer.Dispose)) _ - .WithAdditionalAnnotations(Simplifier.Annotation))), - SyntaxFactory.SingletonList(statement)) - End Function - End Class -End Namespace diff --git a/src/Roslyn.sln b/src/Roslyn.sln index 1571801a89041..ad6e368e77e70 100644 --- a/src/Roslyn.sln +++ b/src/Roslyn.sln @@ -293,6 +293,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeAnalysisDiagnosticAnaly EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeAnalysisDiagnosticsSetup", "Diagnostics\CodeAnalysis\Setup\CodeAnalysisDiagnosticsSetup.csproj", "{54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "System.Runtime.Analyzers", "System.Runtime.Analyzers", "{F24D89AC-5A93-4F21-A329-DCEFD41EC0FE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\Core\SystemRuntimeAnalyzers.csproj", "{D8762A0A-3832-47BE-BCF6-8B1060BE6B28}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\CSharp\CSharpSystemRuntimeAnalyzers.csproj", "{921B412A-5551-4853-82B4-46AD5A05A03E}" +EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\VisualBasic\BasicSystemRuntimeAnalyzers.vbproj", "{B1A6A74B-E484-48FB-8745-7A30A06DB631}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzersTest", "Diagnostics\FxCop\System.Runtime.Analyzers\Test\SystemRuntimeAnalyzersTest.csproj", "{0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{edc68a0e-c68d-4a74-91b7-bf38ec909888}*SharedItemsImports = 4 @@ -802,6 +812,22 @@ Global {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {921B412A-5551-4853-82B4-46AD5A05A03E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {921B412A-5551-4853-82B4-46AD5A05A03E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {921B412A-5551-4853-82B4-46AD5A05A03E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {921B412A-5551-4853-82B4-46AD5A05A03E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -937,5 +963,10 @@ Global {B1A6A74B-E484-48FB-8745-7A30A06DB631} = {2344BE45-7F6B-4A4E-9418-567FA2D9CA8C} {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} = {2344BE45-7F6B-4A4E-9418-567FA2D9CA8C} {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF} = {2344BE45-7F6B-4A4E-9418-567FA2D9CA8C} + {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} = {24E8CBFA-38D2-486F-B772-C10AB2DC7F01} + {D8762A0A-3832-47BE-BCF6-8B1060BE6B28} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {921B412A-5551-4853-82B4-46AD5A05A03E} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {B1A6A74B-E484-48FB-8745-7A30A06DB631} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} EndGlobalSection EndGlobal diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs index d84ea05d3c586..c24f3bca84032 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditorExtensions.cs @@ -94,12 +94,12 @@ public static void InsertMembers(this SyntaxEditor editor, SyntaxNode declaratio public static void AddInterfaceType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode interfaceType) { - editor.ReplaceNode(declaration, (d, g) => g.AddInterfaceType(declaration, interfaceType)); + editor.ReplaceNode(declaration, (d, g) => g.AddInterfaceType(d, interfaceType)); } public static void AddBaseType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode baseType) { - editor.ReplaceNode(declaration, (d, g) => g.AddBaseType(declaration, baseType)); + editor.ReplaceNode(declaration, (d, g) => g.AddBaseType(d, baseType)); } } } From 906419361c2121211711c4bbda38a5226138c9fd Mon Sep 17 00:00:00 2001 From: Srivatsn Narayanan Date: Mon, 9 Feb 2015 18:03:24 -0800 Subject: [PATCH 03/16] The guids for the new analyzer projects were copied from the codeanalysisanalyzers but since the codeanalysisanalyzers werent part of the solution VS didnt know. Once I merged the change that added them to the solution, VS got confused. Fixing the guids. Also adding newlines to the end. --- .../CSharpSystemRuntimeAnalyzers.csproj | 2 +- .../Core/SystemRuntimeAnalyzers.csproj | 4 +- .../Test/SystemRuntimeAnalyzersTest.csproj | 10 ++-- .../BasicSystemRuntimeAnalyzers.vbproj | 4 +- src/Roslyn.sln | 48 +++++++++---------- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj index 2822e9322a7c5..ae03682c14ba7 100644 --- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj @@ -9,7 +9,7 @@ 12.0 Debug AnyCPU - {921B412A-5551-4853-82B4-46AD5A05A03E} + {A36451EC-1127-40CE-B841-47F393D24624} Library true System.Runtime.CSharp.Analyzers diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj index a0fefdfb6527e..18d0809a953fe 100644 --- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj @@ -9,7 +9,7 @@ 12.0 Debug AnyCPU - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28} + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8} Library true System.Runtime.Analyzers @@ -78,4 +78,4 @@ - \ No newline at end of file + diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj index 1a9e8344b9670..8fcaccde7c94f 100644 --- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj @@ -8,7 +8,7 @@ Debug AnyCPU - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863} Library System.Runtime.Analyzers.UnitTests System.Runtime.Analyzers.UnitTests @@ -63,13 +63,17 @@ false - {d8762a0a-3832-47be-bcf6-8b1060be6b28} + {baa0fee4-93c8-46f0-bb36-53a6053776c8} SystemRuntimeAnalyzers - {921b412a-5551-4853-82b4-46ad5a05a03e} + {a36451ec-1127-40ce-b841-47f393d24624} CSharpSystemRuntimeAnalyzers + + {d835c05e-9d83-40b2-9d25-19eb652f10d7} + BasicSystemRuntimeAnalyzers + diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj index 1ccd0322a0a38..ede2e04d6cee0 100644 --- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj +++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj @@ -9,7 +9,7 @@ 12.0 Debug AnyCPU - {B1A6A74B-E484-48FB-8745-7A30A06DB631} + {D835C05E-9D83-40B2-9D25-19EB652F10D7} Library true Microsoft.CodeAnalysis.VisualBasic.Analyzers @@ -76,4 +76,4 @@ - \ No newline at end of file + diff --git a/src/Roslyn.sln b/src/Roslyn.sln index ad6e368e77e70..5b631517ec2e2 100644 --- a/src/Roslyn.sln +++ b/src/Roslyn.sln @@ -295,13 +295,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeAnalysisDiagnosticsSetu EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "System.Runtime.Analyzers", "System.Runtime.Analyzers", "{F24D89AC-5A93-4F21-A329-DCEFD41EC0FE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\Core\SystemRuntimeAnalyzers.csproj", "{D8762A0A-3832-47BE-BCF6-8B1060BE6B28}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\Core\SystemRuntimeAnalyzers.csproj", "{BAA0FEE4-93C8-46F0-BB36-53A6053776C8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\CSharp\CSharpSystemRuntimeAnalyzers.csproj", "{921B412A-5551-4853-82B4-46AD5A05A03E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\CSharp\CSharpSystemRuntimeAnalyzers.csproj", "{A36451EC-1127-40CE-B841-47F393D24624}" EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\VisualBasic\BasicSystemRuntimeAnalyzers.vbproj", "{B1A6A74B-E484-48FB-8745-7A30A06DB631}" +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicSystemRuntimeAnalyzers", "Diagnostics\FxCop\System.Runtime.Analyzers\VisualBasic\BasicSystemRuntimeAnalyzers.vbproj", "{D835C05E-9D83-40B2-9D25-19EB652F10D7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzersTest", "Diagnostics\FxCop\System.Runtime.Analyzers\Test\SystemRuntimeAnalyzersTest.csproj", "{0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemRuntimeAnalyzersTest", "Diagnostics\FxCop\System.Runtime.Analyzers\Test\SystemRuntimeAnalyzersTest.csproj", "{0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -812,22 +812,22 @@ Global {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {921B412A-5551-4853-82B4-46AD5A05A03E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {921B412A-5551-4853-82B4-46AD5A05A03E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {921B412A-5551-4853-82B4-46AD5A05A03E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {921B412A-5551-4853-82B4-46AD5A05A03E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B1A6A74B-E484-48FB-8745-7A30A06DB631}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A36451EC-1127-40CE-B841-47F393D24624}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A36451EC-1127-40CE-B841-47F393D24624}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A36451EC-1127-40CE-B841-47F393D24624}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A36451EC-1127-40CE-B841-47F393D24624}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D835C05E-9D83-40B2-9D25-19EB652F10D7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D835C05E-9D83-40B2-9D25-19EB652F10D7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D835C05E-9D83-40B2-9D25-19EB652F10D7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D835C05E-9D83-40B2-9D25-19EB652F10D7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -964,9 +964,9 @@ Global {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} = {2344BE45-7F6B-4A4E-9418-567FA2D9CA8C} {54F6AE18-B0CD-4799-9DF0-9B1AAD6A78AF} = {2344BE45-7F6B-4A4E-9418-567FA2D9CA8C} {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} = {24E8CBFA-38D2-486F-B772-C10AB2DC7F01} - {D8762A0A-3832-47BE-BCF6-8B1060BE6B28} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} - {921B412A-5551-4853-82B4-46AD5A05A03E} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} - {B1A6A74B-E484-48FB-8745-7A30A06DB631} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} - {0C2925AD-CD97-46FA-A686-E2C1AD19DAD8} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {BAA0FEE4-93C8-46F0-BB36-53A6053776C8} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {A36451EC-1127-40CE-B841-47F393D24624} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {D835C05E-9D83-40B2-9D25-19EB652F10D7} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} + {0FAE8CB3-4D2F-4A11-B1E6-F47EFF0FB863} = {F24D89AC-5A93-4F21-A329-DCEFD41EC0FE} EndGlobalSection EndGlobal From 04434258818f6c3c8ddcf122191f9e54c680a074 Mon Sep 17 00:00:00 2001 From: Paul Harrington Date: Tue, 10 Feb 2015 11:31:15 -0800 Subject: [PATCH 04/16] Fixes #309 We have two targets that each modify a compiled binary in-place: ApplyOptimizations and FakeSign. They each write out their own sentinel file to help keep incremental build healthy and quick. However, this causes problems when you need to run both (e.g. on a developer box compiling Release binaries). This change moves the sentinel file into a third task that depends on the other two. I hope it's obvious how to extend this if more "post compile binary modification" targets are added later. --- build/VSL.Imports.Closed.targets | 89 +++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/build/VSL.Imports.Closed.targets b/build/VSL.Imports.Closed.targets index 1376cc60e1d03..f5567ea18d05b 100644 --- a/build/VSL.Imports.Closed.targets +++ b/build/VSL.Imports.Closed.targets @@ -1,4 +1,35 @@ + + + + + $(IntermediateOutputPath)$(TargetFileName).pcbm + $(CompileDependsOn);PostCompileBinaryModification + $(CleanDependsOn);CleanPostCompileBinaryModification + + + + + + + + + + + + - + ==================================================================================== --> - + + true + true + - - + + + + + + + - $(CompileDependsOn);ApplyOptimizations - $(CleanDependsOn);CleanApplyOptimizations;CleanPhoneCopy + $(CleanDependsOn);CleanPhoneCopy - - true - true - $(CompileDependsOn);FakeSignAssembly - $(IntermediateOutputPath)$(TargetFileName).fakesign - - - - - - - - - $(CreateVsixContainerDependsOn);SignVsixInputs $(PrepareForRunDependsOn);SignVsix true - + From b0b6e709318d8e626660b723a3040f4aa7401a54 Mon Sep 17 00:00:00 2001 From: Brett Forsgren Date: Tue, 10 Feb 2015 12:41:36 -0800 Subject: [PATCH 05/16] properly handle VB Global namespace in DeclaredSymbolInfo --- .../VisualBasicTest/NavigateTo/NavigateToTests.vb | 10 ++++++++++ .../LanguageServices/VisualBasicSyntaxFactsService.vb | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb index 346cd2bf81b4d..a9f4090df4e04 100644 --- a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb +++ b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb @@ -541,6 +541,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.NavigateTo End Using End Sub + + + Public Sub FindClassInGlobalNamespace() + Using worker = SetupWorkspace("Namespace Global", "Public Class C(Of T)", "End Class", "End Namespace") + SetupVerifableGlyph(StandardGlyphGroup.GlyphGroupClass, StandardGlyphItem.GlyphItemPublic) + Dim item = _aggregator.GetItems("C").Single + VerifyNavigateToResultItem(item, "C", MatchKind.Exact, NavigateToItemKind.Class, displayName:="C(Of T)") + End Using + End Sub + Public Sub StartStopSanity() ' Verify that mutliple calls to start/stop don't blow up diff --git a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb index ca58e72f1268f..db3d379a3e793 100644 --- a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb +++ b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb @@ -880,8 +880,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic name = moduleDecl.ModuleStatement.Identifier.ValueText typeParameterList = moduleDecl.ModuleStatement.TypeParameterList Case SyntaxKind.NamespaceBlock - Return GetNodeName(CType(node, NamespaceBlockSyntax).NamespaceStatement.Name, includeTypeParameters:=False) - typeParameterList = Nothing + Dim nameSyntax = CType(node, NamespaceBlockSyntax).NamespaceStatement.Name + If nameSyntax.Kind() = SyntaxKind.GlobalName Then + Return Nothing + Else + Return GetNodeName(nameSyntax, includeTypeParameters:=False) + End If Case SyntaxKind.QualifiedName Dim qualified = CType(node, QualifiedNameSyntax) If qualified.Left.Kind() = SyntaxKind.GlobalName Then From e720a2d7e247a5ed75f17e966f81ce07cdd24e50 Mon Sep 17 00:00:00 2001 From: Paul Harrington Date: Tue, 10 Feb 2015 15:16:31 -0800 Subject: [PATCH 06/16] Incorporate review feedback Review feedback from Jason --- build/VSL.Imports.Closed.targets | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build/VSL.Imports.Closed.targets b/build/VSL.Imports.Closed.targets index f5567ea18d05b..a853bdca6e337 100644 --- a/build/VSL.Imports.Closed.targets +++ b/build/VSL.Imports.Closed.targets @@ -13,21 +13,20 @@ $(IntermediateOutputPath)$(TargetFileName).pcbm - $(CompileDependsOn);PostCompileBinaryModification - $(CleanDependsOn);CleanPostCompileBinaryModification - - - + + + - - Shared\MetadataReaderPdbExtensions.cs - Shared\SymUnmanagedReaderExtensions.cs diff --git a/src/Test/PdbUtilities/Metadata/MetadataReaderPdbExtensions.cs b/src/Test/PdbUtilities/Metadata/MetadataReaderPdbExtensions.cs index 5eed315af4f8c..7bf8727f158bb 100644 --- a/src/Test/PdbUtilities/Metadata/MetadataReaderPdbExtensions.cs +++ b/src/Test/PdbUtilities/Metadata/MetadataReaderPdbExtensions.cs @@ -4,9 +4,11 @@ using System.Diagnostics; using System.Reflection.Metadata.Ecma335; +// TODO: to be moved to System.Reflection.Metadata. + namespace System.Reflection.Metadata { - public enum ImportScopeKind + internal enum ImportScopeKind { ImportNamespace = 1, ImportAssemblyNamespace = 2, @@ -19,7 +21,7 @@ public enum ImportScopeKind AliasType = 9 } - public struct ImportDefinition + internal struct ImportDefinition { private readonly ImportScopeKind _kind; private readonly BlobHandle _alias; @@ -28,8 +30,8 @@ public struct ImportDefinition internal ImportDefinition( ImportScopeKind kind, - BlobHandle alias = default(BlobHandle), - AssemblyReferenceHandle assembly = default(AssemblyReferenceHandle), + BlobHandle alias = default(BlobHandle), + AssemblyReferenceHandle assembly = default(AssemblyReferenceHandle), Handle typeOrNamespace = default(Handle)) { Debug.Assert( From 6cdf94b7ee973e2820caf08cf76892e4414271df Mon Sep 17 00:00:00 2001 From: Kevin Halverson Date: Tue, 10 Feb 2015 01:01:19 -0800 Subject: [PATCH 08/16] Substitute generic type arguments for generic frames in the Call Stack Window. This change also ensures that we get non-fatal Watson reports when we're in the continuation of a call to get generic type arguments or argument values from the debugee process. --- .../CSharpExpressionCompiler.csproj | 3 +- .../ExpressionCompiler/CSharpFrameDecoder.cs | 5 +- .../CSharpInstructionDecoder.cs | 42 ++- .../CSharpLanguageInstructionDecoder.cs | 5 +- .../ExpressionCompiler/CompilationContext.cs | 10 +- .../ExpressionCompiler/SymbolExtensions.cs | 18 ++ .../InstructionDecoderTests.cs | 256 ++++++++++++++++-- .../ExpressionEvaluatorFatalError.cs | 20 +- .../Source/ExpressionCompiler/FrameDecoder.cs | 211 ++++++++++----- .../ExpressionCompiler/InstructionDecoder.cs | 63 +++-- .../LanguageInstructionDecoder.cs | 15 +- .../ExpressionCompiler/CompilationContext.vb | 11 +- .../ExpressionCompiler/SymbolExtensions.vb | 13 +- .../VisualBasicFrameDecoder.vb | 8 +- .../VisualBasicInstructionDecoder.vb | 45 ++- .../VisualBasicLanguageInstructionDecoder.vb | 7 +- .../ExpressionCompilerTests.vb | 4 +- .../InstructionDecoderTests.vb | 209 ++++++++++++-- 18 files changed, 750 insertions(+), 195 deletions(-) create mode 100644 src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SymbolExtensions.cs diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.csproj b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.csproj index 44f46341125a1..bb88c53d90628 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.csproj +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpExpressionCompiler.csproj @@ -79,6 +79,7 @@ + @@ -113,4 +114,4 @@ - + \ No newline at end of file diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpFrameDecoder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpFrameDecoder.cs index 11fa7caa89349..63ffdb55f5eb3 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpFrameDecoder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpFrameDecoder.cs @@ -1,12 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics; using Microsoft.CodeAnalysis.ExpressionEvaluator; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { [DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException] - internal sealed class CSharpFrameDecoder : FrameDecoder + internal sealed class CSharpFrameDecoder : FrameDecoder { public CSharpFrameDecoder() : base(CSharpInstructionDecoder.Instance) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpInstructionDecoder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpInstructionDecoder.cs index 0c155cc3954c9..772ecc5898a15 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpInstructionDecoder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpInstructionDecoder.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Diagnostics; +using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -9,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { - internal sealed class CSharpInstructionDecoder : InstructionDecoder + internal sealed class CSharpInstructionDecoder : InstructionDecoder { // This string was not localized in the old EE. We'll keep it that way // so as not to break consumers who may have been parsing frame names... @@ -28,7 +30,7 @@ private CSharpInstructionDecoder() AddMemberOptions(SymbolDisplayMemberOptions.IncludeParameters). WithParameterOptions(SymbolDisplayParameterOptions.IncludeType); - internal override void AppendFullName(StringBuilder builder, PEMethodSymbol method) + internal override void AppendFullName(StringBuilder builder, MethodSymbol method) { var displayFormat = ((method.MethodKind == MethodKind.PropertyGet) || (method.MethodKind == MethodKind.PropertySet)) ? @@ -86,7 +88,28 @@ internal override void AppendFullName(StringBuilder builder, PEMethodSymbol meth } } - internal override PEMethodSymbol GetMethod(DkmClrInstructionAddress instructionAddress) + internal override MethodSymbol ConstructMethod(MethodSymbol method, ImmutableArray typeParameters, ImmutableArray typeArguments) + { + var methodArity = method.Arity; + var methodArgumentStartIndex = typeParameters.Length - methodArity; + var typeMap = new TypeMap( + ImmutableArray.Create(typeParameters, 0, methodArgumentStartIndex), + ImmutableArray.Create(typeArguments, 0, methodArgumentStartIndex)); + var substitutedType = typeMap.SubstituteNamedType(method.ContainingType); + method = method.AsMember(substitutedType); + if (methodArity > 0) + { + method = method.Construct(ImmutableArray.Create(typeArguments, methodArgumentStartIndex, methodArity)); + } + return method; + } + + internal override ImmutableArray GetAllTypeParameters(MethodSymbol method) + { + return method.GetAllTypeParameters(); + } + + internal override CSharpCompilation GetCompilation(DkmClrInstructionAddress instructionAddress) { var moduleInstance = instructionAddress.ModuleInstance; var appDomain = moduleInstance.AppDomain; @@ -105,7 +128,18 @@ internal override PEMethodSymbol GetMethod(DkmClrInstructionAddress instructionA compilation = dataItem.Compilation; } - return compilation.GetSourceMethod(moduleInstance.Mvid, instructionAddress.MethodId.Token); + return compilation; + } + + internal override MethodSymbol GetMethod(CSharpCompilation compilation, DkmClrInstructionAddress instructionAddress) + { + return compilation.GetSourceMethod(instructionAddress.ModuleInstance.Mvid, instructionAddress.MethodId.Token); + } + + internal override TypeNameDecoder GetTypeNameDecoder(CSharpCompilation compilation, MethodSymbol method) + { + Debug.Assert(method is PEMethodSymbol); + return new EETypeNameDecoder(compilation, (PEModuleSymbol)method.ContainingModule); } } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpLanguageInstructionDecoder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpLanguageInstructionDecoder.cs index f068b0364d1cf..5787513d95ebc 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpLanguageInstructionDecoder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CSharpLanguageInstructionDecoder.cs @@ -2,16 +2,17 @@ using System; using Microsoft.CodeAnalysis.ExpressionEvaluator; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { [DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException] - internal sealed class CSharpLanguageInstructionDecoder : LanguageInstructionDecoder + internal sealed class CSharpLanguageInstructionDecoder : LanguageInstructionDecoder { public CSharpLanguageInstructionDecoder() : base(CSharpInstructionDecoder.Instance) { } } -} +} \ No newline at end of file diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 4fd8220a4b1c4..26345a6da8a8a 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -245,14 +245,6 @@ internal CommonPEModuleBuilder CompileAssignment( return module; } - private static ImmutableArray GetAllTypeParameters(MethodSymbol method) - { - var builder = ArrayBuilder.GetInstance(); - method.ContainingType.GetAllTypeParameters(builder); - builder.AddRange(method.TypeParameters); - return builder.ToImmutableAndFree(); - } - private static string GetNextMethodName(ArrayBuilder builder) { return string.Format("<>m{0}", builder.Count); @@ -270,7 +262,7 @@ internal CommonPEModuleBuilder CompileGetLocals( DiagnosticBag diagnostics) { var objectType = this.Compilation.GetSpecialType(SpecialType.System_Object); - var allTypeParameters = GetAllTypeParameters(_currentFrame); + var allTypeParameters = _currentFrame.GetAllTypeParameters(); var additionalTypes = ArrayBuilder.GetInstance(); EENamedTypeSymbol typeVariablesType = null; diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SymbolExtensions.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SymbolExtensions.cs new file mode 100644 index 0000000000000..d498e56290b11 --- /dev/null +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SymbolExtensions.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CSharp.Symbols; + +namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator +{ + internal static class SymbolExtensions + { + internal static ImmutableArray GetAllTypeParameters(this MethodSymbol method) + { + var builder = ArrayBuilder.GetInstance(); + method.ContainingType.GetAllTypeParameters(builder); + builder.AddRange(method.TypeParameters); + return builder.ToImmutableAndFree(); + } + } +} diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs index 7e33eba502981..26f3a00c48a8b 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs @@ -1,7 +1,10 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Diagnostics; +using System.Linq; using System.Reflection.Metadata.Ecma335; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -14,8 +17,90 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { public class InstructionDecoderTests : ExpressionCompilerTestBase { + [Fact] + void GetNameGenerics() + { + var source = @" +using System; +class Class1 +{ + void M1(Action a) + { + } + void M2(Action a) + { + } + void M3(Action a) + { + } +}"; + + Assert.Equal( + "Class1.M1(System.Action a)", + GetName(source, "Class1.M1", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)); + + Assert.Equal( + "Class1.M2(System.Action a)", + GetName(source, "Class1.M2", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)); + + Assert.Equal( + "Class1.M3(System.Action a)", + GetName(source, "Class1.M3", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)); + + Assert.Equal( + "Class1.M1(System.Action a)", + GetName(source, "Class1.M1", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, new[] { typeof(string), typeof(decimal) })); + + Assert.Equal( + "Class1.M2(System.Action a)", + GetName(source, "Class1.M2", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, new[] { typeof(string), typeof(decimal) })); + + Assert.Equal( + "Class1.M3(System.Action a)", + GetName(source, "Class1.M3", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, new[] { typeof(string), typeof(decimal) })); + } + + [Fact] + void GetNameNullTypeArguments() + { + var source = @" +using System; +class Class1 +{ + void M(Action a) + { + } +}"; + + Assert.Equal( + "Class1.M(System.Action a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, typeArguments: new Type[] { null, null })); + + Assert.Equal( + "Class1.M(System.Action a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, typeArguments: new[] { typeof(string), null })); + + Assert.Equal( + "Class1.M(System.Action a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, typeArguments: new[] { null, typeof(decimal) })); + } + + [Fact] + void GetNameGenericArgumentTypeNotInReferences() + { + var source = @" +class Class1 +{ +}"; + + var serializedTypeArgumentName = "Class1, " + nameof(InstructionDecoderTests) + ", Culture=neutral, PublicKeyToken=null"; + Assert.Equal( + "System.Collections.Generic.Comparer.Create(System.Comparison comparison)", + GetName(source, "System.Collections.Generic.Comparer.Create", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, typeArguments: new[] { serializedTypeArgumentName })); + } + [Fact, WorkItem(1107977)] - public void GetNameGenericAsync() + void GetNameGenericAsync() { var source = @" using System.Threading.Tasks; @@ -29,12 +114,12 @@ static async Task M(T x) }"; Assert.Equal( - "C.M(T x)", - GetName(source, "C.d__0.MoveNext", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)); + "C.M(System.Exception x)", + GetName(source, "C.d__0.MoveNext", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, new[] { typeof(Exception) })); } [Fact] - public void GetNameLambda() + void GetNameLambda() { var source = @" using System; @@ -52,7 +137,7 @@ void M() } [Fact] - public void GetNameGenericLambda() + void GetNameGenericLambda() { var source = @" using System; @@ -65,12 +150,12 @@ void M() where U : T }"; Assert.Equal( - "C.M.AnonymousMethod__0_0(U u)", - GetName(source, "C.<>c__0.b__0_0", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)); + "C.M.AnonymousMethod__0_0(System.ArgumentException u)", + GetName(source, "C.<>c__0.b__0_0", DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types, new[] { typeof(Exception), typeof(ArgumentException) })); } [Fact] - public void GetNameProperties() + void GetNameProperties() { var source = @" class C @@ -101,7 +186,7 @@ int this[object x] } [Fact] - public void GetNameExplicitInterfaceImplementation() + void GetNameExplicitInterfaceImplementation() { var source = @" using System; @@ -116,7 +201,7 @@ void IDisposable.Dispose() { } } [Fact] - public void GetNameExtensionMethod() + void GetNameExtensionMethod() { var source = @" static class Extensions @@ -130,7 +215,7 @@ static void M(this string @this) { } } [Fact] - public void GetNameArgumentFlagsNone() + void GetNameArgumentFlagsNone() { var source = @" static class C @@ -148,41 +233,154 @@ static void M2(int x, int y) { } GetName(source, "C.M2", DkmVariableInfoFlags.None)); } - private string GetName(string source, string methodName, DkmVariableInfoFlags argumentFlags, params string[] argumentValues) + [Fact] + void GetReturnTypeNamePrimitive() + { + var source = @" +static class C +{ + static uint M1() { return 42; } +}"; + + Assert.Equal("uint", GetReturnTypeName(source, "C.M1")); + } + + [Fact] + void GetReturnTypeNameNested() + { + var source = @" +static class C +{ + static N.D.E M1() { return default(N.D.E); } +} +namespace N +{ + class D + { + internal struct E + { + } + } +}"; + + Assert.Equal("N.D.E", GetReturnTypeName(source, "C.M1")); + } + + [Fact] + void GetReturnTypeNameGenericOfPrimitive() + { + var source = @" +using System; +class C +{ + Action M1() { return null; } +}"; + + Assert.Equal("System.Action", GetReturnTypeName(source, "C.M1")); + } + + [Fact] + void GetReturnTypeNameGenericOfNested() + { + var source = @" +using System; +class C +{ + Action M1() { return null; } + class D + { + } +}"; + + Assert.Equal("System.Action", GetReturnTypeName(source, "C.M1")); + } + + [Fact] + void GetReturnTypeNameGenericOfGeneric() + { + var source = @" +using System; +class C +{ + Action> M1() { return null; } +}"; + + Assert.Equal("System.Action>", GetReturnTypeName(source, "C.M1", new[] { typeof(object) })); + } + + private string GetName(string source, string methodName, DkmVariableInfoFlags argumentFlags, Type[] typeArguments = null, string[] argumentValues = null) + { + var serializedTypeArgumentNames = typeArguments?.Select(t => t?.AssemblyQualifiedName).ToArray(); + return GetName(source, methodName, argumentFlags, serializedTypeArgumentNames, argumentValues); + } + + private string GetName(string source, string methodName, DkmVariableInfoFlags argumentFlags, string[] typeArguments, string[] argumentValues = null) { Debug.Assert((argumentFlags & (DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)) == argumentFlags, "Unexpected argumentFlags", "argumentFlags = {0}", argumentFlags); - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); - var runtime = CreateRuntimeInstance(compilation); - var moduleInstances = runtime.Modules; - var blocks = moduleInstances.SelectAsArray(m => m.MetadataBlock); - compilation = blocks.ToCompilation(); - var frame = (PEMethodSymbol)GetMethodOrTypeBySignature(compilation, methodName); + var instructionDecoder = CSharpInstructionDecoder.Instance; + var method = GetConstructedMethod(source, methodName, typeArguments, instructionDecoder); - // Once we have the method token, we want to look up the method (again) - // using the same helper as the product code. This helper will also map - // async/iterator "MoveNext" methods to the original source method. - var method = compilation.GetSourceMethod( - ((PEModuleSymbol)frame.ContainingModule).Module.GetModuleVersionIdOrThrow(), - MetadataTokens.GetToken(frame.Handle)); var includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types); var includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names); ArrayBuilder builder = null; - if (argumentValues.Length > 0) + if (argumentValues != null) { + Assert.InRange(argumentValues.Length, 1, int.MaxValue); builder = ArrayBuilder.GetInstance(); builder.AddRange(argumentValues); } - var frameDecoder = CSharpInstructionDecoder.Instance; - var frameName = frameDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder); + var name = instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder); if (builder != null) { builder.Free(); } - return frameName; + return name; + } + + private string GetReturnTypeName(string source, string methodName, Type[] typeArguments = null) + { + var instructionDecoder = CSharpInstructionDecoder.Instance; + var serializedTypeArgumentNames = typeArguments?.Select(t => (t != null) ? t.AssemblyQualifiedName : null).ToArray(); + var method = GetConstructedMethod(source, methodName, serializedTypeArgumentNames, instructionDecoder); + + return instructionDecoder.GetReturnTypeName(method); + } + + private MethodSymbol GetConstructedMethod(string source, string methodName, string[] serializedTypeArgumentNames, CSharpInstructionDecoder instructionDecoder) + { + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: nameof(InstructionDecoderTests)); + var runtime = CreateRuntimeInstance(compilation); + var moduleInstances = runtime.Modules; + var blocks = moduleInstances.SelectAsArray(m => m.MetadataBlock); + compilation = blocks.ToCompilation(); + var frame = (PEMethodSymbol)GetMethodOrTypeBySignature(compilation, methodName); + + // Once we have the method token, we want to look up the method (again) + // using the same helper as the product code. This helper will also map + // async/iterator "MoveNext" methods to the original source method. + MethodSymbol method = compilation.GetSourceMethod( + ((PEModuleSymbol)frame.ContainingModule).Module.GetModuleVersionIdOrThrow(), + MetadataTokens.GetToken(frame.Handle)); + if (serializedTypeArgumentNames != null) + { + Assert.NotEmpty(serializedTypeArgumentNames); + var typeParameters = instructionDecoder.GetAllTypeParameters(method); + Assert.NotEmpty(typeParameters); + var typeNameDecoder = new EETypeNameDecoder(compilation, (PEModuleSymbol)method.ContainingModule); + // Use the same helper method as the FrameDecoder to get the TypeSymbols for the + // generic type arguments (rather than using EETypeNameDecoder directly). + var typeArguments = instructionDecoder.GetTypeSymbols(compilation, method, serializedTypeArgumentNames); + if (!typeArguments.IsEmpty) + { + method = instructionDecoder.ConstructMethod(method, typeParameters, typeArguments); + } + } + + return method; } } -} +} \ No newline at end of file diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs index 30601e88a1587..77d27323a45b7 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/ExpressionEvaluatorFatalError.cs @@ -4,11 +4,12 @@ using System.Diagnostics; using System.Reflection; using Microsoft.VisualStudio.Debugger; +using Roslyn.Utilities; #if !EXPRESSIONCOMPILER using Microsoft.CodeAnalysis.ErrorReporting; - #endif + namespace Microsoft.CodeAnalysis.ExpressionEvaluator { internal static class ExpressionEvaluatorFatalError @@ -80,5 +81,20 @@ internal static bool CrashIfFailFastEnabled(Exception exception) return FatalError.Report(exception); } + + internal delegate bool NonFatalExceptionHandler(Exception exception, string implementationName); + + internal static bool ReportNonFatalException(Exception exception, NonFatalExceptionHandler handler) + { + if (CrashIfFailFastEnabled(exception)) + { + throw ExceptionUtilities.Unreachable; + } + + // Ignore the return value, because we always want to continue after reporting the Exception. + handler(exception, nameof(ExpressionEvaluatorFatalError)); + + return true; + } } -} +} \ No newline at end of file diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/FrameDecoder.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/FrameDecoder.cs index 0ab210df78e5f..f3e1b24a68b84 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/FrameDecoder.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/FrameDecoder.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using System.Diagnostics; using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.CallStack; @@ -19,86 +20,35 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator /// always used C# syntax (but with language-specific "special names"). Since these names are exposed through public /// APIs, we will remain consistent with the old behavior (for consumers who may be parsing the frame names). /// - internal abstract class FrameDecoder : IDkmLanguageFrameDecoder + internal abstract class FrameDecoder : IDkmLanguageFrameDecoder + where TCompilation : Compilation + where TMethodSymbol : class, IMethodSymbol + where TModuleSymbol : class, IModuleSymbol + where TTypeSymbol : class, ITypeSymbol + where TTypeParameterSymbol : class, ITypeParameterSymbol { - private readonly InstructionDecoder _instructionDecoder; + private readonly InstructionDecoder _instructionDecoder; - internal FrameDecoder(InstructionDecoder instructionDecoder) + internal FrameDecoder(InstructionDecoder instructionDecoder) { _instructionDecoder = instructionDecoder; } - void IDkmLanguageFrameDecoder.GetFrameName(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmStackWalkFrame frame, DkmVariableInfoFlags argumentFlags, DkmCompletionRoutine completionRoutine) + void IDkmLanguageFrameDecoder.GetFrameName( + DkmInspectionContext inspectionContext, + DkmWorkList workList, + DkmStackWalkFrame frame, + DkmVariableInfoFlags argumentFlags, + DkmCompletionRoutine completionRoutine) { try { Debug.Assert((argumentFlags & (DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types | DkmVariableInfoFlags.Values)) == argumentFlags, "Unexpected argumentFlags", "argumentFlags = {0}", argumentFlags); - var instructionAddress = (DkmClrInstructionAddress)frame.InstructionAddress; - var includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types); - var includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names); - - if (argumentFlags.Includes(DkmVariableInfoFlags.Values)) - { - // No need to compute the Expandable bit on - // argument values since that can be expensive. - inspectionContext = DkmInspectionContext.Create( - inspectionContext.InspectionSession, - inspectionContext.RuntimeInstance, - inspectionContext.Thread, - inspectionContext.Timeout, - inspectionContext.EvaluationFlags | DkmEvaluationFlags.NoExpansion, - inspectionContext.FuncEvalFlags, - inspectionContext.Radix, - inspectionContext.Language, - inspectionContext.ReturnValue, - inspectionContext.AdditionalVisualizationData, - inspectionContext.AdditionalVisualizationDataPriority, - inspectionContext.ReturnValues); - - // GetFrameArguments returns an array of formatted argument values. We'll pass - // ourselves (GetFrameName) as the continuation of the GetFrameArguments call. - inspectionContext.GetFrameArguments( - workList, - frame, - result => - { - try - { - var builder = ArrayBuilder.GetInstance(); - foreach (var argument in result.Arguments) - { - var evaluatedArgument = argument as DkmSuccessEvaluationResult; - // Not expecting Expandable bit, at least not from this EE. - Debug.Assert((evaluatedArgument == null) || (evaluatedArgument.Flags & DkmEvaluationResultFlags.Expandable) == 0); - builder.Add((evaluatedArgument != null) ? evaluatedArgument.Value : null); - } - - var frameName = _instructionDecoder.GetName(instructionAddress, includeParameterTypes, includeParameterNames, builder); - builder.Free(); - completionRoutine(new DkmGetFrameNameAsyncResult(frameName)); - } - // TODO: Consider calling DkmComponentManager.ReportCurrentNonFatalException() to - // trigger a non-fatal Watson when this occurs. - catch (Exception e) when (!ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) - { - completionRoutine(DkmGetFrameNameAsyncResult.CreateErrorResult(e)); - } - finally - { - foreach (var argument in result.Arguments) - { - argument.Close(); - } - } - }); - } - else - { - var frameName = _instructionDecoder.GetName(instructionAddress, includeParameterTypes, includeParameterNames, null); - completionRoutine(new DkmGetFrameNameAsyncResult(frameName)); - } + GetNameWithGenericTypeArguments(inspectionContext, workList, frame, + onSuccess: method => GetFrameName(inspectionContext, workList, frame, argumentFlags, completionRoutine, method), + onFailure: e => completionRoutine(DkmGetFrameNameAsyncResult.CreateErrorResult(e))); } catch (Exception e) when (ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { @@ -106,18 +56,135 @@ void IDkmLanguageFrameDecoder.GetFrameName(DkmInspectionContext inspectionContex } } - void IDkmLanguageFrameDecoder.GetFrameReturnType(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmStackWalkFrame frame, DkmCompletionRoutine completionRoutine) + void IDkmLanguageFrameDecoder.GetFrameReturnType( + DkmInspectionContext inspectionContext, + DkmWorkList workList, + DkmStackWalkFrame frame, + DkmCompletionRoutine completionRoutine) { try { - var returnType = _instructionDecoder.GetReturnType((DkmClrInstructionAddress)frame.InstructionAddress); - var result = new DkmGetFrameReturnTypeAsyncResult(returnType); - completionRoutine(result); + GetNameWithGenericTypeArguments(inspectionContext, workList, frame, + onSuccess: method => completionRoutine(new DkmGetFrameReturnTypeAsyncResult(_instructionDecoder.GetReturnTypeName(method))), + onFailure: e => completionRoutine(DkmGetFrameReturnTypeAsyncResult.CreateErrorResult(e))); } catch (Exception e) when (ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } } + + private void GetNameWithGenericTypeArguments( + DkmInspectionContext inspectionContext, + DkmWorkList workList, + DkmStackWalkFrame frame, + Action onSuccess, + Action onFailure) + { + // NOTE: We could always call GetClrGenericParameters, pass them to GetMethod and have that + // return a constructed method symbol, but it seems unwise to call GetClrGenericParameters + // for all frames (as this call requires a round-trip to the debuggee process). + var instructionAddress = (DkmClrInstructionAddress)frame.InstructionAddress; + var compilation = _instructionDecoder.GetCompilation(instructionAddress); + var method = _instructionDecoder.GetMethod(compilation, instructionAddress); + var typeParameters = _instructionDecoder.GetAllTypeParameters(method); + if (!typeParameters.IsEmpty) + { + frame.GetClrGenericParameters( + workList, + result => + { + try + { + var typeArguments = _instructionDecoder.GetTypeSymbols(compilation, method, result.ParameterTypeNames); + if (!typeArguments.IsEmpty) + { + method = _instructionDecoder.ConstructMethod(method, typeParameters, typeArguments); + } + onSuccess(method); + } + catch (Exception e) when (ExpressionEvaluatorFatalError.ReportNonFatalException(e, DkmComponentManager.ReportCurrentNonFatalException)) + { + onFailure(e); + } + }); + } + else + { + onSuccess(method); + } + } + + private void GetFrameName( + DkmInspectionContext inspectionContext, + DkmWorkList workList, + DkmStackWalkFrame frame, + DkmVariableInfoFlags argumentFlags, + DkmCompletionRoutine completionRoutine, + TMethodSymbol method) + { + var includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types); + var includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names); + + if (argumentFlags.Includes(DkmVariableInfoFlags.Values)) + { + // No need to compute the Expandable bit on + // argument values since that can be expensive. + inspectionContext = DkmInspectionContext.Create( + inspectionContext.InspectionSession, + inspectionContext.RuntimeInstance, + inspectionContext.Thread, + inspectionContext.Timeout, + inspectionContext.EvaluationFlags | DkmEvaluationFlags.NoExpansion, + inspectionContext.FuncEvalFlags, + inspectionContext.Radix, + inspectionContext.Language, + inspectionContext.ReturnValue, + inspectionContext.AdditionalVisualizationData, + inspectionContext.AdditionalVisualizationDataPriority, + inspectionContext.ReturnValues); + + // GetFrameArguments returns an array of formatted argument values. We'll pass + // ourselves (GetFrameName) as the continuation of the GetFrameArguments call. + inspectionContext.GetFrameArguments( + workList, + frame, + result => + { + var argumentValues = result.Arguments; + try + { + var builder = ArrayBuilder.GetInstance(); + foreach (var argument in argumentValues) + { + var formattedArgument = argument as DkmSuccessEvaluationResult; + // Not expecting Expandable bit, at least not from this EE. + Debug.Assert((formattedArgument == null) || (formattedArgument.Flags & DkmEvaluationResultFlags.Expandable) == 0); + builder.Add(formattedArgument?.Value); + } + + var frameName = _instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder); + builder.Free(); + completionRoutine(new DkmGetFrameNameAsyncResult(frameName)); + } + catch (Exception e) when (ExpressionEvaluatorFatalError.ReportNonFatalException(e, DkmComponentManager.ReportCurrentNonFatalException)) + { + completionRoutine(DkmGetFrameNameAsyncResult.CreateErrorResult(e)); + } + finally + { + foreach (var argument in argumentValues) + { + argument.Close(); + } + } + }); + } + else + { + var frameName = _instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, null); + completionRoutine(new DkmGetFrameNameAsyncResult(frameName)); + } + } } } diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/InstructionDecoder.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/InstructionDecoder.cs index be947e272e0a1..80126b5f5e6bd 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/InstructionDecoder.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/InstructionDecoder.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; using System.Diagnostics; using System.Text; using Microsoft.CodeAnalysis.Collections; @@ -7,13 +8,12 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator { - internal abstract class InstructionDecoder - { - internal abstract string GetName(DkmClrInstructionAddress instructionAddress, bool includeParameterTypes, bool includeParameterNames, ArrayBuilder argumentValues); - internal abstract string GetReturnType(DkmClrInstructionAddress instructionAddress); - } - - internal abstract class InstructionDecoder : InstructionDecoder where TMethodSymbol : class, IMethodSymbol + internal abstract class InstructionDecoder + where TCompilation : Compilation + where TMethodSymbol : class, IMethodSymbol + where TModuleSymbol : class, IModuleSymbol + where TTypeSymbol : class, ITypeSymbol + where TTypeParameterSymbol : class, ITypeParameterSymbol { internal static readonly SymbolDisplayFormat DisplayFormat = new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, @@ -21,21 +21,18 @@ internal abstract class InstructionDecoder : InstructionDecoder w memberOptions: SymbolDisplayMemberOptions.IncludeContainingType | SymbolDisplayMemberOptions.IncludeExplicitInterface, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); - internal override string GetName(DkmClrInstructionAddress instructionAddress, bool includeParameterTypes, bool includeParameterNames, ArrayBuilder argumentValues) - { - var method = this.GetMethod(instructionAddress); - return this.GetName(method, includeParameterTypes, includeParameterNames, argumentValues); - } + internal abstract void AppendFullName(StringBuilder builder, TMethodSymbol method); - internal override string GetReturnType(DkmClrInstructionAddress instructionAddress) - { - var method = this.GetMethod(instructionAddress); - return method.ReturnType.ToDisplayString(DisplayFormat); - } + /// + /// Constructs a method and any of its generic containing types using the specified . + /// + internal abstract TMethodSymbol ConstructMethod(TMethodSymbol method, ImmutableArray typeParameters, ImmutableArray typeArguments); - internal abstract void AppendFullName(StringBuilder builder, TMethodSymbol method); + internal abstract ImmutableArray GetAllTypeParameters(TMethodSymbol method); + + internal abstract TCompilation GetCompilation(DkmClrInstructionAddress instructionAddress); - internal abstract TMethodSymbol GetMethod(DkmClrInstructionAddress instructionAddress); + internal abstract TMethodSymbol GetMethod(TCompilation compilation, DkmClrInstructionAddress instructionAddress); internal string GetName(TMethodSymbol method, bool includeParameterTypes, bool includeParameterNames, ArrayBuilder argumentValues = null) { @@ -96,5 +93,33 @@ internal string GetName(TMethodSymbol method, bool includeParameterTypes, bool i return pooled.ToStringAndFree(); } + + internal string GetReturnTypeName(TMethodSymbol method) + { + return method.ReturnType.ToDisplayString(DisplayFormat); + } + + internal abstract TypeNameDecoder GetTypeNameDecoder(TCompilation compilation, TMethodSymbol method); + + internal ImmutableArray GetTypeSymbols(TCompilation compilation, TMethodSymbol method, string[] serializedTypeNames) + { + var builder = ArrayBuilder.GetInstance(); + foreach (var name in serializedTypeNames) + { + // The list of type names will include null values if type arguments are not available. + // It seems unlikely that only some type arguments will be missing (and it also seems + // like very little incremental value to include only some of the arguments), so we'll + // keep things simple and omit all type arguments if any are missing. + if (name == null) + { + builder.Free(); + return ImmutableArray.Empty; + } + + var typeNameDecoder = GetTypeNameDecoder(compilation, method); + builder.Add(typeNameDecoder.GetTypeSymbolForSerializedType(name)); + } + return builder.ToImmutableAndFree(); + } } } diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/LanguageInstructionDecoder.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/LanguageInstructionDecoder.cs index d5a7b0a357593..bbed5e6088945 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/LanguageInstructionDecoder.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/LanguageInstructionDecoder.cs @@ -17,11 +17,16 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator /// /// This class provides function name information for the Breakpoints window. /// - internal abstract class LanguageInstructionDecoder : IDkmLanguageInstructionDecoder where TMethodSymbol : class, IMethodSymbol + internal abstract class LanguageInstructionDecoder : IDkmLanguageInstructionDecoder + where TCompilation : Compilation + where TMethodSymbol : class, IMethodSymbol + where TModuleSymbol : class, IModuleSymbol + where TTypeSymbol : class, ITypeSymbol + where TTypeParameterSymbol : class, ITypeParameterSymbol { - private readonly InstructionDecoder _instructionDecoder; + private readonly InstructionDecoder _instructionDecoder; - internal LanguageInstructionDecoder(InstructionDecoder instructionDecoder) + internal LanguageInstructionDecoder(InstructionDecoder instructionDecoder) { _instructionDecoder = instructionDecoder; } @@ -37,7 +42,9 @@ string IDkmLanguageInstructionDecoder.GetMethodName(DkmLanguageInstructionAddres Debug.Assert((argumentFlags & (DkmVariableInfoFlags.FullNames | DkmVariableInfoFlags.Names | DkmVariableInfoFlags.Types)) == argumentFlags, "Unexpected argumentFlags", "argumentFlags = {0}", argumentFlags); - var method = _instructionDecoder.GetMethod((DkmClrInstructionAddress)languageInstructionAddress.Address); + var instructionAddress = (DkmClrInstructionAddress)languageInstructionAddress.Address; + var compilation = _instructionDecoder.GetCompilation(instructionAddress); + var method = _instructionDecoder.GetMethod(compilation, instructionAddress); var includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types); var includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names); diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb index 1b42c478cc57d..1538af4c4605d 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb @@ -1,4 +1,6 @@ -Imports System +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Threading @@ -173,13 +175,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return moduleBuilder End Function - Private Shared Function GetAllTypeParameters(method As MethodSymbol) As ImmutableArray(Of TypeParameterSymbol) - Dim builder = ArrayBuilder(Of TypeParameterSymbol).GetInstance() - method.ContainingType.GetAllTypeParameters(builder) - builder.AddRange(method.TypeParameters) - Return builder.ToImmutableAndFree() - End Function - Private Shared Function GetNextMethodName(builder As ArrayBuilder(Of MethodSymbol)) As String ' NOTE: These names are consumed by Concord, so there's no native precedent. Return String.Format("<>m{0}", builder.Count) diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/SymbolExtensions.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/SymbolExtensions.vb index 4c6b96d59311e..b2f418a0b8278 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/SymbolExtensions.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/SymbolExtensions.vb @@ -1,4 +1,7 @@ -Imports System.Runtime.CompilerServices +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Collections.Immutable +Imports System.Runtime.CompilerServices Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator @@ -59,5 +62,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Friend Function IsStateMachineType(type As TypeSymbol) As Boolean Return type.Name.StartsWith(StringConstants.StateMachineTypeNamePrefix, StringComparison.Ordinal) End Function + + + Friend Function GetAllTypeParameters(method As MethodSymbol) As ImmutableArray(Of TypeParameterSymbol) + Dim builder = ArrayBuilder(Of TypeParameterSymbol).GetInstance() + method.ContainingType.GetAllTypeParameters(builder) + builder.AddRange(method.TypeParameters) + Return builder.ToImmutableAndFree() + End Function End Module End Namespace diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicFrameDecoder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicFrameDecoder.vb index fc1aa18494b38..dc71a62a05c4a 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicFrameDecoder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicFrameDecoder.vb @@ -1,9 +1,13 @@ -Imports Microsoft.CodeAnalysis.ExpressionEvaluator +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis.ExpressionEvaluator +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator - Friend NotInheritable Class VisualBasicFrameDecoder : Inherits FrameDecoder + Friend NotInheritable Class VisualBasicFrameDecoder : Inherits FrameDecoder(Of VisualBasicCompilation, MethodSymbol, PEModuleSymbol, TypeSymbol, TypeParameterSymbol) Public Sub New() MyBase.New(VisualBasicInstructionDecoder.Instance) diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicInstructionDecoder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicInstructionDecoder.vb index ba82c0aac338b..c4fac085d08f5 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicInstructionDecoder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicInstructionDecoder.vb @@ -1,6 +1,8 @@ -Imports System.Runtime.InteropServices +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.ExpressionEvaluator +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.VisualStudio.Debugger Imports Microsoft.VisualStudio.Debugger.Clr @@ -8,7 +10,7 @@ Imports System.Text Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator - Friend NotInheritable Class VisualBasicInstructionDecoder : Inherits InstructionDecoder(Of PEMethodSymbol) + Friend NotInheritable Class VisualBasicInstructionDecoder : Inherits InstructionDecoder(Of VisualBasicCompilation, MethodSymbol, PEModuleSymbol, TypeSymbol, TypeParameterSymbol) ' These strings were not localized in the old EE. We'll keep them that way ' so as not to break consumers who may have been parsing frame names... @@ -18,12 +20,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ''' ''' Singleton instance of (created using default constructor). ''' - Friend Shared ReadOnly Instance as VisualBasicInstructionDecoder = New VisualBasicInstructionDecoder() + Friend Shared ReadOnly Instance As VisualBasicInstructionDecoder = New VisualBasicInstructionDecoder() Private Sub New() End Sub - Friend Overrides Sub AppendFullName(builder As StringBuilder, method As PEMethodSymbol) + Friend Overrides Sub AppendFullName(builder As StringBuilder, method As MethodSymbol) Dim parts = method.ToDisplayParts(DisplayFormat) Dim numParts = parts.Length For i = 0 To numParts - 1 @@ -59,9 +61,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Next End Sub - Friend Overrides Function GetMethod(instructionAddress As DkmClrInstructionAddress) As PEMethodSymbol - Dim moduleInstance = instructionAddress.ModuleInstance - Dim appDomain = moduleInstance.AppDomain + Friend Overrides Function ConstructMethod(method As MethodSymbol, typeParameters As ImmutableArray(Of TypeParameterSymbol), typeArguments As ImmutableArray(Of TypeSymbol)) As MethodSymbol + Dim methodArity = method.Arity + Dim methodArgumentStartIndex = typeParameters.Length - methodArity + Dim typeMap = TypeSubstitution.Create( + method, + ImmutableArray.Create(typeParameters, 0, methodArgumentStartIndex), + ImmutableArray.Create(typeArguments, 0, methodArgumentStartIndex)) + Dim substitutedType = typeMap.SubstituteNamedType(method.ContainingType) + method = method.AsMember(substitutedType) + If methodArity > 0 Then + method = method.Construct(ImmutableArray.Create(typeArguments, methodArgumentStartIndex, methodArity)) + End If + Return method + End Function + + Friend Overrides Function GetAllTypeParameters(method As MethodSymbol) As ImmutableArray(Of TypeParameterSymbol) + Return method.GetAllTypeParameters() + End Function + + Friend Overrides Function GetCompilation(instructionAddress As DkmClrInstructionAddress) As VisualBasicCompilation + Dim appDomain = instructionAddress.ModuleInstance.AppDomain Dim previous = appDomain.GetDataItem(Of VisualBasicMetadataContext)() Dim metadataBlocks = instructionAddress.Process.GetMetadataBlocks(appDomain) @@ -73,7 +93,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator appDomain.SetDataItem(DkmDataCreationDisposition.CreateAlways, New VisualBasicMetadataContext(metadataBlocks)) End If - Return compilation.GetSourceMethod(moduleInstance.Mvid, instructionAddress.MethodId.Token) + Return compilation + End Function + + Friend Overrides Function GetMethod(compilation As VisualBasicCompilation, instructionAddress As DkmClrInstructionAddress) As MethodSymbol + Return compilation.GetSourceMethod(instructionAddress.ModuleInstance.Mvid, instructionAddress.MethodId.Token) + End Function + + Friend Overrides Function GetTypeNameDecoder(compilation As VisualBasicCompilation, method As MethodSymbol) As TypeNameDecoder(Of PEModuleSymbol, TypeSymbol) + Debug.Assert(TypeOf method Is PEMethodSymbol) + Return New EETypeNameDecoder(compilation, DirectCast(method.ContainingModule, PEModuleSymbol)) End Function End Class diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicLanguageInstructionDecoder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicLanguageInstructionDecoder.vb index cd4ba00673d41..c8fad9add4aa5 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicLanguageInstructionDecoder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/VisualBasicLanguageInstructionDecoder.vb @@ -1,10 +1,13 @@ -Imports Microsoft.CodeAnalysis.ExpressionEvaluator +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis.ExpressionEvaluator +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator - Friend NotInheritable Class VisualBasicLanguageInstructionDecoder : Inherits LanguageInstructionDecoder(Of PEMethodSymbol) + Friend NotInheritable Class VisualBasicLanguageInstructionDecoder : Inherits LanguageInstructionDecoder(Of VisualBasicCompilation, MethodSymbol, PEModuleSymbol, TypeSymbol, TypeParameterSymbol) Public Sub New() MyBase.New(VisualBasicInstructionDecoder.Instance) diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb index 5b0f03b1db133..ccc81e7fa618e 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb @@ -1,4 +1,6 @@ -Imports System.Collections.Immutable +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Collections.Immutable Imports System.Globalization Imports System.Reflection.Metadata Imports System.Threading diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/InstructionDecoderTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/InstructionDecoderTests.vb index 1b33fa3b22a4f..93796e17f3f75 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/InstructionDecoderTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/InstructionDecoderTests.vb @@ -1,4 +1,7 @@ -Imports System.Reflection.Metadata.Ecma335 +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Reflection.Metadata.Ecma335 +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.ExpressionEvaluator Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -20,11 +23,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator '// TODO: string argument values requiring quotes '// TODO: argument flags == names only, types only, values only '// TODO: params Argument values - '// TODO: GetFrameReturnType primitive types - '// TODO: GetFrameReturnType non-primitive types (nested namespace/class) - '// TODO: GetFrameReturnType generic(Of non-primitive, nested) - '// TODO: GetFrameReturnType generic(Of generic) - '// TODO: GetFrameReturnType generic(Of primitive) + '// TODO: generic class/method with 2 or more type parameters + '// TODO: generic argument type that is not from a referenced assembly Public Class InstructionDecoderTests : Inherits ExpressionCompilerTestBase @@ -85,7 +85,6 @@ Class Class1(Of T) Sub M3(Of U)(a As Action(Of U)) End Sub End Class" - ' TODO: Type parameters should be substituted with type arguments once we have an API to retrieve them. Assert.Equal( "Class1(Of T).M1(Of U)(System.Action(Of Integer) a)", @@ -98,6 +97,52 @@ End Class" Assert.Equal( "Class1(Of T).M3(Of U)(System.Action(Of U) a)", GetName(source, "Class1.M3", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) + + Assert.Equal( + "Class1(Of String).M1(Of Decimal)(System.Action(Of Integer) a)", + GetName(source, "Class1.M1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) + + Assert.Equal( + "Class1(Of String).M2(Of Decimal)(System.Action(Of String) a)", + GetName(source, "Class1.M2", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) + + Assert.Equal( + "Class1(Of String).M3(Of Decimal)(System.Action(Of Decimal) a)", + GetName(source, "Class1.M3", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), GetType(Decimal)})) + End Sub + + + Sub GetNameNullTypeArguments() + Dim source = " +Imports System +Class Class1(Of T) + Sub M(Of U)(a As Action(Of U)) + End Sub +End Class" + + Assert.Equal( + "Class1(Of T).M(Of U)(System.Action(Of U) a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:=New Type() {Nothing, Nothing})) + + Assert.Equal( + "Class1(Of T).M(Of U)(System.Action(Of U) a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(String), Nothing})) + + Assert.Equal( + "Class1(Of T).M(Of U)(System.Action(Of U) a)", + GetName(source, "Class1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={Nothing, GetType(Decimal)})) + End Sub + + + Sub GetNameGenericArgumentTypeNotInReferences() + Dim source = " +Class Class1 +End Class" + + Dim serializedTypeArgumentName = "Class1, " & NameOf(InstructionDecoderTests) & ", Culture=neutral, PublicKeyToken=null" + Assert.Equal( + "System.Collections.Generic.Comparer(Of Class1).Create(System.Comparison(Of Class1) comparison)", + GetName(source, "System.Collections.Generic.Comparer.Create", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={serializedTypeArgumentName})) End Sub @@ -130,8 +175,8 @@ Class C End Class" Assert.Equal( - "C.M(Of T)(T x)", - GetName(source, "C.VB$StateMachine_1_M.MoveNext", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) + "C.M(Of Long)(Long x)", + GetName(source, "C.VB$StateMachine_1_M.MoveNext", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(Long)})) End Sub @@ -175,10 +220,10 @@ Class Class1(Of T) Dim f As Func(Of U, T) = Function(u2 As U) u2 End Sub End Class" - ' TODO: Type parameter $CLS0 should be substituted with a type argument once we have an API to retrieve it. + Assert.Equal( - "Class1(Of T)..($CLS0 u2)", - GetName(source, "Class1._Closure$__1._Lambda$__1-1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) + "Class1(Of System.Exception)..(System.ArgumentException u2)", + GetName(source, "Class1._Closure$__1._Lambda$__1-1", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, typeArguments:={GetType(Exception), GetType(ArgumentException)})) End Sub @@ -196,7 +241,7 @@ End Module" Assert.Equal( "Module1.M(Date d = #6/23/1912#)", - GetName(source, "Module1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, "#6/23/1912#")) + GetName(source, "Module1.M", DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types, argumentValues:={"#6/23/1912#"})) End Sub @@ -284,14 +329,120 @@ End Module" GetName(source, "Module1.M2", DkmVariableInfoFlags.None)) End Sub - Private Function GetName(source As String, methodName As String, argumentFlags As DkmVariableInfoFlags, ParamArray argumentValues() As String) As String + + Sub GetReturnTypeNamePrimitive() + Dim source = " +Class C + Function M1() As UInteger + Return 42 + End Function +End Class" + + Assert.Equal("UInteger", GetReturnTypeName(source, "C.M1")) + End Sub + + + Sub GetReturnTypeNameNested() + Dim source = " +Class C + Function M1() As N.D.E + Return Nothing + End Function +End Class +Namespace N + Class D + Friend Structure E + End Structure + End Class +End Namespace" + + Assert.Equal("N.D.E", GetReturnTypeName(source, "C.M1")) + End Sub + + + Sub GetReturnTypeNameGenericOfPrimitive() + Dim source = " +Imports System +Class C + Function M1() As Action(Of Int32) + Return Nothing + End Function +End Class" + + Assert.Equal("System.Action(Of Integer)", GetReturnTypeName(source, "C.M1")) + End Sub + + + Sub GetReturnTypeNameGenericOfNested() + Dim source = " +Imports System +Class C + Function M1() As Action(Of D) + Return Nothing + End Function + Class D + End Class +End Class" + + Assert.Equal("System.Action(Of C.D)", GetReturnTypeName(source, "C.M1")) + End Sub + + + Sub GetReturnTypeNameGenericOfGeneric() + Dim source = " +Imports System +Class C + Function M1(Of T)() As Action(Of Func(Of T)) + Return Nothing + End Function +End Class" + + Assert.Equal("System.Action(Of System.Func(Of Object))", GetReturnTypeName(source, "C.M1", typeArguments:={GetType(Object)})) + End Sub + + Private Function GetName(source As String, methodName As String, argumentFlags As DkmVariableInfoFlags, Optional typeArguments() As Type = Nothing, Optional argumentValues() As String = Nothing) As String + Dim serializedTypeArgumentNames = typeArguments?.Select(Function(t) t?.AssemblyQualifiedName).ToArray() + Return GetName(source, methodName, argumentFlags, serializedTypeArgumentNames, argumentValues) + End Function + + Private Function GetName(source As String, methodName As String, argumentFlags As DkmVariableInfoFlags, typeArguments() As String, Optional argumentValues() As String = Nothing) As String Debug.Assert((argumentFlags And (DkmVariableInfoFlags.Names Or DkmVariableInfoFlags.Types)) = argumentFlags, "Unexpected argumentFlags", "argumentFlags = {0}", argumentFlags) + Dim instructionDecoder = VisualBasicInstructionDecoder.Instance + Dim method = GetConstructedMethod(source, methodName, typeArguments, instructionDecoder) + + Dim includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types) + Dim includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names) + Dim builder As ArrayBuilder(Of String) = Nothing + If argumentValues IsNot Nothing Then + Assert.InRange(argumentValues.Length, 1, Integer.MaxValue) + builder = ArrayBuilder(Of String).GetInstance() + builder.AddRange(argumentValues) + End If + + Dim name = instructionDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder) + If builder IsNot Nothing Then + builder.Free() + End If + + Return name + End Function + + Private Function GetReturnTypeName(source As String, methodName As String, Optional typeArguments() As Type = Nothing) As String + Dim instructionDecoder = VisualBasicInstructionDecoder.Instance + Dim serializedTypeArgumentNames = typeArguments?.Select(Function(t) t?.AssemblyQualifiedName).ToArray() + Dim method = GetConstructedMethod(source, methodName, serializedTypeArgumentNames, instructionDecoder) + + Return instructionDecoder.GetReturnTypeName(method) + End Function + + Private Function GetConstructedMethod(source As String, methodName As String, serializedTypeArgumentNames() As String, instructionDecoder As VisualBasicInstructionDecoder) As MethodSymbol Dim compilation = CreateCompilationWithReferences( {VisualBasicSyntaxTree.ParseText(source)}, references:={MscorlibRef_v4_0_30316_17626, MsvbRef_v4_0_30319_17929}, - options:=TestOptions.DebugDll) + options:=TestOptions.DebugDll, + assemblyName:=NameOf(InstructionDecoderTests)) Dim runtime = CreateRuntimeInstance(compilation) Dim moduleInstances = runtime.Modules Dim blocks = moduleInstances.SelectAsArray(Function(m) m.MetadataBlock) @@ -301,26 +452,24 @@ End Module" ' Once we have the method token, we want to look up the method (again) ' using the same helper as the product code. This helper will also map ' async/ iterator "MoveNext" methods to the original source method. - Dim method = compilation.GetSourceMethod( + Dim method As MethodSymbol = compilation.GetSourceMethod( DirectCast(frame.ContainingModule, PEModuleSymbol).Module.GetModuleVersionIdOrThrow(), MetadataTokens.GetToken(frame.Handle)) - Dim includeParameterTypes = argumentFlags.Includes(DkmVariableInfoFlags.Types) - Dim includeParameterNames = argumentFlags.Includes(DkmVariableInfoFlags.Names) - Dim builder As ArrayBuilder(Of String) = Nothing - If argumentValues.Length > 0 Then - builder = ArrayBuilder(Of String).GetInstance() - builder.AddRange(argumentValues) - End If - - Dim frameDecoder = VisualBasicInstructionDecoder.Instance - Dim frameName = frameDecoder.GetName(method, includeParameterTypes, includeParameterNames, builder) - If builder IsNot Nothing Then - builder.Free() + If serializedTypeArgumentNames IsNot Nothing Then + Assert.NotEmpty(serializedTypeArgumentNames) + Dim typeParameters = instructionDecoder.GetAllTypeParameters(method) + Assert.NotEmpty(typeParameters) + Dim typeNameDecoder = New EETypeNameDecoder(compilation, DirectCast(method.ContainingModule, PEModuleSymbol)) + ' Use the same helper method as the FrameDecoder to get the TypeSymbols for the + ' generic type arguments (rather than using EETypeNameDecoder directly). + Dim typeArgumentSymbols = instructionDecoder.GetTypeSymbols(compilation, method, serializedTypeArgumentNames) + If Not typeArgumentSymbols.IsEmpty Then + method = instructionDecoder.ConstructMethod(method, typeParameters, typeArgumentSymbols) + End If End If - Return frameName + Return method End Function - End Class End Namespace From e4dbbc296eed1338d83e3fb1a2823f44783c4fa5 Mon Sep 17 00:00:00 2001 From: Heejae Chang Date: Tue, 10 Feb 2015 16:46:28 -0800 Subject: [PATCH 09/16] remove dead code removed dead code. code I wrote long time ago for specific indenter case is left in code base when it is no longer needed. --- .../Utilities/CommonFormattingHelpers.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/CommonFormattingHelpers.cs b/src/Workspaces/Core/Portable/Shared/Utilities/CommonFormattingHelpers.cs index d3af0c3551fce..cd6ca2f63b19c 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/CommonFormattingHelpers.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/CommonFormattingHelpers.cs @@ -149,36 +149,6 @@ public static int GetTokenColumn(this SyntaxTree tree, SyntaxToken token, int ta return line.GetColumnFromLineOffset(startPosition - line.Start, tabSize); } - public static bool IsFirstTokenOnLine(this SyntaxTree tree, SyntaxToken token) - { - Contract.ThrowIfNull(tree); - Contract.ThrowIfTrue(token.RawKind == 0); - - var previousToken = token.GetPreviousToken(); - - // there should be only whitespace between two tokens unless the token can't be the first token on line - if (!string.IsNullOrWhiteSpace(tree.GetText().GetText(previousToken, token))) - { - return false; - } - - if (previousToken.RawKind == 0) - { - return true; - } - - var previousLine = tree.GetText().Lines.GetLineFromPosition(previousToken.Span.End); - var lineNumber = tree.GetText().Lines.IndexOf(token.SpanStart); - - // if span.End is at the edge of two lines, it belongs to previous line - if (previousLine.Start == previousToken.Span.End) - { - return previousLine.LineNumber - 1 < lineNumber; - } - - return previousLine.LineNumber < lineNumber; - } - public static string GetText(this SourceText text, SyntaxToken token1, SyntaxToken token2) { return (token1.RawKind == 0) ? text.ToString(TextSpan.FromBounds(0, token2.SpanStart)) : text.ToString(TextSpan.FromBounds(token1.Span.End, token2.SpanStart)); From 5c209191f1464f62624dead6ee184d5dd630bbeb Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Tue, 10 Feb 2015 16:48:02 -0800 Subject: [PATCH 10/16] Fix RunTests It is apparently possible for a test to exit with an error code, produce no HTML file and no output. In that case the call to Aggregate was failing with an exception. Change it to use ToArray + File.WriteAllLines. This won't fix the underlying problem but will at least identify the test that is failing. --- src/Tools/Source/RunTests/TestRunner.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tools/Source/RunTests/TestRunner.cs b/src/Tools/Source/RunTests/TestRunner.cs index b18c3c0a65752..48b64d223ce33 100644 --- a/src/Tools/Source/RunTests/TestRunner.cs +++ b/src/Tools/Source/RunTests/TestRunner.cs @@ -129,8 +129,8 @@ private async Task RunTest(string assemblyPath) var all = File.ReadAllText(resultsPath).Trim(); if (all.Length == 0) { - var output = processOutput.OutputLines.Concat(processOutput.ErrorLines).Aggregate((x, y) => x + Environment.NewLine + y); - File.WriteAllText(resultsPath, output); + var output = processOutput.OutputLines.Concat(processOutput.ErrorLines).ToArray(); + File.WriteAllLines(resultsPath, output); } errorOutput = processOutput.ErrorLines.Aggregate((x, y) => x + Environment.NewLine + y); From b73a4fad9e30f794e957e04693b0d3524ad968da Mon Sep 17 00:00:00 2001 From: Tomas Matousek Date: Tue, 10 Feb 2015 17:31:00 -0800 Subject: [PATCH 11/16] Add filter to NavigableItemFactory.DeclaredSymbolNavigableItem._lazyDisplayName --- ...ItemFactory.DeclaredSymbolNavigableItem.cs | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/Core/Extensibility/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs b/src/EditorFeatures/Core/Extensibility/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs index d03e168d4ce7b..d2654499db228 100644 --- a/src/EditorFeatures/Core/Extensibility/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs +++ b/src/EditorFeatures/Core/Extensibility/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs @@ -2,10 +2,12 @@ using System; using System.Threading; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Navigation { @@ -33,24 +35,31 @@ public DeclaredSymbolNavigableItem(Document document, DeclaredSymbolInfo declare _lazySymbol = new Lazy(() => declaredSymbolInfo.GetSymbolAsync(document, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult()); _lazyDisplayName = new Lazy(() => { - if (Symbol == null) + try { - return null; - } + if (Symbol == null) + { + return null; + } - var symbolDisplayService = Document.GetLanguageService(); - switch (Symbol.Kind) - { - case SymbolKind.NamedType: - return symbolDisplayService.ToDisplayString(Symbol, s_shortFormatWithModifiers); + var symbolDisplayService = Document.GetLanguageService(); + switch (Symbol.Kind) + { + case SymbolKind.NamedType: + return symbolDisplayService.ToDisplayString(Symbol, s_shortFormatWithModifiers); - case SymbolKind.Method: - return Symbol.IsStaticConstructor() - ? symbolDisplayService.ToDisplayString(Symbol, s_shortFormatWithModifiers) - : symbolDisplayService.ToDisplayString(Symbol, s_shortFormat); + case SymbolKind.Method: + return Symbol.IsStaticConstructor() + ? symbolDisplayService.ToDisplayString(Symbol, s_shortFormatWithModifiers) + : symbolDisplayService.ToDisplayString(Symbol, s_shortFormat); - default: - return symbolDisplayService.ToDisplayString(Symbol, s_shortFormat); + default: + return symbolDisplayService.ToDisplayString(Symbol, s_shortFormat); + } + } + catch (Exception e) when (FatalError.Report(e)) + { + throw ExceptionUtilities.Unreachable; } }); } From 40b7ea327c8af1b4f8072b18e5bb0a87690005c7 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Tue, 10 Feb 2015 17:50:31 -0800 Subject: [PATCH 12/16] Add skipped test for https://github.com/dotnet/roslyn/issues/320: Possible bug in Batch Fixer merge algorithm. --- .../CSharpEditorServicesTest.csproj | 6 +- .../FixAllProvider/BatchFixerTests.cs | 159 ++++++++++++++++++ 2 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs diff --git a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj index 031328a063af5..8c32d4ce8aa82 100644 --- a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj +++ b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj @@ -224,6 +224,7 @@ + @@ -614,10 +615,7 @@ PreserveNewest - - - - + diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs new file mode 100644 index 0000000000000..36526c82b33ca --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.SimplifyTypeNames +{ + public partial class BatchFixerTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + { + internal override Tuple CreateDiagnosticProviderAndFixer(Workspace workspace) + { + return Tuple.Create(new QualifyWithThisAnalyzer(), new QualifyWithThisFixer()); + } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + private class QualifyWithThisAnalyzer : DiagnosticAnalyzer + { + public static readonly DiagnosticDescriptor Descriptor = new TriggerDiagnosticDescriptor("QualifyWithThis"); + + public override ImmutableArray SupportedDiagnostics + { + get + { + return ImmutableArray.Create(Descriptor); + } + } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.IdentifierName); + } + + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + var node = context.Node as SimpleNameSyntax; + if (node != null) + { + var symbol = context.SemanticModel.GetSymbolInfo(node).Symbol; + if (symbol != null && symbol.Kind == SymbolKind.Field) + { + var diagnostic = Diagnostic.Create(Descriptor, node.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + } + } + + class QualifyWithThisFixer : CodeFixProvider + { + public override ImmutableArray FixableDiagnosticIds + { + get + { + return ImmutableArray.Create(QualifyWithThisAnalyzer.Descriptor.Id); + } + } + + public async override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var node = root.FindNode(context.Span, getInnermostNodeForTie: true) as SimpleNameSyntax; + if (node != null) + { + var leadingTrivia = node.GetLeadingTrivia(); + var newNode = SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.ThisExpression(), + node.WithoutLeadingTrivia()) + .WithLeadingTrivia(leadingTrivia); + + var newRoot = root.ReplaceNode(node, newNode); + var newDocument = context.Document.WithSyntaxRoot(newRoot); + +#pragma warning disable RS0005 // Do not use generic CodeAction.Create to create CodeAction + var fix = CodeAction.Create("QualifyWithThisFix", _ => Task.FromResult(newDocument)); +#pragma warning restore RS0005 // Do not use generic CodeAction.Create to create CodeAction + + context.RegisterCodeFix(fix, context.Diagnostics); + } + } + + public override FixAllProvider GetFixAllProvider() + { + return WellKnownFixAllProviders.BatchFixer; + } + } + + #region "Fix all occurrences tests" + + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/320")] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public void TestFixAllInDocument_QualifyWithThis() + { + var input = @" + + + +class C +{ + int Sign; + void F() + { + string x = @""namespace Namespace + { + class Type + { + void Foo() + { + int x = 1 "" + {|FixAllInDocument:Sign|} + @"" "" + Sign + @""3; + } + } + } +""; + } +} + + +"; + + var expected = @" + + + +class C +{ + int Sign; + void F() + { + string x = @""namespace Namespace + { + class Type + { + void Foo() + { + int x = 1 "" + this.Sign + @"" "" + this.Sign + @""3; + } + } + } +""; + } +} + + +"; + + Test(input, expected, isLine: false, compareTokens: false); + } + + #endregion + } +} From 7927dc40a12be2da92cb0e7e9862c7382d9f9f60 Mon Sep 17 00:00:00 2001 From: Tomas Matousek Date: Tue, 10 Feb 2015 18:40:01 -0800 Subject: [PATCH 13/16] Add documentation of VB root namespace CDI --- docs/specs/PortablePdb-Metadata.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/specs/PortablePdb-Metadata.md b/docs/specs/PortablePdb-Metadata.md index 93a0f14b287a8..3a4032ad6e03f 100644 --- a/docs/specs/PortablePdb-Metadata.md +++ b/docs/specs/PortablePdb-Metadata.md @@ -373,6 +373,19 @@ Structure: TODO: Bit ordering. +##### Root Namespace (VB compiler) +Parent: Module + +Kind: {58b2eab6-209f-4e4e-a22c-b2d0f910c782} + +Structure: + + Blob ::= namespace + +| terminal | encoding | description| +|:---------|:---------|:-----------| +| _namespace_ | UTF8 string | The root namespace. | + ##### Edit and Continue Local Slot Map (C# & VB compilers) Parent: MethodDef From aba54ffca9b670a416196179d7f18c2a35692df9 Mon Sep 17 00:00:00 2001 From: Shyam N Date: Tue, 10 Feb 2015 23:10:38 -0800 Subject: [PATCH 14/16] Add *.wrn to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 25fac6ae83fb2..9ea10718c520f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ UnitTestResults.html *.tmp *.tmp_proj *.log +*.wrn *.vspscc *.vssscc .builds From 0d3212874561c43496c73db24149ef10dbd0269b Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Wed, 11 Feb 2015 01:00:29 -0800 Subject: [PATCH 15/16] Address CR feedback. --- .../CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs index 36526c82b33ca..0ad40aa333f6e 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/FixAllProvider/BatchFixerTests.cs @@ -53,7 +53,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context) } } - class QualifyWithThisFixer : CodeFixProvider + private class QualifyWithThisFixer : CodeFixProvider { public override ImmutableArray FixableDiagnosticIds { @@ -79,6 +79,7 @@ public async override Task RegisterCodeFixesAsync(CodeFixContext context) var newRoot = root.ReplaceNode(node, newNode); var newDocument = context.Document.WithSyntaxRoot(newRoot); + // Disable RS0005 as this is test code and we don't need telemtry for created code action. #pragma warning disable RS0005 // Do not use generic CodeAction.Create to create CodeAction var fix = CodeAction.Create("QualifyWithThisFix", _ => Task.FromResult(newDocument)); #pragma warning restore RS0005 // Do not use generic CodeAction.Create to create CodeAction From 6ba9c7a2005575aa10b544118c5bec174426b5ba Mon Sep 17 00:00:00 2001 From: Tomas Matousek Date: Wed, 11 Feb 2015 10:04:12 -0800 Subject: [PATCH 16/16] Add comments and cleanup method ordinals for additional types; also remove unused code --- .../Portable/Compilation/CSharpCompilation.cs | 24 +------------ .../Portable/Compiler/MethodCompiler.cs | 5 +-- .../Portable/Compiler/TypeCompilationState.cs | 16 +++++---- .../Emitter/Model/PEAssemblyBuilder.cs | 5 ++- .../ExpressionCompiler/CompilationContext.cs | 35 ++++++++++--------- .../Symbols/EEMethodSymbol.cs | 14 ++++++-- .../ExpressionCompiler/CompilationContext.vb | 34 ++++++++++-------- 7 files changed, 65 insertions(+), 68 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 6da8e695cadae..dc7921edb8de5 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2276,25 +2276,6 @@ internal override CommonPEModuleBuilder CreateModuleBuilder( CompilationTestData testData, DiagnosticBag diagnostics, CancellationToken cancellationToken) - { - return this.CreateModuleBuilder( - emitOptions, - manifestResources, - assemblySymbolMapper, - testData, - diagnostics, - ImmutableArray.Empty, - cancellationToken); - } - - internal CommonPEModuleBuilder CreateModuleBuilder( - EmitOptions emitOptions, - IEnumerable manifestResources, - Func assemblySymbolMapper, - CompilationTestData testData, - DiagnosticBag diagnostics, - ImmutableArray additionalTypes, - CancellationToken cancellationToken) { // Do not waste a slot in the submission chain for submissions that contain no executable code // (they may only contain #r directives, usings, etc.) @@ -2319,8 +2300,6 @@ internal CommonPEModuleBuilder CreateModuleBuilder( PEModuleBuilder moduleBeingBuilt; if (_options.OutputKind.IsNetModule()) { - Debug.Assert(additionalTypes.IsEmpty); - moduleBeingBuilt = new PENetModuleBuilder( (SourceModuleSymbol)SourceModule, emitOptions, @@ -2336,8 +2315,7 @@ internal CommonPEModuleBuilder CreateModuleBuilder( kind, moduleProps, manifestResources, - assemblySymbolMapper, - additionalTypes); + assemblySymbolMapper); } // testData is only passed when running tests. diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 1d72ca569db15..6962133bddabd 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -603,8 +603,9 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) AsyncStateMachine stateMachineType; - // In case of async lambdas, the method has already been uniquely named, so there is no need to - // produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) method name. + // Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals). + // In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named, + // so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name. const int methodOrdinal = -1; BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out stateMachineType); diff --git a/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs b/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs index 0325c25a809fd..40274c76ca52a 100644 --- a/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs +++ b/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs @@ -47,8 +47,11 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain im /// only need one wrapper to call it non-virtually. /// private Dictionary _wrappers; - - private readonly NamedTypeSymbol _type; + + /// + /// Type symbol being compiled, or null if we compile a synthesized type that doesn't have a symbol (e.g. PrivateImplementationDetails). + /// + private readonly NamedTypeSymbol _typeOpt; /// /// The builder for generating code, or null if not in emit phase. @@ -65,10 +68,10 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain im public LambdaFrame staticLambdaFrame; - public TypeCompilationState(NamedTypeSymbol type, CSharpCompilation compilation, PEModuleBuilder moduleBuilderOpt) + public TypeCompilationState(NamedTypeSymbol typeOpt, CSharpCompilation compilation, PEModuleBuilder moduleBuilderOpt) { this.Compilation = compilation; - _type = type; + _typeOpt = typeOpt; this.ModuleBuilderOpt = moduleBuilderOpt; } @@ -80,9 +83,8 @@ public NamedTypeSymbol Type get { // NOTE: currently it can be null if only private implementation type methods are compiled - // TODO: is it used? if yes, make sure it is not accessed when type is not available; - Debug.Assert((object)_type != null); - return _type; + Debug.Assert((object)_typeOpt != null); + return _typeOpt; } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index fea5886589b2a..0192c37f247d4 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -223,9 +223,8 @@ public PEAssemblyBuilder( OutputKind outputKind, ModulePropertiesForSerialization serializationProperties, IEnumerable manifestResources, - Func assemblySymbolMapper = null, - ImmutableArray additionalTypes = default(ImmutableArray)) - : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, assemblySymbolMapper, additionalTypes) + Func assemblySymbolMapper = null) + : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, assemblySymbolMapper, ImmutableArray.Empty) { } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 4fd8220a4b1c4..e0d032cbeda95 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -315,10 +315,10 @@ internal CommonPEModuleBuilder CompileGetLocals( } // Hoisted method parameters (represented as locals in the EE). - int ordinal = 0; if (!_hoistedParameterNames.IsEmpty) { - foreach (var local in _localsForBinding) + int localIndex = 0; + foreach(var local in _localsForBinding) { // Since we are showing hoisted method parameters first, the parameters may appear out of order // in the Locals window if only some of the parameters are hoisted. This is consistent with the @@ -326,36 +326,39 @@ internal CommonPEModuleBuilder CompileGetLocals( var localName = local.Name; if (_hoistedParameterNames.Contains(local.Name)) { - AppendLocalAndMethod(localBuilder, methodBuilder, localName, this.GetLocalMethod, container, ordinal, GetLocalResultFlags(local)); + AppendLocalAndMethod(localBuilder, methodBuilder, localName, this.GetLocalMethod, container, localIndex, GetLocalResultFlags(local)); } - ordinal++; + + localIndex++; } } // Method parameters (except those that have been hoisted). - ordinal = m.IsStatic ? 0 : 1; + int parameterIndex = m.IsStatic ? 0 : 1; foreach (var parameter in m.Parameters) { var parameterName = parameter.Name; if (!_hoistedParameterNames.Contains(parameterName)) { - AppendLocalAndMethod(localBuilder, methodBuilder, parameterName, this.GetParameterMethod, container, ordinal, DkmClrCompilationResultFlags.None); + AppendLocalAndMethod(localBuilder, methodBuilder, parameterName, this.GetParameterMethod, container, parameterIndex, DkmClrCompilationResultFlags.None); } - ordinal++; + + parameterIndex++; } if (!argumentsOnly) { // Locals. - ordinal = 0; + int localIndex = 0; foreach (var local in _localsForBinding) { var localName = local.Name; if (!_hoistedParameterNames.Contains(localName)) { - AppendLocalAndMethod(localBuilder, methodBuilder, localName, this.GetLocalMethod, container, ordinal, GetLocalResultFlags(local)); + AppendLocalAndMethod(localBuilder, methodBuilder, localName, this.GetLocalMethod, container, localIndex, GetLocalResultFlags(local)); } - ordinal++; + + localIndex++; } // "Type variables". @@ -401,7 +404,7 @@ private static void AppendLocalAndMethod( string name, Func getMethod, EENamedTypeSymbol container, - int ordinal, + int localOrParameterIndex, DkmClrCompilationResultFlags resultFlags) { // Note: The native EE doesn't do this, but if we don't escape keyword identifiers, @@ -409,7 +412,7 @@ private static void AppendLocalAndMethod( // which it can't do correctly without semantic information. name = SyntaxHelpers.EscapeKeywordIdentifiers(name); var methodName = GetNextMethodName(methodBuilder); - var method = getMethod(container, methodName, name, ordinal); + var method = getMethod(container, methodName, name, localOrParameterIndex); localBuilder.Add(new LocalAndMethod(name, methodName, resultFlags)); methodBuilder.Add(method); } @@ -446,23 +449,23 @@ internal EEMethodSymbol CreateMethod( generateMethodBody); } - private EEMethodSymbol GetLocalMethod(EENamedTypeSymbol container, string methodName, string localName, int index) + private EEMethodSymbol GetLocalMethod(EENamedTypeSymbol container, string methodName, string localName, int localIndex) { var syntax = SyntaxFactory.IdentifierName(localName); return this.CreateMethod(container, methodName, syntax, (method, diagnostics) => { - var local = method.LocalsForBinding[index]; + var local = method.LocalsForBinding[localIndex]; var expression = new BoundLocal(syntax, local, constantValueOpt: local.GetConstantValue(null, null, diagnostics), type: local.Type) { WasCompilerGenerated = true }; return new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true }; }); } - private EEMethodSymbol GetParameterMethod(EENamedTypeSymbol container, string methodName, string parameterName, int ordinal) + private EEMethodSymbol GetParameterMethod(EENamedTypeSymbol container, string methodName, string parameterName, int parameterIndex) { var syntax = SyntaxFactory.IdentifierName(parameterName); return this.CreateMethod(container, methodName, syntax, (method, diagnostics) => { - var parameter = method.Parameters[ordinal]; + var parameter = method.Parameters[parameterIndex]; var expression = new BoundParameter(syntax, parameter) { WasCompilerGenerated = true }; return new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true }; }); diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index de325e47410c0..64259534d85ab 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -19,6 +19,15 @@ namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator /// internal sealed class EEMethodSymbol : MethodSymbol { + // We only create a single EE method (per EE type) that represents an arbitrary expression, + // whose lowering may produce synthesized members (lambdas, dynamic sites, etc). + // We may thus assume that the method ordinal is always 0. + // + // Consider making the implementation more flexible in order to avoid this assumption. + // In future we might need to compile multiple expression and then we'll need to assign + // a unique method ordinal to each of them to avoid duplicate synthesized member names. + private const int _methodOrdinal = 0; + internal readonly TypeMap TypeMap; internal readonly MethodSymbol SubstitutedSourceMethod; internal readonly ImmutableArray Locals; @@ -31,6 +40,7 @@ internal sealed class EEMethodSymbol : MethodSymbol private readonly ImmutableArray _parameters; private readonly ParameterSymbol _thisParameter; private readonly ImmutableDictionary _displayClassVariables; + /// /// Invoked at most once to generate the method body. /// (If the compilation has no errors, it will be invoked @@ -472,7 +482,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, - methodOrdinal: 0, + methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, @@ -544,7 +554,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, - methodOrdinal: 0, + methodOrdinal: _methodOrdinal, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb index 1b42c478cc57d..87f34cce3305a 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb @@ -242,39 +242,43 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' Hoisted method parameters (represented as locals in the EE). - Dim ordinal As Integer = 0 If Not _hoistedParameterNames.IsEmpty Then + Dim localIndex As Integer = 0 + For Each local In _localsForBinding ' Since we are showing hoisted method parameters first, the parameters may appear out of order ' in the Locals window if only some of the parameters are hoisted. This is consistent with the ' behavior of the old EE. Dim localName = local.Name If _hoistedParameterNames.Contains(local.Name) Then - AppendLocalAndMethod(localBuilder, methodBuilder, localName, AddressOf Me.GetLocalMethod, container, ordinal, GetLocalResultFlags(local)) + AppendLocalAndMethod(localBuilder, methodBuilder, localName, AddressOf Me.GetLocalMethod, container, localIndex, GetLocalResultFlags(local)) End If - ordinal += 1 + + localIndex += 1 Next End If ' Method parameters (except those that have been hoisted). - ordinal = If(m.IsShared, 0, 1) + Dim parameterIndex = If(m.IsShared, 0, 1) For Each parameter In m.Parameters Dim parameterName = parameter.Name If Not _hoistedParameterNames.Contains(parameterName) Then - AppendLocalAndMethod(localBuilder, methodBuilder, parameterName, AddressOf Me.GetParameterMethod, container, ordinal, DkmClrCompilationResultFlags.None) + AppendLocalAndMethod(localBuilder, methodBuilder, parameterName, AddressOf Me.GetParameterMethod, container, parameterIndex, DkmClrCompilationResultFlags.None) End If - ordinal += 1 + + parameterIndex += 1 Next If Not argumentsOnly Then ' Locals. - ordinal = 0 + Dim localIndex As Integer = 0 For Each local In _localsForBinding Dim localName = local.Name If Not _hoistedParameterNames.Contains(localName) Then - AppendLocalAndMethod(localBuilder, methodBuilder, localName, AddressOf Me.GetLocalMethod, container, ordinal, GetLocalResultFlags(local)) + AppendLocalAndMethod(localBuilder, methodBuilder, localName, AddressOf Me.GetLocalMethod, container, localIndex, GetLocalResultFlags(local)) End If - ordinal += 1 + + localIndex += 1 Next ' "Type variables". @@ -319,7 +323,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator name As String, getMethod As Func(Of EENamedTypeSymbol, String, String, Integer, MethodSymbol), container As EENamedTypeSymbol, - ordinal As Integer, + localOrParameterIndex As Integer, resultFlags As DkmClrCompilationResultFlags) ' Note: The native EE doesn't do this, but if we don't escape keyword identifiers, @@ -327,7 +331,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ' which it can't do correctly without semantic information. name = SyntaxHelpers.EscapeKeywordIdentifiers(name) Dim methodName = GetNextMethodName(methodBuilder) - Dim method = getMethod(container, methodName, name, ordinal) + Dim method = getMethod(container, methodName, name, localOrParameterIndex) localBuilder.Add(New LocalAndMethod(name, methodName, resultFlags)) methodBuilder.Add(method) End Sub @@ -365,27 +369,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator generateMethodBody) End Function - Private Function GetLocalMethod(container As EENamedTypeSymbol, methodName As String, localName As String, index As Integer) As EEMethodSymbol + Private Function GetLocalMethod(container As EENamedTypeSymbol, methodName As String, localName As String, localIndex As Integer) As EEMethodSymbol Dim syntax = SyntaxFactory.IdentifierName(localName) Return Me.CreateMethod( container, methodName, syntax, Function(method, diagnostics) - Dim local = method.LocalsForBinding(index) + Dim local = method.LocalsForBinding(localIndex) Dim expression = New BoundLocal(syntax, local, isLValue:=False, type:=local.Type).MakeCompilerGenerated() Return New BoundReturnStatement(syntax, expression, Nothing, Nothing).MakeCompilerGenerated() End Function) End Function - Private Function GetParameterMethod(container As EENamedTypeSymbol, methodName As String, parameterName As String, index As Integer) As EEMethodSymbol + Private Function GetParameterMethod(container As EENamedTypeSymbol, methodName As String, parameterName As String, parameterIndex As Integer) As EEMethodSymbol Dim syntax = SyntaxFactory.IdentifierName(parameterName) Return Me.CreateMethod( container, methodName, syntax, Function(method, diagnostics) - Dim parameter = method.Parameters(index) + Dim parameter = method.Parameters(parameterIndex) Dim expression = New BoundParameter(syntax, parameter, isLValue:=False, type:=parameter.Type).MakeCompilerGenerated() Return New BoundReturnStatement(syntax, expression, Nothing, Nothing).MakeCompilerGenerated() End Function)