diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs index 06cc1e677fc46f52ba2c660193a676cea21468a7..95ae1bde8240fe4aaa85d6837c5aa0cd905bb6ba 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs @@ -34,13 +34,13 @@ void M1() }"; CreateCompilationWithMscorlib45(source) .VerifyDiagnostics() - .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new EmptyArrayOperationAnalyzer() }, null, null, false, - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0]").WithLocation(6, 22), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "{ }").WithLocation(7, 23), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "new C[] { }").WithLocation(8, 20), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][]").WithLocation(12, 24), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][][][]").WithLocation(13, 28), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][,]").WithLocation(15, 26) + .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new EmptyArrayAnalyzer() }, null, null, false, + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0]").WithLocation(6, 22), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "{ }").WithLocation(7, 23), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new C[] { }").WithLocation(8, 20), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][]").WithLocation(12, 24), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][][][]").WithLocation(13, 28), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0][,]").WithLocation(15, 26) ); } diff --git a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj index 808ecd8eecb05b83dd8a0ebca2b7d58b57b74b2f..6e030923cc3fff3004a6b7bc44ccb9d045a2317d 100644 --- a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj +++ b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj @@ -29,9 +29,10 @@ - + + - + @@ -184,4 +185,4 @@ - + \ No newline at end of file diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayOperationAnalyzer.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayAnalyzer.cs similarity index 90% rename from src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayOperationAnalyzer.cs rename to src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayAnalyzer.cs index 83184684c547eceb8466fd275e7018673d50016d..50c76d04c7941eb8d754f7bc1aea920effd8a45c 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayOperationAnalyzer.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/EmptyArrayAnalyzer.cs @@ -5,13 +5,12 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Semantics; -namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics +namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics.SystemLanguage { - /// Base type for an analyzer that looks for empty array allocations and recommends their replacement. - public class EmptyArrayOperationAnalyzer : DiagnosticAnalyzer + /// Analyzer that looks for empty array allocations and recommends their replacement. + public class EmptyArrayAnalyzer : DiagnosticAnalyzer { - /// Diagnostic category "Performance". - private const string PerformanceCategory = "Performance"; + private const string SystemCategory = "System"; /// The name of the array type. internal const string ArrayTypeName = "System.Array"; // using instead of GetSpecialType to make more testable @@ -27,7 +26,7 @@ public class EmptyArrayOperationAnalyzer : DiagnosticAnalyzer "EmptyArrayRule", localizableTitle, localizableMessage, - PerformanceCategory, + SystemCategory, DiagnosticSeverity.Warning, isEnabledByDefault: true); diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SystemLanguageAnalyzer.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/FieldCouldBeReadOnlyAnalyzer.cs similarity index 54% rename from src/Compilers/Core/CodeAnalysisTest/Diagnostics/SystemLanguageAnalyzer.cs rename to src/Compilers/Core/CodeAnalysisTest/Diagnostics/FieldCouldBeReadOnlyAnalyzer.cs index 7b94ab8ca1ac6ac0fb2d4cbf5dc04e10b725471b..aadcc7647c9667feb47112e0c77e0e63e8e5450c 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SystemLanguageAnalyzer.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/FieldCouldBeReadOnlyAnalyzer.cs @@ -132,118 +132,4 @@ void Report(CompilationAnalysisContext context, IFieldSymbol field, DiagnosticDe context.ReportDiagnostic(Diagnostic.Create(descriptor, field.Locations.FirstOrDefault())); } } - - /// Analyzer used to identify local variables that could be declared Const. - public class LocalCouldBeConstAnalyzer : DiagnosticAnalyzer - { - private const string SystemCategory = "System"; - - public static readonly DiagnosticDescriptor LocalCouldBeConstDescriptor = new DiagnosticDescriptor( - "LocalCouldBeReadOnly", - "Local Could Be Const", - "Local variable is never modified and so could be const.", - SystemCategory, - DiagnosticSeverity.Warning, - isEnabledByDefault: true); - - /// Gets the set of supported diagnostic descriptors from this analyzer. - public sealed override ImmutableArray SupportedDiagnostics - { - get { return ImmutableArray.Create(LocalCouldBeConstDescriptor); } - } - - public sealed override void Initialize(AnalysisContext context) - { - context.RegisterOperationBlockStartAction( - (operationBlockContext) => - { - IMethodSymbol containingMethod = operationBlockContext.OwningSymbol as IMethodSymbol; - - if (containingMethod != null) - { - HashSet mightBecomeConstLocals = new HashSet(); - HashSet assignedToLocals = new HashSet(); - - operationBlockContext.RegisterOperationAction( - (operationContext) => - { - IAssignmentExpression assignment = (IAssignmentExpression)operationContext.Operation; - AssignTo(assignment.Target, assignedToLocals, mightBecomeConstLocals); - }, - OperationKind.AssignmentExpression, - OperationKind.CompoundAssignmentExpression, - OperationKind.IncrementExpression); - - operationBlockContext.RegisterOperationAction( - (operationContext) => - { - IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation; - foreach (IArgument argument in invocation.ArgumentsInParameterOrder) - { - if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref) - { - AssignTo(argument.Value, assignedToLocals, mightBecomeConstLocals); - } - } - }, - OperationKind.InvocationExpression); - - operationBlockContext.RegisterOperationAction( - (operationContext) => - { - IVariableDeclarationStatement declaration = (IVariableDeclarationStatement)operationContext.Operation; - foreach (IVariable variable in declaration.Variables) - { - ILocalSymbol local = variable.Variable; - if (!local.IsConst) - { - var localType = local.Type; - if ((!localType.IsReferenceType || localType.SpecialType == SpecialType.System_String) && localType.SpecialType != SpecialType.None) - { - if (variable.InitialValue != null && variable.InitialValue.ConstantValue != null) - { - mightBecomeConstLocals.Add(local); - } - } - } - } - }, - OperationKind.VariableDeclarationStatement); - - operationBlockContext.RegisterOperationBlockEndAction( - (operationBlockEndContext) => - { - foreach (ILocalSymbol couldBeConstLocal in mightBecomeConstLocals) - { - Report(operationBlockEndContext, couldBeConstLocal, LocalCouldBeConstDescriptor); - } - }); - } - }); - } - - static void AssignTo(IExpression target, HashSet assignedToLocals, HashSet mightBecomeConstLocals) - { - if (target.Kind == OperationKind.LocalReferenceExpression) - { - ILocalSymbol targetLocal = ((ILocalReferenceExpression)target).Local; - - assignedToLocals.Add(targetLocal); - mightBecomeConstLocals.Remove(targetLocal); - } - else if (target.Kind == OperationKind.FieldReferenceExpression) - { - IFieldReferenceExpression fieldReference = (IFieldReferenceExpression)target; - if (fieldReference.Instance != null && fieldReference.Instance.ResultType.IsValueType) - { - AssignTo(fieldReference.Instance, assignedToLocals, mightBecomeConstLocals); - } - } - } - - void Report(OperationBlockAnalysisContext context, ILocalSymbol local, DiagnosticDescriptor descriptor) - { - context.ReportDiagnostic(Diagnostic.Create(descriptor, local.Locations.FirstOrDefault())); - } - } } \ No newline at end of file diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/LocalCouldBeConstAnalyzer.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/LocalCouldBeConstAnalyzer.cs new file mode 100644 index 0000000000000000000000000000000000000000..bdfb77734be01b20ac3245a984ef8f2146617694 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/LocalCouldBeConstAnalyzer.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Semantics; + +namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics.SystemLanguage +{ + /// Analyzer used to identify local variables that could be declared Const. + public class LocalCouldBeConstAnalyzer : DiagnosticAnalyzer + { + private const string SystemCategory = "System"; + + public static readonly DiagnosticDescriptor LocalCouldBeConstDescriptor = new DiagnosticDescriptor( + "LocalCouldBeReadOnly", + "Local Could Be Const", + "Local variable is never modified and so could be const.", + SystemCategory, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + /// Gets the set of supported diagnostic descriptors from this analyzer. + public sealed override ImmutableArray SupportedDiagnostics + { + get { return ImmutableArray.Create(LocalCouldBeConstDescriptor); } + } + + public sealed override void Initialize(AnalysisContext context) + { + context.RegisterOperationBlockStartAction( + (operationBlockContext) => + { + IMethodSymbol containingMethod = operationBlockContext.OwningSymbol as IMethodSymbol; + + if (containingMethod != null) + { + HashSet mightBecomeConstLocals = new HashSet(); + HashSet assignedToLocals = new HashSet(); + + operationBlockContext.RegisterOperationAction( + (operationContext) => + { + IAssignmentExpression assignment = (IAssignmentExpression)operationContext.Operation; + AssignTo(assignment.Target, assignedToLocals, mightBecomeConstLocals); + }, + OperationKind.AssignmentExpression, + OperationKind.CompoundAssignmentExpression, + OperationKind.IncrementExpression); + + operationBlockContext.RegisterOperationAction( + (operationContext) => + { + IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation; + foreach (IArgument argument in invocation.ArgumentsInParameterOrder) + { + if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref) + { + AssignTo(argument.Value, assignedToLocals, mightBecomeConstLocals); + } + } + }, + OperationKind.InvocationExpression); + + operationBlockContext.RegisterOperationAction( + (operationContext) => + { + IVariableDeclarationStatement declaration = (IVariableDeclarationStatement)operationContext.Operation; + foreach (IVariable variable in declaration.Variables) + { + ILocalSymbol local = variable.Variable; + if (!local.IsConst && !assignedToLocals.Contains(local)) + { + var localType = local.Type; + if ((!localType.IsReferenceType || localType.SpecialType == SpecialType.System_String) && localType.SpecialType != SpecialType.None) + { + if (variable.InitialValue != null && variable.InitialValue.ConstantValue != null) + { + mightBecomeConstLocals.Add(local); + } + } + } + } + }, + OperationKind.VariableDeclarationStatement); + + operationBlockContext.RegisterOperationBlockEndAction( + (operationBlockEndContext) => + { + foreach (ILocalSymbol couldBeConstLocal in mightBecomeConstLocals) + { + Report(operationBlockEndContext, couldBeConstLocal, LocalCouldBeConstDescriptor); + } + }); + } + }); + } + + static void AssignTo(IExpression target, HashSet assignedToLocals, HashSet mightBecomeConstLocals) + { + if (target.Kind == OperationKind.LocalReferenceExpression) + { + ILocalSymbol targetLocal = ((ILocalReferenceExpression)target).Local; + + assignedToLocals.Add(targetLocal); + mightBecomeConstLocals.Remove(targetLocal); + } + else if (target.Kind == OperationKind.FieldReferenceExpression) + { + IFieldReferenceExpression fieldReference = (IFieldReferenceExpression)target; + if (fieldReference.Instance != null && fieldReference.Instance.ResultType.IsValueType) + { + AssignTo(fieldReference.Instance, assignedToLocals, mightBecomeConstLocals); + } + } + } + + void Report(OperationBlockAnalysisContext context, ILocalSymbol local, DiagnosticDescriptor descriptor) + { + context.ReportDiagnostic(Diagnostic.Create(descriptor, local.Locations.FirstOrDefault())); + } + } +} \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb index 62e533a611f56c218fcd5c5d82ffbae3057b5f86..efabaca1c21e206e77fef6555882e5fa898f8939 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb @@ -39,13 +39,13 @@ End Class Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source) comp.VerifyDiagnostics() - comp.VerifyAnalyzerDiagnostics({New EmptyArrayOperationAnalyzer}, Nothing, Nothing, False, - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1) { }").WithLocation(3, 33), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "{ }").WithLocation(4, 30), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "New C(-1) { }").WithLocation(5, 27), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1)() { }").WithLocation(9, 35), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer( -1)()()() { }").WithLocation(10, 39), - Diagnostic(EmptyArrayOperationAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1)(,) { }").WithLocation(12, 37)) + comp.VerifyAnalyzerDiagnostics({New EmptyArrayAnalyzer}, Nothing, Nothing, False, + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1) { }").WithLocation(3, 33), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "{ }").WithLocation(4, 30), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "New C(-1) { }").WithLocation(5, 27), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1)() { }").WithLocation(9, 35), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer( -1)()()() { }").WithLocation(10, 39), + Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "New Integer(-1)(,) { }").WithLocation(12, 37)) End Sub