[asp.net] Fix for bug #633756. Children processed as properties must be instantiated...
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateControlCompiler.cs
index aea733af7795c9a3709612295f92760a25f9698b..c026fed03793a874708921c7368e70625d330c17 100644 (file)
@@ -161,12 +161,35 @@ namespace System.Web.Compilation
                        invoke.Parameters.Add (expr);
                        builder.MethodStatements.Add (AddLinePragma (invoke, builder));
                }
+
+               CodeStatement CreateControlVariable (Type type, ControlBuilder builder, CodeMemberMethod method, CodeTypeReference ctrlTypeRef)
+               {
+                       CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (ctrlTypeRef);
+
+                       object [] atts = type != null ? type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true) : null;
+                       if (atts != null && atts.Length > 0) {
+                               ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
+                               if (att.NeedsTag)
+                                       newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
+                       } else if (builder is DataBindingBuilder) {
+                               newExpr.Parameters.Add (new CodePrimitiveExpression (0));
+                               newExpr.Parameters.Add (new CodePrimitiveExpression (1));
+                       }
+
+                       method.Statements.Add (new CodeVariableDeclarationStatement (ctrlTypeRef, "__ctrl"));
+                       CodeAssignStatement assign = new CodeAssignStatement ();
+                       assign.Left = ctrlVar;
+                       assign.Right = newExpr;
+
+                       return assign;
+               }
                
                void InitMethod (ControlBuilder builder, bool isTemplate, bool childrenAsProperties)
                {
                        currentLocation = builder.Location;
                        bool inBuildControlTree = builder is RootBuilder;
                        string tailname = (inBuildControlTree ? "Tree" : ("_" + builder.ID));
+                       bool isProperty = builder.IsProperty;
                        CodeMemberMethod method = new CodeMemberMethod ();
                        builder.Method = method;
                        builder.MethodStatements = method.Statements;
@@ -174,7 +197,7 @@ namespace System.Web.Compilation
                        method.Name = "__BuildControl" + tailname;
                        method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
                        Type type = builder.ControlType;
-
+                       
                        /* in the case this is the __BuildControlTree
                         * method, allow subclasses to insert control
                         * specific code. */
@@ -199,51 +222,54 @@ namespace System.Web.Compilation
                                mainClass.Members.Add (renderMethod);
                        }
                        
