diff --git a/Confuser.Core/Confuser.Core.csproj b/Confuser.Core/Confuser.Core.csproj
index 333ad1d15..1347f0e07 100644
--- a/Confuser.Core/Confuser.Core.csproj
+++ b/Confuser.Core/Confuser.Core.csproj
@@ -94,6 +94,7 @@
+
diff --git a/Confuser.Core/Project/PatternParser.cs b/Confuser.Core/Project/PatternParser.cs
index f839aaa70..5f894fab2 100644
--- a/Confuser.Core/Project/PatternParser.cs
+++ b/Confuser.Core/Project/PatternParser.cs
@@ -26,6 +26,7 @@ static PatternParser() {
fns.Add(IsPublicFunction.FnName, () => new IsPublicFunction());
fns.Add(InheritsFunction.FnName, () => new InheritsFunction());
fns.Add(IsTypeFunction.FnName, () => new IsTypeFunction());
+ fns.Add(HasAttrFunction.FnName, () => new HasAttrFunction());
ops = new Dictionary>(StringComparer.OrdinalIgnoreCase);
ops.Add(AndOperator.OpName, () => new AndOperator());
diff --git a/Confuser.Core/Project/Patterns/HasAttrFunction.cs b/Confuser.Core/Project/Patterns/HasAttrFunction.cs
new file mode 100644
index 000000000..8b9c10d7b
--- /dev/null
+++ b/Confuser.Core/Project/Patterns/HasAttrFunction.cs
@@ -0,0 +1,27 @@
+using System;
+using dnlib.DotNet;
+
+namespace Confuser.Core.Project.Patterns {
+ ///
+ /// A function that indicate whether the item has the given custom attribute.
+ ///
+ public class HasAttrFunction : PatternFunction {
+ internal const string FnName = "has-attr";
+
+ ///
+ public override string Name {
+ get { return FnName; }
+ }
+
+ ///
+ public override int ArgumentCount {
+ get { return 1; }
+ }
+
+ ///
+ public override object Evaluate(IDnlibDef definition) {
+ string attrName = Arguments[0].Evaluate(definition).ToString();
+ return definition.CustomAttributes.IsDefined(attrName);
+ }
+ }
+}
\ No newline at end of file