[mcs] Validate more nameof argument expressions
authorMarek Safar <marek.safar@gmail.com>
Thu, 4 Dec 2014 13:18:18 +0000 (14:18 +0100)
committerMarek Safar <marek.safar@gmail.com>
Thu, 4 Dec 2014 13:18:18 +0000 (14:18 +0100)
20 files changed:
mcs/errors/cs0103-16.cs [new file with mode: 0644]
mcs/errors/cs7003-6.cs [new file with mode: 0644]
mcs/errors/cs7003-7.cs [new file with mode: 0644]
mcs/errors/cs7003-8.cs [new file with mode: 0644]
mcs/errors/cs8081-2.cs [new file with mode: 0644]
mcs/errors/cs8081.cs [new file with mode: 0644]
mcs/errors/cs8082.cs [new file with mode: 0644]
mcs/errors/cs8083.cs [new file with mode: 0644]
mcs/errors/cs8084-2.cs [new file with mode: 0644]
mcs/errors/cs8084.cs [new file with mode: 0644]
mcs/mcs/complete.cs
mcs/mcs/constant.cs
mcs/mcs/cs-parser.jay
mcs/mcs/dynamic.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/generic.cs
mcs/tests/test-named-09.cs [new file with mode: 0644]
mcs/tests/test-pattern-06.cs
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0103-16.cs b/mcs/errors/cs0103-16.cs
new file mode 100644 (file)
index 0000000..da73c33
--- /dev/null
@@ -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 (file)
index 0000000..7c6fe68
--- /dev/null
@@ -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 (file)
index 0000000..e7bdd50
--- /dev/null
@@ -0,0 +1,14 @@
+// CS7003: Unbound generic name is not valid in this context
+// Line: 12
+
+static class C
+{
+       static void Foo<T> ()
+       {
+       }
+
+       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 (file)
index 0000000..04d8b2c
--- /dev/null
@@ -0,0 +1,14 @@
+// CS7003: Unbound generic name is not valid in this context
+// Line: 12
+
+static class C
+{
+       static void Foo<T> ()
+       {
+       }
+
+       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 (file)
index 0000000..dcc1583
--- /dev/null
@@ -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 (file)
index 0000000..366b932
--- /dev/null
@@ -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 (file)
index 0000000..70afa6b
--- /dev/null
@@ -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 (file)
index 0000000..26b90c8
--- /dev/null
@@ -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 (file)
index 0000000..8a5b004
--- /dev/null
@@ -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<T> ()
+       {
+       }
+
+       static void Main ()
+       {
+               string s = nameof (C.Foo<int>);
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8084.cs b/mcs/errors/cs8084.cs
new file mode 100644 (file)
index 0000000..c5861b5
--- /dev/null
@@ -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<T> ()
+       {
+       }
+
+       static void Main ()
+       {
+               string s = nameof (Foo<int>);
+       }
+}
\ No newline at end of file
index 3504302d589d0e44fd642fe987eea93c51fe1b5f..749c4efcb8a4c99e70920f64be7d008a068e2d51 100644 (file)
@@ -142,7 +142,7 @@ namespace Mono.CSharp {
                        }
 
                        if (targs != null) {
-                               if (!targs.Resolve (rc))
+                               if (!targs.Resolve (rc, true))
                                        return null;
                        }
 
index 18763aa82265e5966f2419fd2ae3cbefd06edc65..050dd83490f32849fde3ec477cfee0f848c8de34 100644 (file)
@@ -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;
                        }
 
index ed173cc5e4ba7348e081dce13772aa27f9718778..16f79e22c3c8ca4a1ec8ec5922e5d5d3b231f7b3 100644 (file)
@@ -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));
index 8a9a0c87de2eb00488f65b94a1ea4b0ec348405d..33fb4555363aa6a795a0b2f0d45ba65d46b5170f 100644 (file)
@@ -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));
index a02b28c9d847c1b14929aac195aea6221ef2f8e3..80e13f33aae8b64561f0d344190bc94dfc741f76 100644 (file)
@@ -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) {
index 017ef439f11c42f6a74ebe9dbed7935ab733b6a4..deb121c140da9e232d7a8518aa7fe30dfa6beba2 100644 (file)
@@ -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);
                                }
index f549432b29ab1330142ff0291f4bf4b8eacda448..304f0e52b0afd8bb2dbfa595c3545e3a35b08653 100644 (file)
@@ -2186,7 +2186,7 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Resolve the type arguments.
                /// </summary>
-               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 (file)
index 0000000..a44dca3
--- /dev/null
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+class X
+{
+       public static int Main ()
+       {
+               switch (nameof (Dictionary<int,int>.Add)) {
+                       case nameof (List<int>.Equals):
+                               return 1;
+                       case nameof(List<int>.Add):
+                               return 0;
+                       default:
+                               return 2;
+               }               
+       }
+}
\ No newline at end of file
index 3b54b840acf9088d8058fadcd5d97a863badf19e..335f075e997d785da861d1ce380f73d072d4801f 100644 (file)
@@ -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:
index c102999bf27bd83607948fdf068874bee0ebaa53..fd4e9ad17ad44530263c6b02f21a7a1aa6a86e93 100644 (file)
       </method>\r
     </type>\r
   </test>\r
+  <test name="test-named-09.cs">\r
+    <type name="X">\r
+      <method name="Int32 Main()" attrs="150">\r
+        <size>11</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
   <test name="test-nameof-01.cs">\r
     <type name="X">\r
       <method name="Int32 Main()" attrs="150">\r
   <test name="test-pattern-06.cs">\r
     <type name="RecursiveNamedPattern">\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>182</size>\r
+        <size>159</size>\r
       </method>\r
       <method name="Int32 Switch_1(System.Object)" attrs="145">\r
-        <size>149</size>\r
+        <size>53</size>\r
       </method>\r
       <method name="Int32 Switch_2(C1)" attrs="145">\r
         <size>28</size>\r