#if NET20 || NET30 || NET35 || !NET_4_6
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
/*============================================================
**
**
**
** Implementation details of CLR Contracts.
**
===========================================================*/
#define DEBUG // The behavior of this contract library should be consistent regardless of build type.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Security;
//using System.Security.Permissions;
namespace System.Diagnostics.Contracts
{
public static partial class Contract
{
[ThreadStatic]
private static bool _assertingMustUseRewriter;
///
/// Allows a managed application environment such as an interactive interpreter (IronPython)
/// to be notified of contract failures and
/// potentially "handle" them, either by throwing a particular exception type, etc. If any of the
/// event handlers sets the Cancel flag in the ContractFailedEventArgs, then the Contract class will
/// not pop up an assert dialog box or trigger escalation policy. Hooking this event requires
/// full trust, because it will inform you of bugs in the appdomain and because the event handler
/// could allow you to continue execution.
///
public static event EventHandler ContractFailed
{
[SecurityCritical]
//[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
add { ContractHelper.InternalContractFailed += value; }
[SecurityCritical]
//[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
remove { ContractHelper.InternalContractFailed -= value; }
}
[SecuritySafeCritical]
private static void AssertMustUseRewriter(ContractFailureKind kind, string contractKind)
{
if (_assertingMustUseRewriter)
{
ContractHelperEx.Fail("Asserting that we must use the rewriter went reentrant."); // Didn't rewrite this mscorlib?
}
_assertingMustUseRewriter = true;
// For better diagnostics, report which assembly is at fault. Walk up stack and
// find the first non-mscorlib assembly.
var thisAssembly = typeof(Contract).Assembly; // In case we refactor mscorlib, use Contract class instead of Object.
var stack = new StackTrace();
Assembly probablyNotRewritten = null;
for (var i = 0; i < stack.FrameCount; i++)
{
var declaringType = stack.GetFrame(i).GetMethod().DeclaringType;
if (declaringType == null)
{
// Not standard method info - ignoring
continue;
}
var caller = declaringType.Assembly;
if (thisAssembly.Equals(caller))
{
continue;
}
probablyNotRewritten = caller;
break;
}
if (probablyNotRewritten == null)
{
probablyNotRewritten = thisAssembly;
}
var simpleName = probablyNotRewritten.GetName().Name;
ContractHelper.TriggerFailure(kind, string.Format("The code has not been rewriten. ContractKind: {0} - Source: {1}", contractKind, simpleName), null, null, null);
_assertingMustUseRewriter = false;
}
[DebuggerNonUserCode]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static void ReportFailure(ContractFailureKind failureKind, string userMessage, string conditionText, Exception innerException)
{
if (failureKind < ContractFailureKind.Precondition || failureKind > ContractFailureKind.Assume)
{
throw new ArgumentException(string.Format("Invalid enum value: {0}", failureKind), "failureKind");
}
EndContractBlock();
// displayMessage == null means: yes we handled it. Otherwise it is the localized failure message
var displayMessage = ContractHelper.RaiseContractFailedEvent(failureKind, userMessage, conditionText, innerException);
if (displayMessage == null)
{
return;
}
ContractHelper.TriggerFailure(failureKind, displayMessage, userMessage, conditionText, innerException);
}
}
}
#endif