Skip to content

Commit

Permalink
Disable blob container path analyzer when an expression is used for t…
Browse files Browse the repository at this point in the history
…he blob path (#1808)

* Don't check path when expressions are used

* Update notes

* Update version
  • Loading branch information
liliankasem committed Aug 9, 2023
1 parent b862aae commit b060c1d
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 43 deletions.
2 changes: 0 additions & 2 deletions docs/analyzer-rules/AZFW0011.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ When using the `BlobInputAttribute` with a container path, the target parameter

Example, if your function uses `BlobInput("<container path>")` and it is binding to a `string`, this rule will be violated.


## How to fix violations

Change the binding type to an iterable type such as `IEnumerable<T>` or provide blob path `container/blob` instead of a container path when using a non-iterable binding type is desired.


### Supported Types

You can refer to the [public documentation](https://learn.microsoft.com/azure/azure-functions/functions-bindings-storage-blob?tabs=in-process%2Cextensionv5%2Cextensionv3&pivots=programming-language-csharp) to see which types are supported for blob container.
6 changes: 3 additions & 3 deletions sdk/Sdk.Analyzers/Extensions/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ internal static bool IsIterableType(this ITypeSymbol typeSymbol, SymbolAnalysisC
return IsIEnumerableTType || IsIEnumerableType || isArrayType;
}

internal static bool IsOrImplementsOrDerivesFrom(this ITypeSymbol symbol, ITypeSymbol? other)
internal static bool IsOrImplementsOrDerivesFrom(this ITypeSymbol symbol, ITypeSymbol other)
{
return symbol.IsOrImplements(other) || symbol.IsOrDerivedFrom(other);
}

internal static bool IsOrDerivedFrom(this ITypeSymbol symbol, ITypeSymbol? other)
internal static bool IsOrDerivedFrom(this ITypeSymbol symbol, ITypeSymbol other)
{
if (other is null)
{
Expand All @@ -114,7 +114,7 @@ internal static bool IsOrDerivedFrom(this ITypeSymbol symbol, ITypeSymbol? other
return false;
}

internal static bool IsOrImplements(this ITypeSymbol symbol, ITypeSymbol? other)
internal static bool IsOrImplements(this ITypeSymbol symbol, ITypeSymbol other)
{
if (other is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

Expand All @@ -17,6 +18,8 @@ public class IterableBindingTypeExpectedForBlobContainerPath : DiagnosticAnalyze
private const string BlobInputBindingAttribute = "Microsoft.Azure.Functions.Worker.BlobInputAttribute";
private const string BlobContainerClientType = "Azure.Storage.Blobs.BlobContainerClient";

private static readonly Regex BlobPathUsesExpression = new Regex("{.*}");

public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
Expand Down Expand Up @@ -65,6 +68,12 @@ private static void AnalyzeParameter(SymbolAnalysisContext context, IParameterSy
{
string path = arg.Value.ToString();

// Skip this analyzer if an expression is used for the blob path
if (BlobPathUsesExpression.IsMatch(path))
{
continue;
}

if (path.Split('/').Length < 2
&& !parameterType.IsIterableType(context)
&& !string.Equals(parameterType.ToDisplayString(), BlobContainerClientType, StringComparison.Ordinal))
Expand Down
2 changes: 1 addition & 1 deletion sdk/Sdk.Analyzers/Sdk.Analyzers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<MinorProductVersion>2</MinorProductVersion>
<PatchProductVersion>0</PatchProductVersion>
<PatchProductVersion>1</PatchProductVersion>
<OutputType>Library</OutputType>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<IncludeBuildOutput>false</IncludeBuildOutput>
Expand Down
2 changes: 1 addition & 1 deletion sdk/Sdk/Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<MinorProductVersion>13</MinorProductVersion>
<PatchProductVersion>0</PatchProductVersion>
<PatchProductVersion>1</PatchProductVersion>
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
<PackageId>Microsoft.Azure.Functions.Worker.Sdk</PackageId>
<Description>This package provides development time support for the Azure Functions .NET Worker.</Description>
Expand Down
8 changes: 4 additions & 4 deletions sdk/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
- My change description (#PR/#issue)
-->

### Microsoft.Azure.Functions.Worker.Sdk <version>
### Microsoft.Azure.Functions.Worker.Sdk 1.13.1

- <entry>
- Update Microsoft.Azure.Functions.Worker.Sdk.Analyzers dependency to 1.2.1

### Microsoft.Azure.Functions.Worker.Sdk.Analyzers <version>
### Microsoft.Azure.Functions.Worker.Sdk.Analyzers 1.2.1

- <entry>
- Disable blob container path analyzer when an expression is used for the blob path

### Microsoft.Azure.Functions.Worker.Sdk.Generators <version>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ public static void Run([BlobInput(""input"")] string message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -68,10 +68,10 @@ public static void Run([BlobInput(""input"")] Stream message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -105,10 +105,10 @@ public static void Run([BlobInput(""input"")] byte[] message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -143,10 +143,10 @@ public static void Run([BlobInput(""input"")] string[] message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -179,10 +179,10 @@ public static void Run([BlobInput(""input"")] IEnumerable<Stream> message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -214,10 +214,10 @@ public static void Run([BlobInput(""input"")] IEnumerable<string> message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -249,10 +249,10 @@ public static void Run([BlobInput(""input"")] byte[][] message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down Expand Up @@ -285,10 +285,46 @@ public static void Run([BlobInput(""input"")] BlobContainerClient message)
var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.15.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.9.0-preview1"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "5.1.1-preview2"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.2.0-preview1"))),
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};

// test.ExpectedDiagnostics is an empty collection.

await test.RunAsync();
}

[Fact]
public async Task BlobInputAttribute_BlobPathExpression_Diagnostics_NotExpected()
{
string testCode = @"
using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Azure.Storage.Blobs;
namespace FunctionApp
{
public static class SomeFunction
{
[Function(nameof(SomeFunction))]
public static void Run([BlobInput(""{input}"")] string message)
{
}
}
}";

var test = new AnalyzerTest
{
ReferenceAssemblies = ReferenceAssemblies.Net.Net50.WithPackages(ImmutableArray.Create(
new PackageIdentity("Microsoft.Azure.Functions.Worker", "1.18.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Sdk", "1.13.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs", "6.0.0"),
new PackageIdentity("Microsoft.Azure.Functions.Worker.Extensions.Abstractions", "1.3.0"))),

TestCode = testCode
};
Expand Down

0 comments on commit b060c1d

Please sign in to comment.