Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Boemer <sbomer@gmail.com>2022-01-14 00:44:10 +0300
committerGitHub <noreply@github.com>2022-01-14 00:44:10 +0300
commitb3c58adac2555627916c6821622ef3a88cf4aeea (patch)
treeeb04b0bca6fcc1d763b157973b913a5a5e571d2d /test/Mono.Linker.Tests.Cases/DataFlow
parentb540d832456972b57329e6b466f8bb2e4b8e4d48 (diff)
[DAM analyzer] Support exceptional control flow (#2481)
This includes a change to make the analyzer tests fail when an exception is thrown. This models exceptional control flow by maintaining an exception state for try/catch regions, which is updated to include all possible states encountered within that region. This exceptional state is propagated from try regions to the beginning of catch regions, and from try or catch regions to the beginning of finally regions. Finally regions are represented as additional information for each predecessor edge in the control flow graph, following the data model given by Roslyn's CFG. Each edge includes a list of finally regions through which control flows as part of the edge before reaching its destination. For now, this approach inefficiently propagates the old finally state along these chains of finally regions when it encounters them. This has the downside that long finally regions will cause re-analysis until each finally block sees a new state. The finally state is also unified along all such paths, so the warning state at the exit of a finally is a conservative approximation that accounts for all normal control flow leading to the finally region. Additionally, the finally regions are analyzed separately for the case when an exception causes a finally block to be reached. Inside the finally region, this will produce a superset of the warnings for normal control flow inside the same region. However this exceptional finally state does not flow out of the finally, to avoid spurious warnings in code that is unreachable when executing finally blocks due to exceptions. Also, implement a wrapper type where Set automatically meets the exception state. The Set operation is specific to the local dataflow analysis, so this introduces a state interface to track the current/exception state. Only the state type for the local dataflow analysis (LocalDataFlowState) implements this specialized behavior.
Diffstat (limited to 'test/Mono.Linker.Tests.Cases/DataFlow')
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs814
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs35
2 files changed, 827 insertions, 22 deletions
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs
new file mode 100644
index 000000000..40bf18ca7
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs
@@ -0,0 +1,814 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.DataFlow
+{
+ [SkipKeptItemsValidation]
+ public class ExceptionalDataFlow
+ {
+ public static void Main ()
+ {
+ TryFlowsToFinally ();
+ TryFlowsToAfterFinally ();
+ MultipleTryExits ();
+ MultipleFinallyPaths ();
+ FinallyChain ();
+ FinallyChainWithPostFinallyState ();
+ TryFlowsToCatch ();
+ CatchFlowsToFinally ();
+ CatchFlowsToAfterTry ();
+ CatchFlowsToAfterFinally ();
+ FinallyFlowsToAfterFinally ();
+ TryFlowsToMultipleCatchAndFinally ();
+ NestedWithFinally ();
+ ControlFlowsOutOfMultipleFinally ();
+ NestedWithCatch ();
+ CatchInTry ();
+ CatchInTryWithFinally ();
+ TestCatchesHaveSeparateState ();
+ FinallyWithBranchToFirstBlock ();
+ FinallyWithBranchToFirstBlockAndEnclosingTryCatchState ();
+ CatchWithBranchToFirstBlock ();
+ CatchWithBranchToFirstBlockAndReassignment ();
+ CatchWithNonSimplePredecessor ();
+ FinallyWithNonSimplePredecessor ();
+ FinallyInTryWithPredecessor ();
+ NestedFinally ();
+ NestedFinallyWithPredecessor ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void TryFlowsToFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ } finally {
+ // methods/fields/properties
+ RequireAll (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void TryFlowsToAfterFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ } finally {
+ // prevent optimizing this away
+ _ = string.Empty;
+ }
+ // properties
+ RequireAll (t);
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void MultipleTryExits ()
+ {
+ Type t = GetWithPublicConstructors ();
+ for (int i = 0; i < 10; i++) {
+ try {
+ if (string.Empty.Length == 0) {
+ t = GetWithPublicMethods ();
+ return;
+ }
+ if (string.Empty.Length == 1) {
+ t = GetWithPublicFields ();
+ continue;
+ }
+ if (string.Empty.Length == 2) {
+ t = GetWithPublicProperties ();
+ break;
+ }
+ } finally {
+ RequireAll (t);
+ }
+ }
+ }
+
+ // There are multiple paths through the finally to different subsequent blocks.
+ // On each path, only one state is possible, but we conservatively merge the (non-exceptional)
+ // finally states for each path and expect the warnings to reflect this merged state.
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicEvents) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicEvents) + "()")]
+
+ [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicEvents) + "()")]
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
+ public static Type MultipleFinallyPaths ()
+ {
+ Type t = GetWithPublicMethods (); // reaches RequireAll1 and RequireAll2
+ while (true) {
+ RequireAll1 (t);
+ try {
+ if (string.Empty.Length == 1) {
+ t = GetWithPublicFields (); // reaches RequireAll1 and RequireAll2
+ continue;
+ }
+ if (string.Empty.Length == 0) {
+ t = GetWithPublicProperties (); // reaches RequireAll2 only, but the finally mergig means
+ // the analysis thinks it can reach RequireAll1.
+ break;
+ }
+ if (string.Empty.Length == 2) {
+ t = GetWithPublicEvents (); // reaches return only, but the finally merging means
+ // the analysis thinks it can reach RequireAll1 (and hence RequireAll2).
+ return t;
+ }
+ } finally {
+ _ = string.Empty;
+ }
+ }
+ RequireAll2 (t); // properties
+
+ throw new Exception ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void FinallyChain ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ try {
+ t = GetWithPublicProperties ();
+ } finally {
+ RequireAll1 (t); // fields/properties
+ }
+ } finally {
+ RequireAll2 (t); // methods/fields/properties
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void FinallyChainWithPostFinallyState ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ try {
+ t = GetWithPublicProperties ();
+ } finally {
+ // normal: properties
+ // exception: fields/properties
+ RequireAll1 (t); // fields/properties
+ }
+ RequireAll2 (t); // properties
+ } finally {
+ // normal: properties
+ // exception: methods/fields/properties
+ RequireAll3 (t); // methods/fields/properties
+ }
+ RequireAll4 (t);
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void TryFlowsToCatch ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ } catch {
+ // methods/fields/properties
+ RequireAll (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void CatchFlowsToFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ } finally {
+ // methods/fields/properties
+ RequireAll (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void CatchFlowsToAfterTry ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ }
+ // methods/properties, not fields
+ RequireAll (t);
+ }
+
+
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void CatchFlowsToAfterFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ } finally { }
+ // methods/properties, not fields
+ RequireAll (t);
+ }
+
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void FinallyFlowsToAfterFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } finally {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ }
+ // properties only
+ RequireAll (t);
+ }
+
+ public class Exception1 : Exception { }
+ public class Exception2 : Exception { }
+
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicEvents) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicEvents) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+
+
+ public static void TryFlowsToMultipleCatchAndFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ RequireAll1 (t); // fields only
+ } catch (Exception1) {
+ RequireAll2 (t); // methods/fields
+ t = GetWithPublicProperties ();
+ RequireAll3 (t); // properties only
+ } catch (Exception2) {
+ RequireAll4 (t); // methods/fields
+ t = GetWithPublicEvents ();
+ RequireAll5 (t); // events only
+ } finally {
+ RequireAll6 (t); // methods/fields/properties/events
+ t = GetWithPublicConstructors ();
+ RequireAll7 (t); // ctors only
+ }
+ RequireAll (t);
+ }
+
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicConstructors) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+
+ public static void NestedWithFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ try {
+ // fields
+ t = GetWithPublicProperties ();
+ } finally {
+ // fields/properties
+ RequireAll1 (t);
+ t = GetWithPublicEvents ();
+ t = GetWithPublicConstructors ();
+ }
+ // ctors
+ RequireAll2 (t);
+ } finally {
+ // methods/fields/properties/events/constructors
+ RequireAll3 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()")]
+ public static void ControlFlowsOutOfMultipleFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ try {
+ try {
+ t = GetWithPublicFields ();
+ } finally {
+ // methods/fields
+ RequireAll1 (t);
+ t = GetWithPublicProperties ();
+ }
+ } finally {
+ // methods/fields/properties
+ RequireAll2 (t);
+ t = GetWithPublicEvents ();
+ }
+ } finally {
+ // methods/fields/propreties/events
+ RequireAll3 (t);
+ }
+ }
+
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+
+ public static void NestedWithCatch ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ try {
+ // fields
+ t = GetWithPublicProperties ();
+ } catch {
+ // fields/properties
+ RequireAll1 (t);
+ t = GetWithPublicEvents ();
+ t = GetWithPublicConstructors ();
+ }
+ // properties/ctors
+ RequireAll2 (t);
+ } catch {
+ // methods/fields/properties/events/constructors
+ RequireAll3 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()")]
+ public static void CatchInTry ()
+ {
+ try {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ t = GetWithPublicFields ();
+ RequireAll (t);
+ }
+ } catch {
+ }
+ }
+
+ // This tests a case where the catch state was being merged with the containing try state incorrectly.
+ // In the bug, the exceptional catch state, which is used in the finally, had too much in it.
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")]
+ // The bug was producing this warning:
+ // [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")]
+ public static void CatchInTryWithFinally ()
+ {
+ Type t = GetWithPublicConstructors ();
+ try {
+ t = GetWithPublicMethods ();
+ // methods
+ // ex: ctors/methods
+ try {
+ // methods
+ // ex: methods
+ } catch {
+ // methods
+ t = GetWithPublicFields ();
+ // fields
+ // ex: methods/fields
+ RequireAll1 (t);
+ } finally {
+ // normal state: fields
+ // exceptional state: methods/fields
+ RequireAll2 (t);
+ }
+ } catch {
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+
+ public static void TestCatchesHaveSeparateState ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch (Exception1) {
+ t = GetWithPublicFields ();
+ } catch (Exception2) {
+ // methods only!
+ RequireAll (t);
+ } finally {
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ public static void FinallyWithBranchToFirstBlock ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } finally {
+ FinallyStart:
+ RequireAll (t);
+ t = GetWithPublicFields ();
+ goto FinallyStart;
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ public static void FinallyWithBranchToFirstBlockAndEnclosingTryCatchState ()
+ {
+ try {
+ Type t = GetWithPublicProperties ();
+ t = GetWithPublicMethods ();
+ try {
+ } finally {
+ FinallyStart:
+ // methods/fields
+ RequireAll (t);
+ t = GetWithPublicFields ();
+ goto FinallyStart;
+ }
+ } finally {
+ // An operation just to prevent optimizing away
+ // the try/finally.
+ _ = String.Empty;
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ public static void CatchWithBranchToFirstBlock ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ CatchStart:
+ RequireAll (t);
+ t = GetWithPublicFields ();
+ goto CatchStart;
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")]
+ [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ public static void CatchWithBranchToFirstBlockAndReassignment ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ } catch {
+ CatchStart:
+ RequireAll (t); // methods/fields, but not properties!
+ t = GetWithPublicProperties ();
+ t = GetWithPublicFields ();
+ goto CatchStart;
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void CatchWithNonSimplePredecessor ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ try {
+ // properties only
+ } catch {
+ // properties only.
+ RequireAll1 (t);
+ }
+ } catch {
+ // methods/fields/properties
+ RequireAll2 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void FinallyWithNonSimplePredecessor ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ try {
+ // properties only
+ } catch {
+ // properties only.
+ RequireAll1 (t);
+ }
+ } finally {
+ // methods/fields/properties
+ RequireAll2 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void FinallyInTryWithPredecessor ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ t = GetWithPublicProperties ();
+ try {
+ // properties only
+ } finally {
+ // properties only.
+ RequireAll1 (t);
+ }
+ } finally {
+ // methods/fields/properties
+ RequireAll2 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void NestedFinally ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ } finally {
+ try {
+ RequireAll1 (t);
+ t = GetWithPublicProperties ();
+ } finally {
+ RequireAll2 (t);
+ }
+ RequireAll3 (t);
+ }
+ }
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+
+ [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")]
+ public static void NestedFinallyWithPredecessor ()
+ {
+ Type t = GetWithPublicMethods ();
+ try {
+ t = GetWithPublicFields ();
+ } finally {
+ _ = 0; // add an operation so that the try isn't the start of the finally.
+ try {
+ RequireAll1 (t);
+ t = GetWithPublicProperties ();
+ } finally {
+ RequireAll2 (t);
+ }
+ RequireAll3 (t);
+ }
+ }
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
+ public static Type GetWithPublicMethods ()
+ {
+ return null;
+ }
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)]
+ public static Type GetWithPublicFields ()
+ {
+ return null;
+ }
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)]
+ public static Type GetWithPublicProperties ()
+ {
+ return null;
+ }
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)]
+ public static Type GetWithPublicEvents ()
+ {
+ return null;
+ }
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
+ public static Type GetWithPublicConstructors ()
+ {
+ return null;
+ }
+
+ public static void RequirePublicMethods (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ Type type)
+ {
+ }
+
+ public static void RequirePublicFields (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
+ Type type)
+ {
+ }
+ public static void RequirePublicProperties (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
+ Type type)
+ {
+ }
+
+
+ public static void RequireFieldsAndProperties (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)]
+ Type type)
+ {
+ }
+
+ public static void RequireAll (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll1 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll2 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll3 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll4 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll5 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll6 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ public static void RequireAll7 (
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type type)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs
index 2f0243938..75f162786 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs
@@ -23,7 +23,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow
TestBranchMergeSwitch ();
TestBranchMergeTry ();
TestBranchMergeCatch ();
- TestBranchMergeFinally ();
// The remaining tests illustrate current limitations of the analysis
// that we might be able to lift in the future.
@@ -36,6 +35,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
TestBranchTry ();
TestBranchCatch ();
TestBranchFinally ();
+ TestBranchMergeFinally ();
// These are missing warnings (potential failure at runtime)
TestBackwardsEdgeGoto ();
@@ -127,13 +127,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)",
- nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
- ProducedBy = ProducedBy.Trimmer)]
+ nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()")]
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)",
- nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()",
- ProducedBy = ProducedBy.Trimmer)]
+ nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()")]
public static void TestBranchMergeTry ()
{
string str = GetWithPublicMethods ();
@@ -150,13 +147,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)",
- nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
- ProducedBy = ProducedBy.Trimmer)]
+ nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()")]
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)",
- nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()",
- ProducedBy = ProducedBy.Trimmer)]
+ nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()")]
public static void TestBranchMergeCatch ()
{
string str = GetWithPublicMethods ();
@@ -171,14 +165,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow
str.RequiresPublicMethods (); // warns for GetWithPublicFields
}
-
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
+ [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)",
+ nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()")]
+ // Linker produces extraneous warnings
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)",
nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)",
- nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()",
- ProducedBy = ProducedBy.Trimmer)]
public static void TestBranchMergeFinally ()
{
string str = GetWithPublicMethods ();
@@ -189,9 +181,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
} finally {
str = GetWithPublicFields ();
}
-
- str.RequiresPublicFields (); // warns for GetWithPublicMethods
- str.RequiresPublicMethods (); // warns for GetWithPublicFields
+ str.RequiresPublicFields (); // should not warn
+ str.RequiresPublicMethods (); // should warn
}
// Analyzer gets this right (no warning), but trimmer merges all branches going forward.
@@ -267,7 +258,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
}
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
+ // Analyzer gets this right (no warning), but trimmer merges all branches going forward.
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields),
nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
ProducedBy = ProducedBy.Trimmer)]
@@ -284,7 +275,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
}
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
+ // Analyzer gets this right (no warning), but trimmer merges all branches going forward.
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields),
nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
ProducedBy = ProducedBy.Trimmer)]
@@ -300,7 +291,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
}
- // Analyzer doesn't understand exceptional control flow yet (https://github.com/dotnet/linker/issues/2273)
+ // Analyzer gets this right (no warning), but trimmer merges all branches going forward.
[ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields),
nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()",
ProducedBy = ProducedBy.Trimmer)]