From 336755ca9edfbb0dd5c395f59a398c76449f7fdc Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Thu, 4 Dec 2014 14:18:18 +0100 Subject: [mcs] Validate more nameof argument expressions --- mcs/errors/cs0103-16.cs | 10 ++++++++ mcs/errors/cs7003-6.cs | 10 ++++++++ mcs/errors/cs7003-7.cs | 14 +++++++++++ mcs/errors/cs7003-8.cs | 14 +++++++++++ mcs/errors/cs8081-2.cs | 10 ++++++++ mcs/errors/cs8081.cs | 10 ++++++++ mcs/errors/cs8082.cs | 11 +++++++++ mcs/errors/cs8083.cs | 10 ++++++++ mcs/errors/cs8084-2.cs | 14 +++++++++++ mcs/errors/cs8084.cs | 14 +++++++++++ mcs/mcs/complete.cs | 2 +- mcs/mcs/constant.cs | 55 +++++++++++++++++++++++++++++++++++++++++--- mcs/mcs/cs-parser.jay | 2 ++ mcs/mcs/dynamic.cs | 2 +- mcs/mcs/ecore.cs | 21 +++++++---------- mcs/mcs/expression.cs | 22 ++++++++++-------- mcs/mcs/generic.cs | 15 ++++++++---- mcs/tests/test-named-09.cs | 16 +++++++++++++ mcs/tests/test-pattern-06.cs | 12 +++++----- mcs/tests/ver-il-net_4_5.xml | 14 +++++++++-- 20 files changed, 238 insertions(+), 40 deletions(-) create mode 100644 mcs/errors/cs0103-16.cs create mode 100644 mcs/errors/cs7003-6.cs create mode 100644 mcs/errors/cs7003-7.cs create mode 100644 mcs/errors/cs7003-8.cs create mode 100644 mcs/errors/cs8081-2.cs create mode 100644 mcs/errors/cs8081.cs create mode 100644 mcs/errors/cs8082.cs create mode 100644 mcs/errors/cs8083.cs create mode 100644 mcs/errors/cs8084-2.cs create mode 100644 mcs/errors/cs8084.cs create mode 100644 mcs/tests/test-named-09.cs diff --git a/mcs/errors/cs0103-16.cs b/mcs/errors/cs0103-16.cs new file mode 100644 index 00000000000..da73c33c0a7 --- /dev/null +++ b/mcs/errors/cs0103-16.cs @@ -0,0 +1,10 @@ +// CS0103: The name `nameof' does not exist in the current context +// Line: 8 + +static class C +{ + static void Main () + { + string s = nameof (nameof); + } +} \ No newline at end of file diff --git a/mcs/errors/cs7003-6.cs b/mcs/errors/cs7003-6.cs new file mode 100644 index 00000000000..7c6fe68d46b --- /dev/null +++ b/mcs/errors/cs7003-6.cs @@ -0,0 +1,10 @@ +// CS7003: Unbound generic name is not valid in this context +// Line: 8 + +class C +{ + static void Main () + { + System.Action<>.Combine (); + } +} \ No newline at end of file diff --git a/mcs/errors/cs7003-7.cs b/mcs/errors/cs7003-7.cs new file mode 100644 index 00000000000..e7bdd50145c --- /dev/null +++ b/mcs/errors/cs7003-7.cs @@ -0,0 +1,14 @@ +// CS7003: Unbound generic name is not valid in this context +// Line: 12 + +static class C +{ + static void Foo () + { + } + + static void Main () + { + string s = nameof (Foo<>); + } +} \ No newline at end of file diff --git a/mcs/errors/cs7003-8.cs b/mcs/errors/cs7003-8.cs new file mode 100644 index 00000000000..04d8b2c57d5 --- /dev/null +++ b/mcs/errors/cs7003-8.cs @@ -0,0 +1,14 @@ +// CS7003: Unbound generic name is not valid in this context +// Line: 12 + +static class C +{ + static void Foo () + { + } + + static void Main () + { + string s = nameof (C.Foo<>); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8081-2.cs b/mcs/errors/cs8081-2.cs new file mode 100644 index 00000000000..dcc1583db8a --- /dev/null +++ b/mcs/errors/cs8081-2.cs @@ -0,0 +1,10 @@ +// CS8081: Expression does not have a name +// Line: 8 + +class C +{ + void Foo () + { + string s = nameof (this); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8081.cs b/mcs/errors/cs8081.cs new file mode 100644 index 00000000000..366b9326a83 --- /dev/null +++ b/mcs/errors/cs8081.cs @@ -0,0 +1,10 @@ +// CS8081: Expression does not have a name +// Line: 8 + +class C +{ + static void Main () + { + string s = nameof (Main ()); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8082.cs b/mcs/errors/cs8082.cs new file mode 100644 index 00000000000..70afa6b7e79 --- /dev/null +++ b/mcs/errors/cs8082.cs @@ -0,0 +1,11 @@ +// CS8082: An argument to nameof operator cannot include sub-expression +// Line: 9 + +class C +{ + void Foo () + { + object o = null; + var s = nameof (o.ToString ().Equals); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8083.cs b/mcs/errors/cs8083.cs new file mode 100644 index 00000000000..26b90c846a9 --- /dev/null +++ b/mcs/errors/cs8083.cs @@ -0,0 +1,10 @@ +// CS8083: An alias-qualified name is not an expression +// Line: 8 + +class C +{ + static void Main () + { + string s = nameof (global::C); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8084-2.cs b/mcs/errors/cs8084-2.cs new file mode 100644 index 00000000000..8a5b00425dd --- /dev/null +++ b/mcs/errors/cs8084-2.cs @@ -0,0 +1,14 @@ +// CS8084: An argument to nameof operator cannot be method group with type arguments +// Line: 12 + +static class C +{ + static void Foo () + { + } + + static void Main () + { + string s = nameof (C.Foo); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8084.cs b/mcs/errors/cs8084.cs new file mode 100644 index 00000000000..c5861b515f6 --- /dev/null +++ b/mcs/errors/cs8084.cs @@ -0,0 +1,14 @@ +// CS8084: An argument to nameof operator cannot be method group with type arguments +// Line: 12 + +static class C +{ + static void Foo () + { + } + + static void Main () + { + string s = nameof (Foo); + } +} \ No newline at end of file diff --git a/mcs/mcs/complete.cs b/mcs/mcs/complete.cs index 3504302d589..749c4efcb8a 100644 --- a/mcs/mcs/complete.cs +++ b/mcs/mcs/complete.cs @@ -142,7 +142,7 @@ namespace Mono.CSharp { } if (targs != null) { - if (!targs.Resolve (rc)) + if (!targs.Resolve (rc, true)) return null; } diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs index 18763aa8226..050dd83490f 100644 --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -2144,6 +2144,11 @@ namespace Mono.CSharp { this.name = name; } + static void Error_MethodGroupWithTypeArguments (ResolveContext rc, Location loc) + { + rc.Report.Error (8084, loc, "An argument to nameof operator cannot be method group with type arguments"); + } + protected override Expression DoResolve (ResolveContext rc) { throw new NotSupportedException (); @@ -2158,20 +2163,37 @@ namespace Mono.CSharp { if (rc.Module.Compiler.Settings.Version < LanguageVersion.V_6) rc.Report.FeatureIsNotAvailable (rc.Module.Compiler, Location, "nameof operator"); - sn.LookupNameExpression (rc, MemberLookupRestrictions.IgnoreAmbiguity); + var res = sn.LookupNameExpression (rc, MemberLookupRestrictions.IgnoreAmbiguity | MemberLookupRestrictions.NameOfExcluded); + if (sn.HasTypeArguments && res is MethodGroupExpr) { + Error_MethodGroupWithTypeArguments (rc, expr.Location); + } + return true; } var ma = expr as MemberAccess; if (ma != null) { + var lexpr = ma.LeftExpression; + var res = ma.LookupNameExpression (rc, MemberLookupRestrictions.IgnoreAmbiguity); - if (res == null) + if (res == null) { return false; + } if (rc.Module.Compiler.Settings.Version < LanguageVersion.V_6) rc.Report.FeatureIsNotAvailable (rc.Module.Compiler, Location, "nameof operator"); + if (ma is QualifiedAliasMember) { + rc.Report.Error (8083, loc, "An alias-qualified name is not an expression"); + return false; + } + + if (!IsLeftExpressionValid (lexpr)) { + rc.Report.Error (8082, lexpr.Location, "An argument to nameof operator cannot include sub-expression"); + return false; + } + var mg = res as MethodGroupExpr; if (mg != null) { var emg = res as ExtensionMethodGroupExpr; @@ -2182,12 +2204,40 @@ namespace Mono.CSharp { if (!mg.HasAccessibleCandidate (rc)) { ErrorIsInaccesible (rc, ma.GetSignatureForError (), loc); } + + if (ma.HasTypeArguments) { + Error_MethodGroupWithTypeArguments (rc, ma.Location); + } } Value = ma.Name; return true; } + rc.Report.Error (8081, loc, "Expression does not have a name"); + return false; + } + + static bool IsLeftExpressionValid (Expression expr) + { + if (expr is SimpleName) + return true; + + if (expr is This) + return true; + + if (expr is NamespaceExpression) + return true; + + if (expr is TypeExpr) + return true; + + var ma = expr as MemberAccess; + if (ma != null) { + // TODO: Will conditional access be allowed? + return IsLeftExpressionValid (ma.LeftExpression); + } + return false; } @@ -2201,7 +2251,6 @@ namespace Mono.CSharp { var arg = args [0]; var res = ResolveArgumentExpression (rc, arg.Expr); if (!res) { - name.Error_NameDoesNotExist (rc); return null; } diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index ed173cc5e4b..16f79e22c3c 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -5929,6 +5929,7 @@ switch_label Error_SyntaxError (yyToken); $$ = new SwitchLabel ((Expression) $2, GetLocation ($1)); } +/* | CASE pattern_expr_invocation COLON { if (lang_version != LanguageVersion.Experimental) @@ -5939,6 +5940,7 @@ switch_label }; lbag.AddLocation ($$, GetLocation ($3)); } +*/ | DEFAULT_COLON { $$ = new SwitchLabel (null, GetLocation ($1)); diff --git a/mcs/mcs/dynamic.cs b/mcs/mcs/dynamic.cs index 8a9a0c87de2..33fb4555363 100644 --- a/mcs/mcs/dynamic.cs +++ b/mcs/mcs/dynamic.cs @@ -787,7 +787,7 @@ namespace Mono.CSharp if (member != null && member.HasTypeArguments) { TypeArguments ta = member.TypeArguments; - if (ta.Resolve (ec)) { + if (ta.Resolve (ec, false)) { var targs = new ArrayInitializer (ta.Count, loc); foreach (TypeSpec t in ta.Arguments) targs.Add (new TypeOf (t, loc)); diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index a02b28c9d84..80e13f33aae 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -819,7 +819,8 @@ namespace Mono.CSharp { ReadAccess = 1 << 3, EmptyArguments = 1 << 4, IgnoreArity = 1 << 5, - IgnoreAmbiguity = 1 << 6 + IgnoreAmbiguity = 1 << 6, + NameOfExcluded = 1 << 7, } // @@ -2521,7 +2522,7 @@ namespace Mono.CSharp { } protected ATypeNameExpression (string name, int arity, Location l) - : this (name, new UnboundTypeArguments (arity), l) + : this (name, new UnboundTypeArguments (arity, l), l) { } @@ -2563,11 +2564,6 @@ namespace Mono.CSharp { (targs == null || targs.Equals (atne.targs)); } - protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc) - { - mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context"); - } - public override int GetHashCode () { return Name.GetHashCode (); @@ -2703,8 +2699,7 @@ namespace Mono.CSharp { return ct; } - if (!allowUnboundTypeArguments) - Error_OpenGenericTypeIsNotAllowed (mc); + targs.Resolve (mc, allowUnboundTypeArguments); return new GenericOpenTypeExpr (fne.Type, loc); } @@ -2839,7 +2834,7 @@ namespace Mono.CSharp { me = me.ResolveMemberAccess (rc, null, null); if (Arity > 0) { - targs.Resolve (rc); + targs.Resolve (rc, false); me.SetTypeArguments (rc, targs); } @@ -2863,13 +2858,13 @@ namespace Mono.CSharp { var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc); if (mg != null) { if (Arity > 0) { - targs.Resolve (rc); + targs.Resolve (rc, false); mg.SetTypeArguments (rc, targs); } return mg; } - if (Name == "nameof") + if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof") return new NameOf (this); if (errorMode) { @@ -3130,7 +3125,7 @@ namespace Mono.CSharp { return this; } - public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity) + public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc) { var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc); if (retval != null) { diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 017ef439f11..deb121c140d 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -9666,12 +9666,16 @@ namespace Mono.CSharp var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc); if (retval == null) { - ns.Error_NamespaceDoesNotExist (rc, Name, Arity); + ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc); return null; } - if (HasTypeArguments) - return new GenericTypeExpr (retval.Type, targs, loc); + if (Arity > 0) { + if (HasTypeArguments) + return new GenericTypeExpr (retval.Type, targs, loc); + + targs.Resolve (rc, false); + } return retval; } @@ -9720,7 +9724,7 @@ namespace Mono.CSharp if (methods != null) { var emg = new ExtensionMethodGroupExpr (methods, expr, loc); if (HasTypeArguments) { - if (!targs.Resolve (rc)) + if (!targs.Resolve (rc, false)) return null; emg.SetTypeArguments (rc, targs); @@ -9799,7 +9803,7 @@ namespace Mono.CSharp me = me.ResolveMemberAccess (rc, expr, sn); if (Arity > 0) { - if (!targs.Resolve (rc)) + if (!targs.Resolve (rc, false)) return null; me.SetTypeArguments (rc, targs); @@ -9826,15 +9830,14 @@ namespace Mono.CSharp FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc); if (retval == null) { - ns.Error_NamespaceDoesNotExist (rc, Name, Arity); + ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc); } else if (Arity > 0) { if (HasTypeArguments) { retval = new GenericTypeExpr (retval.Type, targs, loc); if (retval.ResolveAsType (rc) == null) return null; } else { - if (!allowUnboundTypeArguments) - Error_OpenGenericTypeIsNotAllowed (rc); + targs.Resolve (rc, allowUnboundTypeArguments); retval = new GenericOpenTypeExpr (retval.Type, loc); } @@ -9895,8 +9898,7 @@ namespace Mono.CSharp if (HasTypeArguments) { texpr = new GenericTypeExpr (nested, targs, loc); } else { - if (!allowUnboundTypeArguments || expr_resolved is GenericTypeExpr) // && HasTypeArguments - Error_OpenGenericTypeIsNotAllowed (rc); + targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr)); texpr = new GenericOpenTypeExpr (nested, loc); } diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index f549432b29a..304f0e52b0a 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -2186,7 +2186,7 @@ namespace Mono.CSharp { /// /// Resolve the type arguments. /// - public virtual bool Resolve (IMemberContext ec) + public virtual bool Resolve (IMemberContext ec, bool allowUnbound) { if (atypes != null) return true; @@ -2239,9 +2239,12 @@ namespace Mono.CSharp { public class UnboundTypeArguments : TypeArguments { - public UnboundTypeArguments (int arity) + Location loc; + + public UnboundTypeArguments (int arity, Location loc) : base (new FullNamedExpression[arity]) { + this.loc = loc; } public override bool IsEmpty { @@ -2250,8 +2253,12 @@ namespace Mono.CSharp { } } - public override bool Resolve (IMemberContext ec) + public override bool Resolve (IMemberContext mc, bool allowUnbound) { + if (!allowUnbound) { + mc.Module.Compiler.Report.Error (7003, loc, "Unbound generic name is not valid in this context"); + } + // Nothing to be resolved return true; } @@ -2437,7 +2444,7 @@ namespace Mono.CSharp { if (eclass != ExprClass.Unresolved) return type; - if (!args.Resolve (mc)) + if (!args.Resolve (mc, allowUnboundTypeArguments)) return null; TypeSpec[] atypes = args.Arguments; diff --git a/mcs/tests/test-named-09.cs b/mcs/tests/test-named-09.cs new file mode 100644 index 00000000000..a44dca3a154 --- /dev/null +++ b/mcs/tests/test-named-09.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +class X +{ + public static int Main () + { + switch (nameof (Dictionary.Add)) { + case nameof (List.Equals): + return 1; + case nameof(List.Add): + return 0; + default: + return 2; + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-06.cs b/mcs/tests/test-pattern-06.cs index 3b54b840acf..335f075e997 100644 --- a/mcs/tests/test-pattern-06.cs +++ b/mcs/tests/test-pattern-06.cs @@ -15,8 +15,8 @@ class RecursiveNamedPattern if (Switch_1 (1) != 1) return 3; - if (Switch_1 (new C1 ()) != 3) - return 4; +// if (Switch_1 (new C1 ()) != 3) +// return 4; if (Switch_1 ((byte?) 1) != 1) return 5; @@ -36,10 +36,10 @@ class RecursiveNamedPattern switch (o) { case 1: return 1; - case C1 (3): - return 2; - case C1 (2): - return 3; +// case C1 (3): +// return 2; +// case C1 (2): +// return 3; case null: return 4; default: diff --git a/mcs/tests/ver-il-net_4_5.xml b/mcs/tests/ver-il-net_4_5.xml index c102999bf27..fd4e9ad17ad 100644 --- a/mcs/tests/ver-il-net_4_5.xml +++ b/mcs/tests/ver-il-net_4_5.xml @@ -67820,6 +67820,16 @@ + + + + 11 + + + 7 + + + @@ -69101,10 +69111,10 @@ - 182 + 159 - 149 + 53 28 -- cgit v1.2.3