Skip to content

Commit 41ae575

Browse files
committed
Check for suppressions on reflection access
1 parent b9fdca1 commit 41ae575

File tree

2 files changed

+205
-5
lines changed

2 files changed

+205
-5
lines changed

src/linker/Linker/Annotations.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,13 @@ internal bool DoesMethodRequireUnreferencedCode (MethodDefinition method, [NotNu
606606
TryGetLinkerAttribute (method.DeclaringType, out attribute))
607607
return true;
608608

609+
MethodDefinition? owningMethod;
610+
while (context.CompilerGeneratedState.TryGetOwningMethodForCompilerGeneratedMember (method, out owningMethod)) {
611+
if (DoesMethodRequireUnreferencedCode (owningMethod, out attribute))
612+
return true;
613+
method = owningMethod;
614+
}
615+
609616
return false;
610617
}
611618

test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs

Lines changed: 198 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public static void Main ()
3535
SuppressInComplex.Test ();
3636

3737
StateMachinesOnlyReferencedViaReflection.Test ();
38+
LocalFunctionsReferencedViaReflection.Test ();
39+
LambdasReferencedViaReflection.Test ();
3840

3941
ComplexCases.AsyncBodyCallingMethodWithRequires.Test ();
4042
ComplexCases.GenericAsyncBodyCallingMethodWithRequires.Test ();
@@ -1257,7 +1259,7 @@ static void TestSuppressionOnLambdaWithNestedLambda ()
12571259
() => MethodWithRequires ();
12581260
};
12591261

1260-
lambda (); // This will produce a warning since the local function has Requires on it
1262+
lambda (); // This will produce a warning since the lambda has Requires on it
12611263
}
12621264

12631265
[RequiresUnreferencedCode ("Suppress in body")]
@@ -1596,13 +1598,204 @@ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn ()
15961598

