Skip to content

Commit

Permalink
GH-212 - disable CallInfo analysis for Arg.AnyType matchers (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
tpodolak authored Feb 11, 2024
1 parent 417e4e7 commit 2748119
Show file tree
Hide file tree
Showing 20 changed files with 102 additions and 157 deletions.
12 changes: 12 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"cake.tool": {
"version": "4.0.0",
"commands": [
"dotnet-cake"
]
}
}
}
19 changes: 8 additions & 11 deletions build/build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
#load "./releasenotes.cake"
#load "./table-of-contents.cake"

// Install modules
#module nuget:?package=Cake.DotNetTool.Module&version=0.1.0

// Install tools.
#tool "dotnet:https://api.nuget.org/v3/index.json?package=GitVersion.Tool&version=5.8.1"
#tool "dotnet:https://api.nuget.org/v3/index.json?package=coveralls.net&version=4.0.1"
#tool "nuget:https://www.nuget.org/api/v2?package=ReportGenerator&version=5.0.2"
#addin "nuget:https://www.nuget.org/api/v2?package=Cake.Incubator&version=4.0.1"
#addin "nuget:https://www.nuget.org/api/v2?package=Cake.Incubator&version=8.0.0"
#addin "nuget:https://www.nuget.org/api/v2?package=Newtonsoft.Json&version=9.0.1"
#addin "nuget:https://www.nuget.org/api/v2?package=semver.core&version=2.0.0"