-                       if (childrenAsProperties || builder.ControlType == null) {
+                       if (childrenAsProperties || type == null) {
                                string typeString;
-                               if (builder is RootBuilder)
+                               bool isGlobal = true;
+                               bool returnsControl;
+
+                               if (builder is RootBuilder) {
                                        typeString = parser.ClassName;
-                               else {
-                                       if (builder.ControlType != null && builder.IsProperty &&
-                                           !typeof (ITemplate).IsAssignableFrom (builder.ControlType))
-                                               typeString = builder.ControlType.FullName;
-                                       else 
+                                       isGlobal = false;
+                                       returnsControl = false;
+                               } else {
+                                       returnsControl = builder.PropertyBuilderShouldReturnValue;
+                                       if (type != null && builder.IsProperty && !typeof (ITemplate).IsAssignableFrom (type)) {
+                                               typeString = type.FullName;
+                                               isGlobal = !type.IsPrimitive;
+                                       } else 
                                                typeString = "System.Web.UI.Control";
                                        ProcessTemplateChildren (builder);
                                }
+                               CodeTypeReference ctrlTypeRef = new CodeTypeReference (typeString);
+                               if (isGlobal)
+                                       ctrlTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
+                               
+                               if (returnsControl) {
+                                       method.ReturnType = ctrlTypeRef;
 
-                               method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
+                                       // $controlType _ctrl = new $controlType ($parameters);
+                                       //
+                                       method.Statements.Add (CreateControlVariable (type, builder, method, ctrlTypeRef));
+                               } else
+                                       method.Parameters.Add (new CodeParameterDeclarationExpression (typeString, "__ctrl"));
                        } else {
+                               CodeTypeReference ctrlTypeRef = new CodeTypeReference (type.FullName);
+                               if (!type.IsPrimitive)
+                                       ctrlTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
                                
                                if (typeof (Control).IsAssignableFrom (type))
-                                       method.ReturnType = new CodeTypeReference (typeof (Control));
+                                       method.ReturnType = ctrlTypeRef;
 
-                               // _ctrl = new $controlType ($parameters);
+                               // $controlType _ctrl = new $controlType ($parameters);
                                //
-                               CodeObjectCreateExpression newExpr = new CodeObjectCreateExpression (type);
-
-                               object [] atts = type.GetCustomAttributes (typeof (ConstructorNeedsTagAttribute), true);
-                               if (atts != null && atts.Length > 0) {
-                                       ConstructorNeedsTagAttribute att = (ConstructorNeedsTagAttribute) atts [0];
-                                       if (att.NeedsTag)
-                                               newExpr.Parameters.Add (new CodePrimitiveExpression (builder.TagName));
-                               } else if (builder is DataBindingBuilder) {
-                                       newExpr.Parameters.Add (new CodePrimitiveExpression (0));
-                                       newExpr.Parameters.Add (new CodePrimitiveExpression (1));
-                               }
-
-                               method.Statements.Add (new CodeVariableDeclarationStatement (builder.ControlType, "__ctrl"));
-                               CodeAssignStatement assign = new CodeAssignStatement ();
-                               assign.Left = ctrlVar;
-                               assign.Right = newExpr;
-                               method.Statements.Add (AddLinePragma (assign, builder));
+                               method.Statements.Add (AddLinePragma (CreateControlVariable (type, builder, method, ctrlTypeRef), builder));
                                                                
                                // this.$builderID = _ctrl;
                                //
                                CodeFieldReferenceExpression builderID = new CodeFieldReferenceExpression ();
                                builderID.TargetObject = thisRef;
                                builderID.FieldName = builder.ID;
-                               assign = new CodeAssignStatement ();
+                               CodeAssignStatement assign = new CodeAssignStatement ();
                                assign.Left = builderID;
                                assign.Right = ctrlVar;
                                method.Statements.Add (AddLinePragma (assign, builder));
@@ -1154,7 +1180,8 @@ namespace System.Web.Compilation
                {
                        if (parent == null || child == null)
                                return;
-                       
+
+                       CodeStatementCollection methodStatements = parent.MethodStatements;
                        CodeMethodReferenceExpression m = new CodeMethodReferenceExpression (thisRef, child.Method.Name);
                        CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (m);
 
@@ -1192,26 +1219,42 @@ namespace System.Web.Compilation
                                else
                                        parms.Add (new CodePrimitiveExpression (null));
 #endif
-                               parent.MethodStatements.Add (AddLinePragma (build, parent));
+                               methodStatements.Add (AddLinePragma (build, parent));
                                if (parent.HasAspCode)
                                        AddRenderControl (parent);
                                return;
                        }
                                 
                        if (child.IsProperty || parent.ChildrenAsProperties) {
-                               expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
-                               parent.MethodStatements.Add (AddLinePragma (expr, parent));
+                               if (!child.PropertyBuilderShouldReturnValue) {
+                                       expr.Parameters.Add (new CodeFieldReferenceExpression (ctrlVar, child.TagName));
+                                       parent.MethodStatements.Add (AddLinePragma (expr, parent));
+                               } else {
+                                       string localVarName = parent.GetNextLocalVariableName ("__ctrl");
+                                       methodStatements.Add (new CodeVariableDeclarationStatement (child.Method.ReturnType, localVarName));
+                                       CodeVariableReferenceExpression localVarRef = new CodeVariableReferenceExpression (localVarName);
+                                       CodeAssignStatement assign = new CodeAssignStatement ();
+                                       assign.Left = localVarRef;
+                                       assign.Right = expr;
+                                       methodStatements.Add (AddLinePragma (assign, parent));
+
+                                       assign = new CodeAssignStatement ();
+                                       assign.Left = new CodeFieldReferenceExpression (ctrlVar, child.TagName);
+                                       assign.Right = localVarRef;
+                                       methodStatements.Add (AddLinePragma (assign, parent));
+                               }
+                               
                                return;
                        }
 
-                       parent.MethodStatements.Add (AddLinePragma (expr, parent));
+                       methodStatements.Add (AddLinePragma (expr, parent));
                        CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, child.ID);
                        if (parent.ControlType == null || typeof (IParserAccessor).IsAssignableFrom (parent.ControlType))
                                AddParsedSubObjectStmt (parent, field);
                        else {
                                CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (ctrlVar, "Add");
                                invoke.Parameters.Add (field);
-                               parent.MethodStatements.Add (AddLinePragma (invoke, parent));
+                               methodStatements.Add (AddLinePragma (invoke, parent));
                        }
                                
                        if (parent.HasAspCode)
@@ -1446,7 +1489,7 @@ namespace System.Web.Compilation
                protected void CreateControlTree (ControlBuilder builder, bool inTemplate, bool childrenAsProperties)
                {
                        EnsureID (builder);
-                       bool isTemplate = (typeof (TemplateBuilder).IsAssignableFrom (builder.GetType ()));
+                       bool isTemplate = builder.IsTemplate;
                        
                        if (!isTemplate && !inTemplate) {
                                CreateField (builder, true);
@@ -1560,8 +1603,8 @@ namespace System.Web.Compilation
                        
                        if ((!isTemplate || builder is RootBuilder) && !String.IsNullOrEmpty (builder.GetAttribute ("meta:resourcekey")))
                                CreateAssignStatementFromAttribute (builder, "meta:resourcekey");
-
-                       if (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType))
+                       
+                       if ((childrenAsProperties && builder.PropertyBuilderShouldReturnValue) || (!childrenAsProperties && typeof (Control).IsAssignableFrom (builder.ControlType)))
                                builder.Method.Statements.Add (new CodeMethodReturnStatement (ctrlVar));
 
                        builder.ProcessGeneratedCode (CompileUnit, BaseType, DerivedType, builder.Method, builder.DataBindingMethod);