15971599
[ExpectedWarning ("IL2026", "Requires to suppress")]
15981600
[ExpectedWarning ("IL2026", "Requires to suppress")]
1599-
public static void Test ()
1601+
// Analyzer doesn't emit additional warnings about reflection access to the compiler-generated
1602+
// state machine members.
1603+
[ExpectedWarning ("IL2026", "Requires to suppress", ProducedBy = ProducedBy.Trimmer)]
1604+
[ExpectedWarning ("IL2026", "Requires to suppress", ProducedBy = ProducedBy.Trimmer)]
1605+
static void TestAll ()
16001606
{
1601-
// This is not a 100% reliable test, since in theory it can be marked in any order and so it could happen that the
1602-
// user method is marked before the nested state machine gets marked. But it's the best we can do right now.
1603-
// (Note that currently linker will mark the state machine first actually so the test is effective).
16041607
typeof (StateMachinesOnlyReferencedViaReflection).RequiresAll ();
16051608
}
1609+
1610+
[ExpectedWarning ("IL2026", "Requires to suppress")]
1611+
[ExpectedWarning ("IL2026", "Requires to suppress")]
1612+
// NonPublicMethods doesn't warn for members emitted into compiler-generated state machine types.
1613+
static void TestNonPublicMethods ()
1614+
{
1615+
typeof (StateMachinesOnlyReferencedViaReflection).RequiresNonPublicMethods ();
1616+
}
1617+
1618+
public static void Test ()
1619+
{
1620+
TestAll ();
1621+
TestNonPublicMethods ();
1622+
}
1623+
}
1624+
1625+
class LocalFunctionsReferencedViaReflection
1626+
{
1627+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--")]
1628+
[ExpectedWarning ("IL3002", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer)]
1629+
[ExpectedWarning ("IL3050", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer)]
1630+
static void TestLocalFunctionWithRequires ()
1631+
{
1632+
LocalFunction ();
1633+
1634+
[RequiresUnreferencedCode ("--TestLocalFunctionWithRequires--")]
1635+
[RequiresAssemblyFiles ("--TestLocalFunctionWithRequires--")]
1636+
[RequiresDynamicCode ("--TestLocalFunctionWithRequires--")]
1637+
void LocalFunction () => MethodWithRequires ();
1638+
}
1639+
1640+
[ExpectedWarning ("IL2026", "LocalFunction")]
1641+
[ExpectedWarning ("IL3002", "LocalFunction", ProducedBy = ProducedBy.Analyzer)]
1642+
[ExpectedWarning ("IL3050", "LocalFunction", ProducedBy = ProducedBy.Analyzer)]
1643+
static void TestLocalFunctionWithClosureWithRequires (int p = 0)
1644+
{
1645+
LocalFunction ();
1646+
1647+
[RequiresUnreferencedCode ("--TestLocalFunctionWithClosureWithRequires--")]
1648+
[RequiresAssemblyFiles ("--TestLocalFunctionWithClosureWithRequires--")]
1649+
[RequiresDynamicCode ("--TestLocalFunctionWithClosureWithRequires--")]
1650+
void LocalFunction () {
1651+
p++;
1652+
MethodWithRequires ();
1653+
}
1654+
}
1655+
1656+
[RequiresUnreferencedCode ("--TestLocalFunctionInMethodWithRequires--")]
1657+
[RequiresAssemblyFiles ("--TestLocalFunctionInMethodWithRequires--")]
1658+
[RequiresDynamicCode ("--TestLocalFunctionInMethodWithRequires--")]
1659+
static void TestLocalFunctionInMethodWithRequires ()
1660+
{
1661+
LocalFunction ();
1662+
1663+
void LocalFunction () => MethodWithRequires ();
1664+
}
1665+
1666+
[RequiresUnreferencedCode ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
1667+
[RequiresAssemblyFiles ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
1668+
[RequiresDynamicCode ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
1669+
static void TestLocalFunctionWithClosureInMethodWithRequires (int p = 0)
1670+
{
1671+
LocalFunction ();
1672+
1673+
void LocalFunction () {
1674+
p++;
1675+
MethodWithRequires ();
1676+
}
1677+
}
1678+
1679+
// Warnings for Reflection access to methods with Requires
1680+
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")]
1681+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")]
1682+
// The linker correctly emits warnings about reflection access to local functions with Requires
1683+
// or which inherit Requires from the containing method. The analyzer doesn't bind to local functions
1684+
// so does not warn here.
1685+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1686+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1687+
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1688+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1689+
static void TestAll ()
1690+
{
1691+
typeof (LocalFunctionsReferencedViaReflection).RequiresAll ();
1692+
}
1693+
1694+
// Warnings for Reflection access to methods with Requires
1695+
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")]
1696+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")]
1697+
// NonPublicMethods warns for local functions not emitted into display classes.
1698+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1699+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1700+
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1701+
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1702+
static void TestNonPublicMethods ()
1703+
{
1704+
typeof (LocalFunctionsReferencedViaReflection).RequiresNonPublicMethods ();
1705+
}
1706+
1707+
public static void Test ()
1708+
{
1709+
TestAll ();
1710+
TestNonPublicMethods ();
1711+
}
1712+
}
1713+
1714+
class LambdasReferencedViaReflection
1715+
{
1716+
[ExpectedWarning ("IL2026", "--TestLambdaWithRequires--")]
1717+
[ExpectedWarning ("IL3002", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
1718+
[ExpectedWarning ("IL3050", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
1719+
static void TestLambdaWithRequires ()
1720+
{
1721+
var lambda =
1722+
[RequiresUnreferencedCode ("--TestLambdaWithRequires--")]
1723+
[RequiresAssemblyFiles ("--TestLambdaWithRequires--")]
1724+
[RequiresDynamicCode ("--TestLambdaWithRequires--")]
1725+
() => MethodWithRequires ();
1726+
1727+
lambda ();
1728+
}
1729+
1730+
[ExpectedWarning ("IL2026", "Lambda")]
1731+
[ExpectedWarning ("IL3002", "Lambda", ProducedBy = ProducedBy.Analyzer)]
1732+
[ExpectedWarning ("IL3050", "Lambda", ProducedBy = ProducedBy.Analyzer)]
1733+
static void TestLambdaWithClosureWithRequires (int p = 0)
1734+
{
1735+
var lambda =
1736+
[RequiresUnreferencedCode ("--TestLambdaWithClosureWithRequires--")]
1737+
[RequiresAssemblyFiles ("--TestLambdaWithClosureWithRequires--")]
1738+
[RequiresDynamicCode ("--TestLambdaWithClosureWithRequires--")]
1739+
() => {
1740+
p++;
1741+
MethodWithRequires ();
1742+
};
1743+
1744+
lambda ();
1745+
}
1746+
1747+
[RequiresUnreferencedCode ("--TestLambdaInMethodWithRequires--")]
1748+
[RequiresAssemblyFiles ("--TestLambdaInMethodWithRequires--")]
1749+
[RequiresDynamicCode ("--TestLambdaInMethodWithRequires--")]
1750+
static void TestLambdaInMethodWithRequires ()
1751+
{
1752+
var lambda = () => MethodWithRequires ();
1753+
1754+
lambda ();
1755+
}
1756+
1757+
[RequiresUnreferencedCode ("--TestLambdaWithClosureInMethodWithRequires--")]
1758+
[RequiresAssemblyFiles ("--TestLambdaWithClosureInMethodWithRequires--")]
1759+
[RequiresDynamicCode ("--TestLambdaWithClosureInMethodWithRequires--")]
1760+
static void TestLambdaWithClosureInMethodWithRequires (int p = 0)
1761+
{
1762+
var lambda = () => {
1763+
p++;
1764+
MethodWithRequires ();
1765+
};
1766+
1767+
lambda ();
1768+
}
1769+
1770+
// Warnings for Reflection access to methods with Requires
1771+
[ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")]
1772+
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")]
1773+
// The linker correctly emits warnings about reflection access to lambdas with Requires
1774+
// or which inherit Requires from the containing method. The analyzer doesn't bind to lambdas
1775+
// so does not warn here.
1776+
[ExpectedWarning ("IL2026", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1777+
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1778+
[ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1779+
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
1780+
static void TestAll ()
1781+
{
1782+
typeof (LambdasReferencedViaReflection).RequiresAll ();
1783+
}
1784+
1785+
// Warnings for Reflection access to methods with Requires
1786+
[ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")]
1787+
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")]
1788+
// NonPublicMethods doesn't warn for lambdas emitted into display class types.
1789+
static void TestNonPublicMethods ()
1790+
{
1791+
typeof (LambdasReferencedViaReflection).RequiresNonPublicMethods ();
1792+
}
1793+
1794+
public static void Test ()
1795+
{
1796+
TestAll ();
1797+
TestNonPublicMethods ();
1798+
}
16061799
}
16071800

16081801
class ComplexCases

0 commit comments

Comments
 (0)