Expand Down Expand Up @@ -62,22 +59,22 @@ Setup(context =>
Task("Clean")
.Does(() =>
{
DotNetCoreClean(paths.Files.Solution.ToString());
DotNetClean(paths.Files.Solution.ToString());
});

Task("Restore-NuGet-Packages")
.IsDependentOn("Clean")
.Does(() =>
{
DotNetCoreRestore(paths.Files.Solution.ToString());
DotNetRestore(paths.Files.Solution.ToString());
});

Task("Run-Tests")
.IsDependentOn("Build")
.Does(() =>
{

var testSettings = new DotNetCoreTestSettings
var testSettings = new DotNetTestSettings
{
Framework = parameters.TargetFramework,
NoBuild = true,
Expand All @@ -97,7 +94,7 @@ Task("Run-Tests")
.Append("-- RunConfiguration.NoAutoReporters=true");
}

DotNetCoreTest(paths.Files.Solution.MakeAbsolute(Context.Environment).ToString(), testSettings);
DotNetTest(paths.Files.Solution.MakeAbsolute(Context.Environment).ToString(), testSettings);

if(parameters.SkipCodeCoverage == false)
{
Expand Down Expand Up @@ -129,7 +126,7 @@ Task("Build")
.IsDependentOn("Restore-NuGet-Packages")
.Does(() =>
{
DotNetCoreBuild(paths.Files.Solution.ToString(), new DotNetCoreBuildSettings
DotNetBuild(paths.Files.Solution.ToString(), new DotNetBuildSettings
{
Configuration = parameters.Configuration,
NoRestore = true,
Expand All @@ -146,15 +143,15 @@ Task("NuGet-Pack")
{
foreach(var projectFile in paths.Files.ProjectsToPack)
{
var settings = new DotNetCorePackSettings
var settings = new DotNetPackSettings
{
NoBuild = true,
VersionSuffix = buildVersion.SemVersion.ToString(),
Configuration = parameters.Configuration,
OutputDirectory = paths.Directories.Artifacts
};

DotNetCorePack(projectFile.ToString(), settings);
DotNetPack(projectFile.ToString(), settings);
}
});

Expand Down
91 changes: 9 additions & 82 deletions build/build.ps1
Original file line number Diff line number Diff line change
@@ -1,86 +1,13 @@
$DotNetInstallerUri = 'https://dot.net/v1/dotnet-install.ps1';
$DotNetUnixInstallerUri = 'https://dot.net/v1/dotnet-install.sh'
$DotNetChannel = 'LTS'
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
$ErrorActionPreference = 'Stop'

[string] $CakeVersion = ''
foreach($line in Get-Content "$PSScriptRoot\build.config")
{
if ($line -like 'CAKE_VERSION=*') {
$CakeVersion = $line.SubString(13)
}
}
Set-Location -LiteralPath $PSScriptRoot

$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1'
$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1'
$env:DOTNET_NOLOGO = '1'

if ([string]::IsNullOrEmpty($CakeVersion)) {
'Failed to parse Cake Version'
exit 1
}
dotnet tool restore
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

# Make sure tools folder exists
$ToolPath = Join-Path $PSScriptRoot "tools"
if (!(Test-Path $ToolPath)) {
Write-Verbose "Creating tools directory..."
New-Item -Path $ToolPath -Type Directory -Force | out-null
}


if ($PSVersionTable.PSEdition -ne 'Core') {
# Attempt to set highest encryption available for SecurityProtocol.
# PowerShell will not set this by default (until maybe .NET 4.6.x). This
# will typically produce a message for PowerShell v2 (just an info
# message though)
try {
# Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48)
# Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't
# exist in .NET 4.0, even though they are addressable if .NET 4.5+ is
# installed (.NET 4.5 is an in-place upgrade).
[System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48
} catch {
Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3'
}
}

###########################################################################
# INSTALL CAKE
###########################################################################

# Make sure Cake has been installed.
[string] $CakeExePath = ''
[string] $CakeInstalledVersion = Get-Command dotnet-cake -ErrorAction SilentlyContinue | % {&$_.Source --version}

if ($CakeInstalledVersion -eq $CakeVersion) {
# Cake found locally
$CakeExePath = (Get-Command dotnet-cake).Source
}
else {
$CakePath = Join-Path $ToolPath ".store\cake.tool\$CakeVersion"
$CakeExePath = (Get-ChildItem -Path $ToolPath -Filter "dotnet-cake*" -File| ForEach-Object FullName | Select-Object -First 1)


if ((!(Test-Path -Path $CakePath -PathType Container)) -or (!(Test-Path $CakeExePath -PathType Leaf))) {

if ((![string]::IsNullOrEmpty($CakeExePath)) -and (Test-Path $CakeExePath -PathType Leaf))
{
& dotnet tool uninstall --tool-path $ToolPath Cake.Tool
}

& dotnet tool install --tool-path $ToolPath --version $CakeVersion Cake.Tool
if ($LASTEXITCODE -ne 0)
{
'Failed to install cake'
exit 1
}
$CakeExePath = (Get-ChildItem -Path $ToolPath -Filter "dotnet-cake*" -File| ForEach-Object FullName | Select-Object -First 1)
}
}

###########################################################################
# RUN BUILD SCRIPT
###########################################################################
& "$CakeExePath" ./build.cake --bootstrap
if ($LASTEXITCODE -eq 0)
{
& "$CakeExePath" ./build.cake $args
}
exit $LASTEXITCODE
dotnet cake @args
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
57 changes: 8 additions & 49 deletions build/build.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,53 +1,12 @@
#!/usr/bin/env bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source $SCRIPT_DIR/build.config
TOOLS_DIR=$SCRIPT_DIR/tools
CAKE_EXE=$TOOLS_DIR/dotnet-cake
CAKE_PATH=$TOOLS_DIR/.store/cake.tool/$CAKE_VERSION
#!/usr/bin/env bash
set -euox pipefail

if [ "$CAKE_VERSION" = "" ]; then
echo "An error occured while parsing Cake version."
exit 1
fi
cd "$(dirname "${BASH_SOURCE[0]}")"

# Make sure the tools folder exist.
if [ ! -d "$TOOLS_DIR" ]; then
mkdir "$TOOLS_DIR"
fi
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_NOLOGO=1

dotnet tool restore

###########################################################################
# INSTALL CAKE
###########################################################################

CAKE_INSTALLED_VERSION=$(dotnet-cake --version 2>&1)

if [ "$CAKE_VERSION" != "$CAKE_INSTALLED_VERSION" ]; then
if [ ! -f "$CAKE_EXE" ] || [ ! -d "$CAKE_PATH" ]; then
if [ -f "$CAKE_EXE" ]; then
dotnet tool uninstall --tool-path $TOOLS_DIR Cake.Tool
fi

echo "Installing Cake $CAKE_VERSION..."
dotnet tool install --tool-path $TOOLS_DIR --version $CAKE_VERSION Cake.Tool
if [ $? -ne 0 ]; then
echo "An error occured while installing Cake."
exit 1
fi
fi

# Make sure that Cake has been installed.
if [ ! -f "$CAKE_EXE" ]; then
echo "Could not find Cake.exe at '$CAKE_EXE'."
exit 1
fi
else
CAKE_EXE="dotnet-cake"
fi

###########################################################################
# RUN BUILD SCRIPT
###########################################################################

# Start Cake
(exec "$CAKE_EXE" build.cake --bootstrap) && (exec "$CAKE_EXE" build.cake "$@")
dotnet cake "$@"
Binary file modified libs/nsubstitute-latest/NSubstitute.dll
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ private void AnalyzeArgAtInvocations(OperationAnalysisContext operationAnalysisC
continue;
}

if (IsAssignableTo(
var substituteParameterTypeSymbol = substituteCallParameters[position.Value].GetTypeSymbol();
if (substituteParameterTypeSymbol.IsArgAnyType(operationAnalysisContext.Compilation) == false && IsAssignableTo(
operationAnalysisContext.Compilation,
substituteCallParameters[position.Value].GetTypeSymbol(),
substituteParameterTypeSymbol,
argAtInvocation.TargetMethod.TypeArguments.First()) == false)
{
var diagnostic = Diagnostic.Create(
Expand Down Expand Up @@ -213,7 +214,9 @@ private bool AnalyzeCast(OperationAnalysisContext operationAnalysisContext, IRea
}

var type = conversionOperation.Type;
if (type != null && CanCast(operationAnalysisContext.Compilation, substituteCallParameters[position.Value].GetTypeSymbol(), type) == false)
var substituteParameterTypeSymbol = substituteCallParameters[position.Value].GetTypeSymbol();
if (type != null && substituteParameterTypeSymbol.IsArgAnyType(operationAnalysisContext.Compilation) == false &&
CanCast(operationAnalysisContext.Compilation, substituteParameterTypeSymbol, type) == false)
{
var diagnostic = Diagnostic.Create(
DiagnosticDescriptorsProvider.CallInfoCouldNotConvertParameterAtPosition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ typeSymbol is INamedTypeSymbol namedTypeSymbol &&
return isCalledViaDelegate;
}

public static bool IsArgAnyType(this ITypeSymbol? typeSymbol, Compilation compilation)
{
return typeSymbol != null
&& typeSymbol.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.OrdinalIgnoreCase) == true
&& typeSymbol.ToString().Equals(MetadataNames.NSubstituteArgAnyTypeFullTypeName, StringComparison.OrdinalIgnoreCase);
}

public static bool IsCallInfoSymbol(this ITypeSymbol symbol)
{
return IsCallInfoSymbolInternal(symbol) || IsCallInfoSymbolInternal(symbol.BaseType);
Expand Down
1 change: 1 addition & 0 deletions src/NSubstitute.Analyzers.Shared/MetadataNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal class MetadataNames
public const string NSubstituteReturnsExtensionsFullTypeName = "NSubstitute.ReturnsExtensions.ReturnsExtensions";
public const string NSubstituteExceptionExtensionsFullTypeName = "NSubstitute.ExceptionExtensions.ExceptionExtensions";
public const string NSubstituteCallInfoFullTypeName = "NSubstitute.Core.CallInfo";
public const string NSubstituteArgAnyTypeFullTypeName = "NSubstitute.Arg.AnyType";
public const string NSubstituteConfiguredCallFullTypeName = "NSubstitute.Core.ConfiguredCall";
public const string NSubstituteSubstituteFullTypeName = "NSubstitute.Substitute";
public const string NSubstituteFactoryFullTypeName = "NSubstitute.Core.ISubstituteFactory";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ public abstract class CallInfoDiagnosticVerifier : CSharpDiagnosticVerifier, ICa
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = callInfo.Args()[1] as BarBase;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = callInfo.Args()[1] as object;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = (int)callInfo.Args()[0];")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = (string)callInfo.Args()[1];")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = callInfo.Args()[1] as string;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = (string)callInfo[1];")]
public abstract Task ReportsNoDiagnostic_WhenManuallyCasting_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down Expand Up @@ -183,6 +186,7 @@ public abstract class CallInfoDiagnosticVerifier : CSharpDiagnosticVerifier, ICa
[InlineData("substitute[Arg.Any<decimal>(), Arg.Any<Bar>()]", "callInfo.ArgAt<object>(1);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "callInfo.ArgAt<int>(0);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "callInfo.ArgAt<object>(0);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "callInfo.ArgAt<string>(1);")]
public abstract Task ReportsNoDiagnostic_WhenCasting_WithArgAt_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,11 @@ public interface Foo
{{
Task<int> Bar(int x, Bar y);
Task<int> Bar(int x, object y);
Task<int> this[int x, Bar y] {{ get; }}
Task<int> this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Loading

0 comments on commit 2748119

Please sign in to comment.