blob: 56b8d1a50341ebfd9d31e41651356e761babbe48 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Lucene.Net.CodeAnalysis.Dev.CodeFixes.LuceneDev4xxx;
using Lucene.Net.CodeAnalysis.Dev.LuceneDev4xxx;
using Lucene.Net.CodeAnalysis.Dev.TestUtilities;
using Lucene.Net.CodeAnalysis.Dev.Utility;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using System.Threading.Tasks;
namespace Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests.LuceneDev4xxx
{
[TestFixture]
public class TestLuceneDev4002_StackTraceHelperNoInliningCodeFixProvider
{
private const string StackTraceHelperStub = @"
namespace Lucene.Net.Support.ExceptionHandling
{
public static class StackTraceHelper
{
public static bool DoesStackTraceContainMethod(string methodName) => false;
public static bool DoesStackTraceContainMethod(string className, string methodName) => false;
}
}
";
[Test]
public async Task Fix_AddsAttribute_WhenUsingAlreadyPresent()
{
var testCode = @"
using System.Runtime.CompilerServices;
public class Target
{
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var fixedCode = @"
using System.Runtime.CompilerServices;
public class Target
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var expected = new DiagnosticResult(Descriptors.LuceneDev4002_MissingNoInlining)
.WithSeverity(DiagnosticSeverity.Warning)
.WithSpan(16, 13, 16, 132)
.WithArguments("Target.Merge");
var test = new InjectableCodeFixTest(
() => new LuceneDev4002_StackTraceHelperNoInliningAnalyzer(),
() => new LuceneDev4002_StackTraceHelperNoInliningCodeFixProvider())
{
TestCode = testCode,
FixedCode = fixedCode,
ExpectedDiagnostics = { expected }
};
await test.RunAsync();
}
[Test]
public async Task Fix_AddsAttributeAndUsing_WhenUsingMissing()
{
// No `using System.Runtime.CompilerServices;` initially — fix must add it.
var testCode = @"
public class Target
{
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var fixedCode = @"using System.Runtime.CompilerServices;
public class Target
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var expected = new DiagnosticResult(Descriptors.LuceneDev4002_MissingNoInlining)
.WithSeverity(DiagnosticSeverity.Warning)
.WithSpan(14, 13, 14, 132)
.WithArguments("Target.Merge");
var test = new InjectableCodeFixTest(
() => new LuceneDev4002_StackTraceHelperNoInliningAnalyzer(),
() => new LuceneDev4002_StackTraceHelperNoInliningCodeFixProvider())
{
TestCode = testCode,
FixedCode = fixedCode,
ExpectedDiagnostics = { expected }
};
await test.RunAsync();
}
[Test]
public async Task Fix_AddsAttributeAndUsing_InTargetDocument_WhenTargetIsInDifferentFile()
{
// Target lives in /0/Test0.cs, Caller in /0/Test1.cs. The code fix must
// edit the target's document (adding the attribute and the using) rather
// than the caller's.
var targetSource = @"
public class Target
{
public void Merge()
{
var x = 1;
}
}
";
var callerSource = @"
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var fixedTargetSource = @"using System.Runtime.CompilerServices;
public class Target
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Merge()
{
var x = 1;
}
}
";
var expected = new DiagnosticResult(Descriptors.LuceneDev4002_MissingNoInlining)
.WithSeverity(DiagnosticSeverity.Warning)
.WithLocation("/0/Test1.cs", line: 6, column: 13)
.WithArguments("Target.Merge");
var test = new InjectableCodeFixTest(
() => new LuceneDev4002_StackTraceHelperNoInliningAnalyzer(),
() => new LuceneDev4002_StackTraceHelperNoInliningCodeFixProvider())
{
ExpectedDiagnostics = { expected }
};
test.TestState.Sources.Add(targetSource);
test.TestState.Sources.Add(callerSource);
test.FixedState.Sources.Add(fixedTargetSource);
test.FixedState.Sources.Add(callerSource);
await test.RunAsync();
}
[Test]
public async Task Fix_PreservesExistingAttributeOnTarget()
{
// Target method has another attribute; the new MethodImpl list should
// be inserted ahead of it without disturbing it.
var testCode = @"
using System;
using System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method)]
public class FooAttribute : Attribute { }
public class Target
{
[Foo]
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var fixedCode = @"
using System;
using System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method)]
public class FooAttribute : Attribute { }
public class Target
{
[MethodImpl(MethodImplOptions.NoInlining)]
[Foo]
public void Merge()
{
var x = 1;
}
}
public class Caller
{
public void Check()
{
if (Lucene.Net.Support.ExceptionHandling.StackTraceHelper.DoesStackTraceContainMethod(nameof(Target), nameof(Target.Merge)))
{
}
}
}" + StackTraceHelperStub;
var expected = new DiagnosticResult(Descriptors.LuceneDev4002_MissingNoInlining)
.WithSeverity(DiagnosticSeverity.Warning)
.WithSpan(21, 13, 21, 132)
.WithArguments("Target.Merge");
var test = new InjectableCodeFixTest(
() => new LuceneDev4002_StackTraceHelperNoInliningAnalyzer(),
() => new LuceneDev4002_StackTraceHelperNoInliningCodeFixProvider())
{
TestCode = testCode,
FixedCode = fixedCode,
ExpectedDiagnostics = { expected }
};
await test.RunAsync();
}
}
}