/// <summary>Called once at compilation start to register actions in the compilation context.</summary> /// <param name="context">The analysis context.</param> internal void RegisterOperationAction(CompilationStartAnalysisContext context) { context.RegisterOperationAction( (operationContext) => { IArrayCreationExpression arrayCreation = (IArrayCreationExpression)operationContext.Operation; // ToDo: Need to suppress analysis of array creation expressions within attribute applications. // Detect array creation expression that have rank 1 and size 0. Such expressions // can be replaced with Array.Empty<T>(), provided that the element type can be a generic type argument. if (arrayCreation.DimensionSizes.Length == 1 //// Pointer types can't be generic type arguments. && arrayCreation.ElementType.TypeKind != TypeKind.Pointer) { Optional <object> arrayLength = arrayCreation.DimensionSizes[0].ConstantValue; if (arrayLength.HasValue && arrayLength.Value is int && (int)arrayLength.Value == 0) { Report(operationContext, arrayCreation.Syntax); } } }, OperationKind.ArrayCreationExpression); }
private void AnalyzeOperation(OperationAnalysisContext context) { IArrayCreationExpression arrayCreationExpression = context.Operation as IArrayCreationExpression; // We can't replace array allocations in attributes, as they're persisted to metadata // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check. if (arrayCreationExpression.Syntax.Ancestors().Any(IsAttributeSyntax)) { return; } if (arrayCreationExpression.DimensionSizes.Length == 1) { IOperation dimensionSize = arrayCreationExpression.DimensionSizes[0]; if (dimensionSize.HasConstantValue(0)) { // Workaround for https://github.com/dotnet/roslyn/issues/10214 // Bail out for compiler generated param array creation. if (IsCompilerGeneratedParamsArray(arrayCreationExpression, context)) { return; } // pointers can't be used as generic arguments if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer) { context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor)); } } } }
private static IArrayCreationExpression CreateArrayCreationExpression(IType elementType, CSharpElementFactory factory) { IArrayCreationExpression expression = (IArrayCreationExpression)factory.CreateExpression("new[]{}", new object[0]); IArrayType arrayType = TypeFactory.CreateArrayType(elementType, 1, null); return(factory.CreateArrayCreationExpression(arrayType, expression.ArrayInitializer)); }
private static bool IsCompilerGeneratedParamsArray(IArrayCreationExpression arrayCreationExpression, OperationAnalysisContext context) { var model = context.Compilation.GetSemanticModel(arrayCreationExpression.Syntax.SyntaxTree); // Compiler generated array creation seems to just use the syntax from the parent. var parent = model.GetOperationInternal(arrayCreationExpression.Syntax, context.CancellationToken) as IInvocationExpression; if (parent?.TargetMethod == null || parent.TargetMethod.Parameters.Length == 0) { return(false); } if (!parent.TargetMethod.Parameters.Last().IsParams) { return(false); } // At this point the array creation is known to be compiler synthesized as part of a call // to a method with a params parameter, and so it is probably sound to return true at this point. // As a sanity check, verify that the last argument to the call is equivalent to the array creation. // (Comparing for object identity does not work because the semantic model can return a fresh operation tree.) var lastArgument = parent.ArgumentsInParameterOrder.LastOrDefault(); return(lastArgument != null && lastArgument.Value.Syntax == arrayCreationExpression.Syntax && AreEquivalentZeroLengthArrayCreations(arrayCreationExpression, lastArgument.Value as IArrayCreationExpression)); }
private void AnalyzeOperation(OperationAnalysisContext context) { IArrayCreationExpression arrayCreationExpression = context.Operation as IArrayCreationExpression; // We can't replace array allocations in attributes, as they're persisted to metadata // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check. if (arrayCreationExpression.Syntax.Ancestors().Any(IsAttributeSyntax)) { return; } if (arrayCreationExpression.DimensionSizes.Length == 1) { IOperation dimensionSize = arrayCreationExpression.DimensionSizes[0]; if (dimensionSize.ConstantValue.HasValue && (int)dimensionSize.ConstantValue.Value == 0) { // pointers can't be used as generic arguments if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer) { context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor)); } } } }
public override void VisitArrayCreationExpression(IArrayCreationExpression operation) { LogString(nameof(IArrayCreationExpression)); LogString($" (Dimension sizes: {operation.DimensionSizes.Length}, Element Type: {operation.ElementType?.ToTestDisplayString()})"); LogCommonPropertiesAndNewLine(operation); base.VisitArrayCreationExpression(operation); }
/// <summary> /// Swap to built in type alias. /// </summary> /// <param name="node"> /// The node to process. /// </param> public static void SwapToBuiltInTypeAlias(ITreeNode node) { for (ITreeNode currentNode = node; currentNode != null; currentNode = currentNode.NextSibling) { ITypeArgumentList typeArgumentListNode = currentNode as ITypeArgumentList; if (typeArgumentListNode != null) { SwapGenericDeclarationToBuiltInType(typeArgumentListNode); } else { IMethodDeclaration methodDeclarationNode = currentNode as IMethodDeclaration; if (methodDeclarationNode != null) { SwapReturnTypeToBuiltInType(methodDeclarationNode); } else { IVariableDeclaration variableDeclaration = currentNode as IVariableDeclaration; if (variableDeclaration != null) { SwapVariableDeclarationToBuiltInType(variableDeclaration); } else { IObjectCreationExpression creationExpressionNode = currentNode as IObjectCreationExpression; if (creationExpressionNode != null) { //// No need to call this now and its messing up nested {} //// SwapObjectCreationToBuiltInType(creationExpressionNode); } else { IArrayCreationExpression arrayCreationNode = currentNode as IArrayCreationExpression; if (arrayCreationNode != null) { SwapArrayCreationToBuiltInType(arrayCreationNode); } else { IReferenceExpression referenceExpressionNode = currentNode as IReferenceExpression; if (referenceExpressionNode != null) { SwapReferenceExpressionToBuiltInType(referenceExpressionNode); } } } } } } if (currentNode != null && currentNode.FirstChild != null) { SwapToBuiltInTypeAlias(currentNode.FirstChild); } } }
public override void VisitArrayCreationExpression(IArrayCreationExpression operation) { LogString(nameof(IArrayCreationExpression)); LogString($" (Element Type: {operation.ElementType?.ToTestDisplayString()})"); LogCommonPropertiesAndNewLine(operation); VisitArray(operation.DimensionSizes, "Dimension Sizes", logElementCount: true); Visit(operation.Initializer, "Initializer"); }
public InefficientMultidimensionalArrayUsageQuickFix(InefficientMultidimensionalArrayUsageWarning warning) { myWarning = warning; myVariableDeclaration = warning.VariableDeclaration; myTreeNodePointers = warning.Usages; myArrayCreationExpression = warning.ArrayCreationExpression; myType = (myVariableDeclaration.Type as IArrayType).NotNull("type != null"); myMultipleDeclaration = warning.MultiplyDeclaration; }
private static void CheckArrayCreation( [NotNull] IArrayCreationExpression arrayCreation, [NotNull] IHighlightingConsumer consumer) { if (arrayCreation.GetContainingNode <IAttribute>() == null) { var newKeyword = arrayCreation.NewKeyword.NotNull(); consumer.AddHighlighting( new ObjectAllocationHighlighting(newKeyword, "array creation"), newKeyword.GetDocumentRange()); } }
private static void CheckArrayCreation([NotNull] IArrayCreationExpression arrayCreation, [NotNull] IHighlightingConsumer consumer) { if (arrayCreation.IsInTheContextWhereAllocationsAreNotImportant()) { return; } var newKeyword = arrayCreation.NewKeyword.NotNull(); consumer.AddHighlighting( new ObjectAllocationEvidentHighlighting(newKeyword, "array creation"), newKeyword.GetDocumentRange()); }
private static bool IsCompilerGeneratedParamsArray(IArrayCreationExpression arrayCreationExpression, OperationAnalysisContext context) { var model = context.Compilation.GetSemanticModel(arrayCreationExpression.Syntax.SyntaxTree); // Compiler generated array creation seems to just use the syntax from the parent. var parent = model.GetOperationInternal(arrayCreationExpression.Syntax, context.CancellationToken) as IHasArgumentsExpression; if (parent == null) { return(false); } ISymbol targetSymbol; if (parent is IInvocationExpression invocation) { targetSymbol = invocation.TargetMethod; } else { if (parent is IObjectCreationExpression objectCreation) { targetSymbol = objectCreation.Constructor; } else { targetSymbol = (parent as IIndexedPropertyReferenceExpression)?.Property; } } if (targetSymbol == null) { return(false); } var parameters = targetSymbol.GetParameters(); if (parameters.Length == 0 || !parameters[parameters.Length - 1].IsParams) { return(false); } // At this point the array creation is known to be compiler synthesized as part of a call // to a method with a params parameter, and so it is probably sound to return true at this point. // As a sanity check, verify that the last argument to the call is equivalent to the array creation. // (Comparing for object identity does not work because the semantic model can return a fresh operation tree.) var lastArgument = parent.ArgumentsInEvaluationOrder.LastOrDefault(); return(lastArgument != null && lastArgument.Value.Syntax == arrayCreationExpression.Syntax && AreEquivalentZeroLengthArrayCreations(arrayCreationExpression, lastArgument.Value as IArrayCreationExpression)); }
/// <summary> /// The execute transaction inner. /// </summary> /// <param name="solution"> /// The solution. /// </param> /// <param name="textControl"> /// The text control. /// </param> public override void ExecuteTransactionInner(ISolution solution, ITextControl textControl) { IList <ITokenNode> tokensForLine = Utils.GetTokensForLineFromTextControl(solution, textControl); foreach (ITokenNode tokenNode in tokensForLine) { ITypeArgumentList typeArgumentListNode = tokenNode.GetContainingNode <ITypeArgumentList>(true); if (typeArgumentListNode != null) { ReadabilityRules.SwapToBuiltInTypeAlias(typeArgumentListNode); } IObjectCreationExpression objectCreationExpressionNode = tokenNode.GetContainingNode <IObjectCreationExpression>(true); if (objectCreationExpressionNode != null) { ReadabilityRules.SwapToBuiltInTypeAlias(objectCreationExpressionNode); } IArrayCreationExpression arrayCreationExpressionNode = tokenNode.GetContainingNode <IArrayCreationExpression>(true); if (arrayCreationExpressionNode != null) { ReadabilityRules.SwapToBuiltInTypeAlias(arrayCreationExpressionNode); } IMethodDeclaration methodDeclaration = tokenNode.GetContainingNode <IMethodDeclaration>(true); if (methodDeclaration != null) { ReadabilityRules.SwapToBuiltInTypeAlias(methodDeclaration); } IVariableDeclaration variableDeclaration = tokenNode.GetContainingNode <IVariableDeclaration>(true); if (variableDeclaration != null) { ReadabilityRules.SwapToBuiltInTypeAlias(variableDeclaration); } IMultipleDeclaration multipleDeclarationNode = tokenNode.GetContainingNode <IMultipleDeclaration>(true); if (multipleDeclarationNode != null) { ReadabilityRules.SwapToBuiltInTypeAlias(multipleDeclarationNode); } } }
/// <summary> /// Swap array creation to built in type. /// </summary> /// <param name="arrayCreationExpression"> /// The array creation expression. /// </param> private static void SwapArrayCreationToBuiltInType(IArrayCreationExpression arrayCreationExpression) { if (!arrayCreationExpression.IsImplicitlyTypedArray) { using (WriteLockCookie.Create(true)) { bool fileIsCSharp30 = arrayCreationExpression.IsCSharp3Supported(); // If the array creation type is the same type as the initializer (and we are CSharp 3.0 or greater) remove it completely IArrayType arrayType = arrayCreationExpression.Type() as IArrayType; if ((arrayType != null) && arrayCreationExpression.ArrayInitializer != null && fileIsCSharp30 && arrayType.ElementType.Equals(arrayCreationExpression.ArrayInitializer.GetElementType(true))) { IList <IRankSpecifier> dims = arrayCreationExpression.Dims; arrayCreationExpression.SetArrayType(null); for (int i = 0; i < (dims.Count - 1); i++) { using (WriteLockCookie.Create(true)) { ModificationUtil.DeleteChild(dims[i]); } } foreach (ICSharpExpression size in arrayCreationExpression.Sizes) { if (size != null) { using (WriteLockCookie.Create(true)) { ModificationUtil.DeleteChild(size); } } } } else { using (WriteLockCookie.Create(true)) { arrayCreationExpression.SetArrayType(arrayType); } } } } }
public sealed override void Initialize(AnalysisContext context) { context.RegisterOperationAction( (operationContext) => { IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation; long priorArgumentValue = long.MinValue; foreach (IArgument argument in invocation.ArgumentsInParameterOrder) { TestAscendingArgument(operationContext, argument.Value, ref priorArgumentValue); if (argument.Kind == ArgumentKind.ParamArray) { IArrayCreationExpression arrayArgument = argument.Value as IArrayCreationExpression; if (arrayArgument != null && arrayArgument.ElementValues.ArrayClass == ArrayInitializerKind.Dimension) { IDimensionArrayInitializer dimension = arrayArgument.ElementValues as IDimensionArrayInitializer; if (dimension != null) { if (dimension.ElementValues.Length > 10) { Report(operationContext, invocation.Syntax, BigParamarrayArgumentsDescriptor); } foreach (IArrayInitializer dimensionValues in dimension.ElementValues) { if (dimensionValues.ArrayClass == ArrayInitializerKind.Expression) { IExpressionArrayInitializer expressionInitializer = dimensionValues as IExpressionArrayInitializer; if (expressionInitializer != null) { TestAscendingArgument(operationContext, expressionInitializer.ElementValue, ref priorArgumentValue); } } } } } } } }, OperationKind.InvocationExpression); }
public sealed override void Initialize(AnalysisContext context) { context.RegisterOperationAction( (operationContext) => { IInvocationExpression invocation = (IInvocationExpression)operationContext.Operation; foreach (IArgument argument in invocation.ArgumentsInSourceOrder) { if (argument.Parameter.IsParams) { IArrayCreationExpression arrayValue = argument.Value as IArrayCreationExpression; if (arrayValue != null) { Optional <object> dimensionSize = arrayValue.DimensionSizes[0].ConstantValue; if (dimensionSize.HasValue && IntegralValue(dimensionSize.Value) > 3) { operationContext.ReportDiagnostic(Diagnostic.Create(LongParamsDescriptor, argument.Value.Syntax.GetLocation())); } } } } foreach (IArgument argument in invocation.ArgumentsInParameterOrder) { if (argument.Parameter.IsParams) { IArrayCreationExpression arrayValue = argument.Value as IArrayCreationExpression; if (arrayValue != null) { Optional <object> dimensionSize = arrayValue.DimensionSizes[0].ConstantValue; if (dimensionSize.HasValue && IntegralValue(dimensionSize.Value) > 3) { operationContext.ReportDiagnostic(Diagnostic.Create(LongParamsDescriptor, argument.Value.Syntax.GetLocation())); } } } } }, OperationKind.InvocationExpression); }
private static bool AreEquivalentZeroLengthArrayCreations(IArrayCreationExpression first, IArrayCreationExpression second) { if (first == null || second == null) { return false; } ImmutableArray<IOperation> sizes = first.DimensionSizes; if (sizes.Length != 1 || !sizes[0].HasConstantValue(0)) { return false; } sizes = second.DimensionSizes; if (sizes.Length != 1 || !sizes[0].HasConstantValue(0)) { return false; } return first.Type.Equals(second.Type); }
private static bool AreEquivalentZeroLengthArrayCreations(IArrayCreationExpression first, IArrayCreationExpression second) { if (first == null || second == null) { return(false); } ImmutableArray <IOperation> sizes = first.DimensionSizes; if (sizes.Length != 1 || !sizes[0].HasConstantValue(0)) { return(false); } sizes = second.DimensionSizes; if (sizes.Length != 1 || !sizes[0].HasConstantValue(0)) { return(false); } return(first.Type.Equals(second.Type)); }
private static bool IsCompilerGeneratedParamsArray(IArrayCreationExpression arrayCreationExpression, OperationAnalysisContext context) { var model = context.Compilation.GetSemanticModel(arrayCreationExpression.Syntax.SyntaxTree); // Compiler generated array creation seems to just use the syntax from the parent. var parent = model.GetOperation(arrayCreationExpression.Syntax, context.CancellationToken) as IInvocationExpression; if (parent == null || parent.TargetMethod == null || parent.TargetMethod.Parameters.Length == 0) { return(false); } if (!parent.TargetMethod.Parameters.Last().IsParams) { return(false); } var lastArgument = parent.ArgumentsInParameterOrder.LastOrDefault(); return(lastArgument.Syntax == parent.Syntax && lastArgument != null && lastArgument.ArgumentKind == ArgumentKind.ParamArray); }
private void AnalyzeOperation(OperationAnalysisContext context, Func <SyntaxNode, bool> isAttributeSytnax) { IArrayCreationExpression arrayCreationExpression = (IArrayCreationExpression)context.Operation; // We can't replace array allocations in attributes, as they're persisted to metadata // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check. if (arrayCreationExpression.Syntax.Ancestors().Any(isAttributeSytnax)) { return; } if (arrayCreationExpression.DimensionSizes.Length == 1) { IOperation dimensionSize = arrayCreationExpression.DimensionSizes[0]; if (dimensionSize.HasConstantValue(0)) { // Workaround for https://github.com/dotnet/roslyn/issues/10214 // Bail out for compiler generated param array creation. if (IsCompilerGeneratedParamsArray(arrayCreationExpression, context)) { return; } // pointers can't be used as generic arguments if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer) { var arrayType = context.Compilation.GetTypeByMetadataName(ArrayTypeName); IMethodSymbol emptyMethod = (IMethodSymbol)arrayType.GetMembers(ArrayEmptyMethodName).First(); var constructed = emptyMethod.Construct(arrayCreationExpression.ElementType); string typeName = constructed.ToDisplayString(ReportFormat); context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor, typeName)); } } } }
public virtual void VisitArrayCreationExpression(IArrayCreationExpression operation) { DefaultVisit(operation); }
/// <summary> /// Swap array creation to built in type. /// </summary> /// <param name="arrayCreationExpression"> /// The array creation expression. /// </param> private static void SwapArrayCreationToBuiltInType(IArrayCreationExpression arrayCreationExpression) { if (!arrayCreationExpression.IsImplicitlyTypedArray) { using (WriteLockCookie.Create(true)) { bool fileIsCSharp30 = arrayCreationExpression.IsCSharp3Supported(); // If the array creation type is the same type as the initializer (and we are CSharp 3.0 or greater) remove it completely IArrayType arrayType = arrayCreationExpression.Type() as IArrayType; if ((arrayType != null) && arrayCreationExpression.ArrayInitializer != null && fileIsCSharp30 && arrayType.ElementType.Equals(arrayCreationExpression.ArrayInitializer.GetElementType(true))) { TreeNodeCollection<IRankSpecifier> dims = arrayCreationExpression.Dims; arrayCreationExpression.SetArrayType(null); for (int i = 0; i < (dims.Count - 1); i++) { using (WriteLockCookie.Create(true)) { ModificationUtil.DeleteChild(dims[i]); } } foreach (ICSharpExpression size in arrayCreationExpression.Sizes) { if (size != null) { using (WriteLockCookie.Create(true)) { ModificationUtil.DeleteChild(size); } } } } else { using (WriteLockCookie.Create(true)) { arrayCreationExpression.SetArrayType(arrayType); } } } } }
public override void VisitArrayCreationExpression(IArrayCreationExpression operation) { base.VisitArrayCreationExpression(operation); }
public override void VisitArrayCreationExpression(IArrayCreationExpression operation) { var elementType = operation.ElementType; base.VisitArrayCreationExpression(operation); }
public override void VisitArrayCreationExpression(IArrayCreationExpression operation) { VisitArray(operation.DimensionSizes); Visit(operation.Initializer); }
public override IOperation VisitArrayCreationExpression(IArrayCreationExpression operation, object argument) { return(new ArrayCreationExpression(VisitArray(operation.DimensionSizes), Visit(operation.Initializer), ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit)); }
/// <inheritdoc /> public override IOperation VisitArrayCreationExpression(IArrayCreationExpression operation, object argument) { return(base.VisitArrayCreationExpression(operation, argument)); }
/// <inheritdoc /> public override Expression VisitArrayCreationExpression(IArrayCreationExpression operation, LocalBinder argument) { return(base.VisitArrayCreationExpression(operation, argument)); }
private static bool IsCompilerGeneratedParamsArray(IArrayCreationExpression arrayCreationExpression, OperationAnalysisContext context) { var model = context.Compilation.GetSemanticModel(arrayCreationExpression.Syntax.SyntaxTree); // Compiler generated array creation seems to just use the syntax from the parent. var parent = model.GetOperation(arrayCreationExpression.Syntax, context.CancellationToken) as IInvocationExpression; if (parent?.TargetMethod == null || parent.TargetMethod.Parameters.Length == 0) { return false; } if (!parent.TargetMethod.Parameters.Last().IsParams) { return false; } // At this point the array creation is known to be compiler synthesized as part of a call // to a method with a params parameter, and so it is probably sound to return true at this point. // As a sanity check, verify that the last argument to the call is equivalent to the array creation. // (Comparing for object identity does not work because the semantic model can return a fresh operation tree.) var lastArgument = parent.ArgumentsInParameterOrder.LastOrDefault(); return lastArgument != null && lastArgument.Value.Syntax == arrayCreationExpression.Syntax && AreEquivalentZeroLengthArrayCreations(arrayCreationExpression, lastArgument.Value as IArrayCreationExpression); }
public static IArrayCreationExpression Update(this IArrayCreationExpression self, ImmutableArray <IOperation> @bounds, IOperation @initializerOpt, ITypeSymbol @type) => self;
private static bool IsCompilerGeneratedParamsArray(IArrayCreationExpression arrayCreationExpression, OperationAnalysisContext context) { var model = context.Compilation.GetSemanticModel(arrayCreationExpression.Syntax.SyntaxTree); // Compiler generated array creation seems to just use the syntax from the parent. var parent = model.GetOperation(arrayCreationExpression.Syntax, context.CancellationToken) as IInvocationExpression; if (parent == null || parent.TargetMethod == null || parent.TargetMethod.Parameters.Length == 0) { return false; } if (!parent.TargetMethod.Parameters.Last().IsParams) { return false; } var lastArgument = parent.ArgumentsInParameterOrder.LastOrDefault(); return lastArgument.Syntax == parent.Syntax && lastArgument != null && lastArgument.ArgumentKind == ArgumentKind.ParamArray; }
public static void CreateInefficientMultidimensionalArrayAccessWarning([CanBeNull] IDeclaredElement declaredElement, [NotNull] IVariableDeclaration variableDeclaration, [NotNull] IDaemonProcess daemonProcess, [NotNull] DaemonProcessKind kind, [NotNull] IHighlightingConsumer consumer, [NotNull] DocumentRange highlightingRange) { if (declaredElement == null) { return; } var type = variableDeclaration.Type as IArrayType; if (type == null) { return; } if (type.Rank == 1) { return; } IArrayCreationExpression arrayCreationExpression = null; IMultipleDeclaration multipleDeclaration = null; switch (variableDeclaration) { case IFieldDeclaration fieldDeclaration: // perfomance optimization if (fieldDeclaration.GetAccessRights() != AccessRights.PRIVATE) { return; } arrayCreationExpression = (fieldDeclaration.Initial as IExpressionInitializer)?.Value as IArrayCreationExpression; multipleDeclaration = MultipleFieldDeclarationNavigator.GetByDeclarator(fieldDeclaration); break; case ILocalVariableDeclaration localVariableDeclaration: var initial = localVariableDeclaration.Initial; arrayCreationExpression = (initial as IExpressionInitializer)?.Value as IArrayCreationExpression; if (initial != null && arrayCreationExpression == null) { return; } multipleDeclaration = MultipleLocalVariableDeclarationNavigator.GetByDeclarator(localVariableDeclaration); break; default: return; } var classDeclaration = variableDeclaration.GetContainingNode <IClassLikeDeclaration>(); if (classDeclaration == null) { return; } var usages = FindArrayUsages(declaredElement, classDeclaration, daemonProcess, kind); foreach (var usage in usages) { if (ElementAccessExpressionNavigator.GetByOperand(usage as ICSharpExpression) == null) { return; } } if (arrayCreationExpression.ContainsErrorElement()) { return; } consumer.AddHighlighting(new InefficientMultidimensionalArrayUsageWarning(usages.Select(t => t.CreateTreeElementPointer()).ToList(), arrayCreationExpression, variableDeclaration, multipleDeclaration, highlightingRange)); }