From 68bc8c8ecc4d2f606ac99a869fce2ff7b44881b7 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sat, 31 Oct 2020 12:15:33 -0700 Subject: [PATCH] Use IOperation APIs for SA1129 when supported --- .../ReadabilityRules/SA1129UnitTests.cs | 28 ++-- .../Lightup/IArgumentOperationWrapper.cs | 50 ++++++ .../IObjectCreationOperationWrapper.cs | 82 ++++++++++ ...OrCollectionInitializerOperationWrapper.cs | 62 ++++++++ .../Lightup/IOperationWrapper.cs | 32 ++++ ...ParameterObjectCreationOperationWrapper.cs | 61 ++++++++ .../Lightup/LanguageVersionEx.cs | 1 + .../Lightup/LightupHelpers.cs | 147 ++++++++++++++++++ .../Lightup/OperationKindEx.cs | 20 +++ .../Lightup/WrapperHelper.cs | 71 +++++---- ...1129DoNotUseDefaultValueTypeConstructor.cs | 55 ++++++- 11 files changed, 562 insertions(+), 47 deletions(-) create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IArgumentOperationWrapper.cs create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectCreationOperationWrapper.cs create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectOrCollectionInitializerOperationWrapper.cs create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IOperationWrapper.cs create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/ITypeParameterObjectCreationOperationWrapper.cs create mode 100644 StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs index 39d264dc0..d4aa7e48d 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs @@ -91,9 +91,9 @@ public async Task VerifyInvalidValueTypeCreationAsync() { public void TestMethod() { - var v1 = new TestStruct(); + var v1 = {|#0:new TestStruct()|}; - System.Console.WriteLine(new TestStruct()); + System.Console.WriteLine({|#1:new TestStruct()|}); } private struct TestStruct @@ -121,8 +121,8 @@ private struct TestStruct DiagnosticResult[] expected = { - Diagnostic().WithLocation(5, 18), - Diagnostic().WithLocation(7, 34), + Diagnostic().WithLocation(0), + Diagnostic().WithLocation(1), }; await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false); @@ -139,11 +139,11 @@ public async Task VerifyTriviaPreservationAsync() { public void TestMethod() { - var v1 = /* c1 */ new TestStruct(); // c2 + var v1 = /* c1 */ {|#0:new TestStruct()|}; // c2 var v2 = #if true - new TestStruct(); + {|#1:new TestStruct()|}; #else new TestStruct() { TestProperty = 3 }; #endif @@ -179,8 +179,8 @@ private struct TestStruct DiagnosticResult[] expected = { - Diagnostic().WithLocation(5, 27), - Diagnostic().WithLocation(9, 13), + Diagnostic().WithLocation(0), + Diagnostic().WithLocation(1), }; await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false); @@ -198,7 +198,7 @@ public async Task VerifyGenericsTypeCreationAsync() public T TestMethod1() where T : struct { - return new T(); + return {|#0:new T()|}; } public T TestMethod2() @@ -227,7 +227,7 @@ public T TestMethod2() DiagnosticResult[] expected = { - Diagnostic().WithLocation(6, 16), + Diagnostic().WithLocation(0), }; await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false); @@ -451,7 +451,7 @@ public async Task VerifyEnumMemberReplacementBehaviorAsync(string declarationBod {{ public void TestMethod() {{ - var v1 = new MyEnum(); + var v1 = {{|#0:new MyEnum()|}}; }} private enum MyEnum {{ {declarationBody} }} @@ -469,7 +469,7 @@ private enum MyEnum {{ {declarationBody} }} DiagnosticResult[] expected = { - Diagnostic().WithLocation(5, 18), + Diagnostic().WithLocation(0), }; await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false); @@ -492,7 +492,7 @@ public async Task VerifyEnumMemberDefaultBehaviorAsync(string declarationBody) {{ public void TestMethod() {{ - var v1 = new MyEnum(); + var v1 = {{|#0:new MyEnum()|}}; }} private enum MyEnum {{ {declarationBody} }} @@ -510,7 +510,7 @@ private enum MyEnum {{ {declarationBody} }} DiagnosticResult[] expected = { - Diagnostic().WithLocation(5, 18), + Diagnostic().WithLocation(0), }; await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false); diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IArgumentOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IArgumentOperationWrapper.cs new file mode 100644 index 000000000..e96f617a5 --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IArgumentOperationWrapper.cs @@ -0,0 +1,50 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace StyleCop.Analyzers.Lightup +{ + using System; + using Microsoft.CodeAnalysis; + + internal readonly struct IArgumentOperationWrapper : IOperationWrapper + { + internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IArgumentOperation"; + private static readonly Type WrappedType; + + private readonly IOperation operation; + + static IArgumentOperationWrapper() + { + WrappedType = WrapperHelper.GetWrappedType(typeof(IObjectCreationOperationWrapper)); + } + + private IArgumentOperationWrapper(IOperation operation) + { + this.operation = operation; + } + + public IOperation WrappedOperation => this.operation; + + public ITypeSymbol Type => this.WrappedOperation.Type; + + public static IArgumentOperationWrapper FromOperation(IOperation operation) + { + if (operation == null) + { + return default; + } + + if (!IsInstance(operation)) + { + throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'"); + } + + return new IArgumentOperationWrapper(operation); + } + + public static bool IsInstance(IOperation operation) + { + return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType); + } + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectCreationOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectCreationOperationWrapper.cs new file mode 100644 index 000000000..88a20b747 --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectCreationOperationWrapper.cs @@ -0,0 +1,82 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace StyleCop.Analyzers.Lightup +{ + using System; + using System.Collections.Immutable; + using Microsoft.CodeAnalysis; + + internal readonly struct IObjectCreationOperationWrapper : IOperationWrapper + { + internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IObjectCreationOperation"; + private static readonly Type WrappedType; + + private static readonly Func ConstructorAccessor; + private static readonly Func InitializerAccessor; + private static readonly Func> ArgumentsAccessor; + + private readonly IOperation operation; + + static IObjectCreationOperationWrapper() + { + WrappedType = WrapperHelper.GetWrappedType(typeof(IObjectCreationOperationWrapper)); + ConstructorAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Constructor)); + InitializerAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Initializer)); + ArgumentsAccessor = LightupHelpers.CreateOperationListPropertyAccessor(WrappedType, nameof(Arguments)); + } + + private IObjectCreationOperationWrapper(IOperation operation) + { + this.operation = operation; + } + + public IOperation WrappedOperation => this.operation; + + public ITypeSymbol Type => this.WrappedOperation.Type; + + public IMethodSymbol Constructor + { + get + { + return ConstructorAccessor(this.WrappedOperation); + } + } + + public IObjectOrCollectionInitializerOperationWrapper Initializer + { + get + { + return IObjectOrCollectionInitializerOperationWrapper.FromOperation(InitializerAccessor(this.WrappedOperation)); + } + } + + public ImmutableArray Arguments + { + get + { + return ArgumentsAccessor(this.WrappedOperation); + } + } + + public static IObjectCreationOperationWrapper FromOperation(IOperation operation) + { + if (operation == null) + { + return default; + } + + if (!IsInstance(operation)) + { + throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'"); + } + + return new IObjectCreationOperationWrapper(operation); + } + + public static bool IsInstance(IOperation operation) + { + return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType); + } + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectOrCollectionInitializerOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectOrCollectionInitializerOperationWrapper.cs new file mode 100644 index 000000000..8539b275e --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IObjectOrCollectionInitializerOperationWrapper.cs @@ -0,0 +1,62 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace StyleCop.Analyzers.Lightup +{ + using System; + using System.Collections.Immutable; + using Microsoft.CodeAnalysis; + + internal readonly struct IObjectOrCollectionInitializerOperationWrapper : IOperationWrapper + { + internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IObjectOrCollectionInitializerOperation"; + private static readonly Type WrappedType; + + private static readonly Func> InitializersAccessor; + + private readonly IOperation operation; + + static IObjectOrCollectionInitializerOperationWrapper() + { + WrappedType = WrapperHelper.GetWrappedType(typeof(IObjectOrCollectionInitializerOperationWrapper)); + InitializersAccessor = LightupHelpers.CreateOperationPropertyAccessor>(WrappedType, nameof(Initializers)); + } + + private IObjectOrCollectionInitializerOperationWrapper(IOperation operation) + { + this.operation = operation; + } + + public IOperation WrappedOperation => this.operation; + + public ITypeSymbol Type => this.WrappedOperation.Type; + + public ImmutableArray Initializers + { + get + { + return InitializersAccessor(this.WrappedOperation); + } + } + + public static IObjectOrCollectionInitializerOperationWrapper FromOperation(IOperation operation) + { + if (operation == null) + { + return default; + } + + if (!IsInstance(operation)) + { + throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'"); + } + + return new IObjectOrCollectionInitializerOperationWrapper(operation); + } + + public static bool IsInstance(IOperation operation) + { + return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType); + } + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IOperationWrapper.cs new file mode 100644 index 000000000..29f1f7eb6 --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/IOperationWrapper.cs @@ -0,0 +1,32 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#nullable enable + +namespace StyleCop.Analyzers.Lightup +{ + using Microsoft.CodeAnalysis; + + internal interface IOperationWrapper + { + IOperation? WrappedOperation { get; } + + ////IOperationWrapper Parent { get; } + + ////OperationKind Kind { get; } + + ////SyntaxNode Syntax { get; } + + ITypeSymbol? Type { get; } + + ////Optional ConstantValue { get; } + + ////IEnumerable Children { get; } + + ////string Language { get; } + + ////bool IsImplicit { get; } + + ////SemanticModel SemanticModel { get; } + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/ITypeParameterObjectCreationOperationWrapper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/ITypeParameterObjectCreationOperationWrapper.cs new file mode 100644 index 000000000..928591b67 --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/ITypeParameterObjectCreationOperationWrapper.cs @@ -0,0 +1,61 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace StyleCop.Analyzers.Lightup +{ + using System; + using Microsoft.CodeAnalysis; + + internal readonly struct ITypeParameterObjectCreationOperationWrapper : IOperationWrapper + { + internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.ITypeParameterObjectCreationOperation"; + private static readonly Type WrappedType; + + private static readonly Func InitializerAccessor; + + private readonly IOperation operation; + + static ITypeParameterObjectCreationOperationWrapper() + { + WrappedType = WrapperHelper.GetWrappedType(typeof(ITypeParameterObjectCreationOperationWrapper)); + InitializerAccessor = LightupHelpers.CreateOperationPropertyAccessor(WrappedType, nameof(Initializer)); + } + + private ITypeParameterObjectCreationOperationWrapper(IOperation operation) + { + this.operation = operation; + } + + public IOperation WrappedOperation => this.operation; + + public ITypeSymbol Type => this.WrappedOperation.Type; + + public IObjectOrCollectionInitializerOperationWrapper Initializer + { + get + { + return IObjectOrCollectionInitializerOperationWrapper.FromOperation(InitializerAccessor(this.WrappedOperation)); + } + } + + public static ITypeParameterObjectCreationOperationWrapper FromOperation(IOperation operation) + { + if (operation == null) + { + return default; + } + + if (!IsInstance(operation)) + { + throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'"); + } + + return new ITypeParameterObjectCreationOperationWrapper(operation); + } + + public static bool IsInstance(IOperation operation) + { + return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType); + } + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LanguageVersionEx.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LanguageVersionEx.cs index ff15d5345..e1c8986d8 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LanguageVersionEx.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LanguageVersionEx.cs @@ -15,6 +15,7 @@ internal static class LanguageVersionEx public const LanguageVersion CSharp7_2 = (LanguageVersion)702; public const LanguageVersion CSharp7_3 = (LanguageVersion)703; public const LanguageVersion CSharp8 = (LanguageVersion)800; + public const LanguageVersion CSharp9 = (LanguageVersion)900; public const LanguageVersion LatestMajor = (LanguageVersion)int.MaxValue - 2; public const LanguageVersion Preview = (LanguageVersion)int.MaxValue - 1; public const LanguageVersion Latest = (LanguageVersion)int.MaxValue; diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LightupHelpers.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LightupHelpers.cs index 9515d3092..b3af49584 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LightupHelpers.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/LightupHelpers.cs @@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Lightup { using System; using System.Collections.Concurrent; + using System.Collections.Immutable; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -16,6 +17,9 @@ internal static class LightupHelpers private static readonly ConcurrentDictionary> SupportedWrappers = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> SupportedOperationWrappers + = new ConcurrentDictionary>(); + public static bool SupportsCSharp7 { get; } = Enum.GetNames(typeof(LanguageVersion)).Contains(nameof(LanguageVersionEx.CSharp7)); @@ -28,6 +32,14 @@ private static readonly ConcurrentDictionary SupportsCSharp73; + internal static bool CanWrapNode(SyntaxNode node, Type underlyingType) { if (node == null) @@ -56,6 +68,141 @@ internal static bool CanWrapNode(SyntaxNode node, Type underlyingType) return canCast; } + internal static bool CanWrapOperation(IOperation operation, Type underlyingType) + { + if (operation == null) + { + // The wrappers support a null instance + return true; + } + + if (underlyingType == null) + { + // The current runtime doesn't define the target type of the conversion, so no instance of it can exist + return false; + } + + ConcurrentDictionary wrappedSyntax = SupportedOperationWrappers.GetOrAdd(underlyingType, _ => new ConcurrentDictionary()); + + // Avoid creating the delegate if the value already exists + bool canCast; + if (!wrappedSyntax.TryGetValue(operation.Kind, out canCast)) + { + canCast = wrappedSyntax.GetOrAdd( + operation.Kind, + kind => underlyingType.GetTypeInfo().IsAssignableFrom(operation.GetType().GetTypeInfo())); + } + + return canCast; + } + + internal static Func CreateOperationPropertyAccessor(Type type, string propertyName) + { + TProperty FallbackAccessor(TOperation syntax) + { + if (syntax == null) + { + // Unlike an extension method which would throw ArgumentNullException here, the light-up + // behavior needs to match behavior of the underlying property. + throw new NullReferenceException(); + } + + return default; + } + + if (type == null) + { + return FallbackAccessor; + } + + if (!typeof(TOperation).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) + { + throw new InvalidOperationException(); + } + + var property = type.GetTypeInfo().GetDeclaredProperty(propertyName); + if (property == null) + { + return FallbackAccessor; + } + + if (!typeof(TProperty).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo())) + { + throw new InvalidOperationException(); + } + + var operationParameter = Expression.Parameter(typeof(TOperation), "operation"); + Expression instance = + type.GetTypeInfo().IsAssignableFrom(typeof(TOperation).GetTypeInfo()) + ? (Expression)operationParameter + : Expression.Convert(operationParameter, type); + + Expression> expression = + Expression.Lambda>( + Expression.Call(instance, property.GetMethod), + operationParameter); + return expression.Compile(); + } + + internal static Func> CreateOperationListPropertyAccessor(Type type, string propertyName) + { + ImmutableArray FallbackAccessor(TOperation syntax) + { + if (syntax == null) + { + // Unlike an extension method which would throw ArgumentNullException here, the light-up + // behavior needs to match behavior of the underlying property. + throw new NullReferenceException(); + } + + return ImmutableArray.Empty; + } + + if (type == null) + { + return FallbackAccessor; + } + + if (!typeof(TOperation).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) + { + throw new InvalidOperationException(); + } + + var property = type.GetTypeInfo().GetDeclaredProperty(propertyName); + if (property == null) + { + return FallbackAccessor; + } + + if (property.PropertyType.GetGenericTypeDefinition() != typeof(ImmutableArray<>)) + { + throw new InvalidOperationException(); + } + + var propertyOperationType = property.PropertyType.GenericTypeArguments[0]; + + if (!typeof(IOperation).GetTypeInfo().IsAssignableFrom(propertyOperationType.GetTypeInfo())) + { + throw new InvalidOperationException(); + } + + var syntaxParameter = Expression.Parameter(typeof(TOperation), "syntax"); + Expression instance = + type.GetTypeInfo().IsAssignableFrom(typeof(TOperation).GetTypeInfo()) + ? (Expression)syntaxParameter + : Expression.Convert(syntaxParameter, type); + Expression propertyAccess = Expression.Call(instance, property.GetMethod); + + var unboundCastUpMethod = typeof(ImmutableArray).GetTypeInfo().GetDeclaredMethod(nameof(ImmutableArray.CastUp)); + var boundCastUpMethod = unboundCastUpMethod.MakeGenericMethod(propertyOperationType); + + Expression>> expression = + Expression.Lambda>>( + Expression.Call(boundCastUpMethod, propertyAccess), + syntaxParameter); + return expression.Compile(); + } + internal static Func CreateSyntaxPropertyAccessor(Type type, string propertyName) { TProperty FallbackAccessor(TSyntax syntax) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs new file mode 100644 index 000000000..ac22f7fc9 --- /dev/null +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/OperationKindEx.cs @@ -0,0 +1,20 @@ +// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace StyleCop.Analyzers.Lightup +{ + using Microsoft.CodeAnalysis; + + internal static class OperationKindEx + { + /// + /// Indicates an . + /// + public const OperationKind ObjectCreation = (OperationKind)36; + + /// + /// Indicates an . + /// + public const OperationKind TypeParameterObjectCreation = (OperationKind)37; + } +} diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs index deffecc00..f58421c45 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/Lightup/WrapperHelper.cs @@ -6,6 +6,7 @@ namespace StyleCop.Analyzers.Lightup using System; using System.Collections.Immutable; using System.Reflection; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; internal static class WrapperHelper @@ -14,45 +15,51 @@ internal static class WrapperHelper static WrapperHelper() { - var codeAnalysisAssembly = typeof(CSharpSyntaxNode).GetTypeInfo().Assembly; + var csharpCodeAnalysisAssembly = typeof(CSharpSyntaxNode).GetTypeInfo().Assembly; + var codeAnalysisAssembly = typeof(SyntaxNode).GetTypeInfo().Assembly; var builder = ImmutableDictionary.CreateBuilder(); - builder.Add(typeof(CasePatternSwitchLabelSyntaxWrapper), codeAnalysisAssembly.GetType(CasePatternSwitchLabelSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(CasePatternSwitchLabelSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(CasePatternSwitchLabelSyntaxWrapper.WrappedTypeName)); // Prior to C# 7, ForEachStatementSyntax was the base type for all foreach statements. If // the CommonForEachStatementSyntax type isn't found at runtime, we fall back to using this type instead. - var forEachStatementSyntaxType = codeAnalysisAssembly.GetType(CommonForEachStatementSyntaxWrapper.WrappedTypeName) - ?? codeAnalysisAssembly.GetType(CommonForEachStatementSyntaxWrapper.FallbackWrappedTypeName); + var forEachStatementSyntaxType = csharpCodeAnalysisAssembly.GetType(CommonForEachStatementSyntaxWrapper.WrappedTypeName) + ?? csharpCodeAnalysisAssembly.GetType(CommonForEachStatementSyntaxWrapper.FallbackWrappedTypeName); builder.Add(typeof(CommonForEachStatementSyntaxWrapper), forEachStatementSyntaxType); - builder.Add(typeof(ConstantPatternSyntaxWrapper), codeAnalysisAssembly.GetType(ConstantPatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(DeclarationExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(DeclarationExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(DeclarationPatternSyntaxWrapper), codeAnalysisAssembly.GetType(DeclarationPatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(DiscardDesignationSyntaxWrapper), codeAnalysisAssembly.GetType(DiscardDesignationSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(DiscardPatternSyntaxWrapper), codeAnalysisAssembly.GetType(DiscardPatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(ForEachVariableStatementSyntaxWrapper), codeAnalysisAssembly.GetType(ForEachVariableStatementSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(IsPatternExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(IsPatternExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(ImplicitStackAllocArrayCreationExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(ImplicitStackAllocArrayCreationExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(LocalFunctionStatementSyntaxWrapper), codeAnalysisAssembly.GetType(LocalFunctionStatementSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(ParenthesizedVariableDesignationSyntaxWrapper), codeAnalysisAssembly.GetType(ParenthesizedVariableDesignationSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(PatternSyntaxWrapper), codeAnalysisAssembly.GetType(PatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(PositionalPatternClauseSyntaxWrapper), codeAnalysisAssembly.GetType(PositionalPatternClauseSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(PropertyPatternClauseSyntaxWrapper), codeAnalysisAssembly.GetType(PropertyPatternClauseSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(RangeExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(RangeExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(RecursivePatternSyntaxWrapper), codeAnalysisAssembly.GetType(RecursivePatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(RefExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(RefExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(RefTypeSyntaxWrapper), codeAnalysisAssembly.GetType(RefTypeSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(SingleVariableDesignationSyntaxWrapper), codeAnalysisAssembly.GetType(SingleVariableDesignationSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(SubpatternSyntaxWrapper), codeAnalysisAssembly.GetType(SubpatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(SwitchExpressionArmSyntaxWrapper), codeAnalysisAssembly.GetType(SwitchExpressionArmSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(SwitchExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(SwitchExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(ThrowExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(ThrowExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(TupleElementSyntaxWrapper), codeAnalysisAssembly.GetType(TupleElementSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(TupleExpressionSyntaxWrapper), codeAnalysisAssembly.GetType(TupleExpressionSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(TupleTypeSyntaxWrapper), codeAnalysisAssembly.GetType(TupleTypeSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(VarPatternSyntaxWrapper), codeAnalysisAssembly.GetType(VarPatternSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(VariableDesignationSyntaxWrapper), codeAnalysisAssembly.GetType(VariableDesignationSyntaxWrapper.WrappedTypeName)); - builder.Add(typeof(WhenClauseSyntaxWrapper), codeAnalysisAssembly.GetType(WhenClauseSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(ConstantPatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(ConstantPatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(DeclarationExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(DeclarationExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(DeclarationPatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(DeclarationPatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(DiscardDesignationSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(DiscardDesignationSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(DiscardPatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(DiscardPatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(ForEachVariableStatementSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(ForEachVariableStatementSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(IsPatternExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(IsPatternExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(ImplicitStackAllocArrayCreationExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(ImplicitStackAllocArrayCreationExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(LocalFunctionStatementSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(LocalFunctionStatementSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(ParenthesizedVariableDesignationSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(ParenthesizedVariableDesignationSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(PatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(PatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(PositionalPatternClauseSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(PositionalPatternClauseSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(PropertyPatternClauseSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(PropertyPatternClauseSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(RangeExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(RangeExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(RecursivePatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(RecursivePatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(RefExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(RefExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(RefTypeSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(RefTypeSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(SingleVariableDesignationSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(SingleVariableDesignationSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(SubpatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(SubpatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(SwitchExpressionArmSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(SwitchExpressionArmSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(SwitchExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(SwitchExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(ThrowExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(ThrowExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(TupleElementSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(TupleElementSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(TupleExpressionSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(TupleExpressionSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(TupleTypeSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(TupleTypeSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(VarPatternSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(VarPatternSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(VariableDesignationSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(VariableDesignationSyntaxWrapper.WrappedTypeName)); + builder.Add(typeof(WhenClauseSyntaxWrapper), csharpCodeAnalysisAssembly.GetType(WhenClauseSyntaxWrapper.WrappedTypeName)); + + builder.Add(typeof(IArgumentOperationWrapper), codeAnalysisAssembly.GetType(IArgumentOperationWrapper.WrappedTypeName)); + builder.Add(typeof(IObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(IObjectCreationOperationWrapper.WrappedTypeName)); + builder.Add(typeof(IObjectOrCollectionInitializerOperationWrapper), codeAnalysisAssembly.GetType(IObjectOrCollectionInitializerOperationWrapper.WrappedTypeName)); + builder.Add(typeof(ITypeParameterObjectCreationOperationWrapper), codeAnalysisAssembly.GetType(ITypeParameterObjectCreationOperationWrapper.WrappedTypeName)); WrappedTypes = builder.ToImmutable(); } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1129DoNotUseDefaultValueTypeConstructor.cs b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1129DoNotUseDefaultValueTypeConstructor.cs index 2e8267500..8b80f0670 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1129DoNotUseDefaultValueTypeConstructor.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1129DoNotUseDefaultValueTypeConstructor.cs @@ -9,6 +9,7 @@ namespace StyleCop.Analyzers.ReadabilityRules using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; + using StyleCop.Analyzers.Lightup; /// /// A value type was constructed using the syntax new T(). @@ -28,6 +29,8 @@ internal class SA1129DoNotUseDefaultValueTypeConstructor : DiagnosticAnalyzer private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink); + private static readonly Action ObjectCreationOperationAction = HandleObjectCreationOperation; + private static readonly Action TypeParameterObjectCreationOperationAction = HandleTypeParameterObjectCreationOperation; private static readonly Action ObjectCreationExpressionAction = HandleObjectCreationExpression; /// @@ -40,7 +43,57 @@ public override void Initialize(AnalysisContext context) context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); - context.RegisterSyntaxNodeAction(ObjectCreationExpressionAction, SyntaxKind.ObjectCreationExpression); + if (LightupHelpers.SupportsIOperation) + { + context.RegisterOperationAction(ObjectCreationOperationAction, OperationKindEx.ObjectCreation); + context.RegisterOperationAction(TypeParameterObjectCreationOperationAction, OperationKindEx.TypeParameterObjectCreation); + } + else + { + context.RegisterSyntaxNodeAction(ObjectCreationExpressionAction, SyntaxKind.ObjectCreationExpression); + } + } + + private static void HandleObjectCreationOperation(OperationAnalysisContext context) + { + var objectCreation = IObjectCreationOperationWrapper.FromOperation(context.Operation); + + var typeToCreate = objectCreation.Constructor.ContainingType; + if ((typeToCreate == null) || typeToCreate.IsReferenceType || IsReferenceTypeParameter(typeToCreate)) + { + return; + } + + if (!objectCreation.Arguments.IsEmpty) + { + // Not a use of the default constructor + return; + } + + if (objectCreation.Initializer.WrappedOperation != null) + { + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, objectCreation.WrappedOperation.Syntax.GetLocation())); + } + + private static void HandleTypeParameterObjectCreationOperation(OperationAnalysisContext context) + { + var objectCreation = ITypeParameterObjectCreationOperationWrapper.FromOperation(context.Operation); + + var typeToCreate = objectCreation.Type; + if ((typeToCreate == null) || typeToCreate.IsReferenceType || IsReferenceTypeParameter(typeToCreate)) + { + return; + } + + if (objectCreation.Initializer.WrappedOperation != null) + { + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, objectCreation.WrappedOperation.Syntax.GetLocation())); } private static void HandleObjectCreationExpression(SyntaxNodeAnalysisContext context)