File: Compilation\BaseCodeDomTreeGenerator.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="BaseCodeDomTreeGenerator.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
/**********************************************
 
Class hierarchy:
 
BaseCodeDomTreeGenerator
    BaseTemplateCodeDomTreeGenerator
        TemplateControlCodeDomTreeGenerator
            PageCodeDomTreeGenerator
            UserControlCodeDomTreeGenerator
        PageThemeCodeDomTreeGenerator
    ApplicationFileCodeDomTreeGenerator
***********************************************/
 
 
 
namespace System.Web.Compilation {
 
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.IO;
using Microsoft.Win32;
using System.Security.Cryptography;
using System.Web.Caching;
using System.Web.Util;
using System.Web.UI;
using System.Web.SessionState;
using System.CodeDom;
using System.CodeDom.Compiler;
using Util = System.Web.UI.Util;
using System.Web.Hosting;
using System.Web.Profile;
using System.Web.Configuration;
using System.Globalization;
using System.Linq;
 
 
internal abstract class BaseCodeDomTreeGenerator {
 
    protected CodeDomProvider _codeDomProvider;
    protected CodeCompileUnit _codeCompileUnit;
    private CodeNamespace _sourceDataNamespace;
    protected CodeTypeDeclaration _sourceDataClass;
    protected CodeTypeDeclaration _intermediateClass;
    private CompilerParameters _compilParams;
    protected StringResourceBuilder _stringResourceBuilder;
    protected bool _usingVJSCompiler;
    private static IDictionary _generatedColumnOffsetDictionary;
    private CodeMemberMethod _initMethod;
 
    private VirtualPath _virtualPath;
 
    // The constructors
    private CodeConstructor _ctor;
 
    protected CodeTypeReferenceExpression _classTypeExpr;
 
    internal const string defaultNamespace = "ASP";
 
    // Used for things that we don't want the user to see
    internal const string internalAspNamespace = "__ASP";
    
    private const string initializedFieldName = "__initialized";
 
    private const string _dummyVariable = "__dummyVar";
    private const int _defaultColumnOffset = 4;
 
    private const string InitMethodName = "__Init";
 
    private TemplateParser _parser;
    TemplateParser Parser { get { return _parser; } }
 
    // We generate different code for the designer
    protected bool _designerMode;
    internal void SetDesignerMode() { _designerMode = true; }
 
    private IDictionary _linePragmasTable;
    internal IDictionary LinePragmasTable { get { return _linePragmasTable; } }
 
    // Used to generate indexed into the LinePragmasTable
    private int _pragmaIdGenerator=1;
 
    private static bool _urlLinePragmas;
    private bool _initMethodSet;
 
        static BaseCodeDomTreeGenerator() {
        CompilationSection config = MTConfigUtil.GetCompilationAppConfig();
 
        _urlLinePragmas = config.UrlLinePragmas;
    }
 
#if DBG
    private bool _addedDebugComment;
#endif
 
#if DBG
    protected void AppendDebugComment(CodeStatementCollection statements) {
        if (!_addedDebugComment) {
            _addedDebugComment = true;
            StringBuilder debugComment = new StringBuilder();
 
            debugComment.Append("\r\n");
            debugComment.Append("** DEBUG INFORMATION **");
            debugComment.Append("\r\n");
 
            statements.Add(new CodeCommentStatement(debugComment.ToString()));
        }
    }
#endif
 
    internal /*public*/ CodeCompileUnit GetCodeDomTree(CodeDomProvider codeDomProvider,
        StringResourceBuilder stringResourceBuilder, VirtualPath virtualPath) {
 
        Debug.Assert(_codeDomProvider == null && _stringResourceBuilder == null);
 
        _codeDomProvider = codeDomProvider;
        _stringResourceBuilder = stringResourceBuilder;
        _virtualPath = virtualPath;
 
        // Build the data tree that needs to be compiled
        if (!BuildSourceDataTree())
            return null;
 
        // Tell the root builder that the CodeCompileUnit is now fully complete
        if (Parser.RootBuilder != null) {
            Parser.RootBuilder.OnCodeGenerationComplete();
        }
 
        return _codeCompileUnit;
    }
 
    protected /*public*/ CompilerParameters CompilParams { get { return _compilParams; } }
 
    internal string GetInstantiatableFullTypeName() {
 
        // In updatable mode, we never build the final type, so return null
        if (PrecompilingForUpdatableDeployment)
            return null;
 
        return Util.MakeFullTypeName(_sourceDataNamespace.Name, _sourceDataClass.Name);
    }
 
    internal string GetIntermediateFullTypeName() {
 
        return Util.MakeFullTypeName(Parser.BaseTypeNamespace, _intermediateClass.Name);
    }
 
    /*
     * Set some fields that are needed for code generation
     */
    protected BaseCodeDomTreeGenerator(TemplateParser parser) {
        _parser = parser;
 
        Debug.Assert(Parser.BaseType != null);
    }
 
    protected void ApplyEditorBrowsableCustomAttribute(CodeTypeMember member) {
        Debug.Assert(_designerMode, "This method should only be used in design mode.");
 
        // Generate EditorBrowsableAttribute to hide the generated methods from the tool
        // [EditorBrowsable(EditorBrowsableState.Never)]
        CodeAttributeDeclaration editorBrowsableAttribute = new CodeAttributeDeclaration();
        editorBrowsableAttribute.Name = typeof(EditorBrowsableAttribute).FullName;
        editorBrowsableAttribute.Arguments.Add(new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EditorBrowsableState)), "Never")));
        member.CustomAttributes.Add(editorBrowsableAttribute);
    }
 
 
    /// <devdoc>
    ///     Create a name for the generated class
    /// </devdoc>
    protected virtual string GetGeneratedClassName() {
        string className;
 
        // If the user specified the class name, just use that
        if (Parser.GeneratedClassName != null)
            return Parser.GeneratedClassName;
 
        // Use the input file name to generate the class name
 
        className = _virtualPath.FileName;
 
        // Prepend the class name with the directory path within the app (DevDiv 42063)
        string appRelVirtualDir = _virtualPath.Parent.AppRelativeVirtualPathStringOrNull;
        if (appRelVirtualDir != null) {
            Debug.Assert(UrlPath.IsAppRelativePath(appRelVirtualDir));
            className = appRelVirtualDir.Substring(2) + className;
        }
 
        // Change invalid chars to underscores
        className = Util.MakeValidTypeNameFromString(className);
 
        // Make it lower case to make it more predictable (VSWhidbey 503369)
        className = className.ToLowerInvariant();
 
        // If it's the same as the base type name, prepend it with an underscore to prevent
        // a compile error.
        string baseTypeName = Parser.BaseTypeName != null ? Parser.BaseTypeName : Parser.BaseType.Name;
        if (StringUtil.EqualsIgnoreCase(className, baseTypeName)) {
            className = "_" + className;
        }
 
        return className;
    }
 
    internal static bool IsAspNetNamespace(string ns) {
        return (ns == defaultNamespace);
    }
 
    private bool PrecompilingForUpdatableDeployment {
        get {
            // For global.asax, this never applies
            if (IsGlobalAsaxGenerator)
                return false;
 
            return BuildManager.PrecompilingForUpdatableDeployment;
        }
    }
 
    private bool BuildSourceDataTree() {
 
        _compilParams = Parser.CompilParams;
 
        _codeCompileUnit = new CodeCompileUnit();
        _codeCompileUnit.UserData["AllowLateBound"] = !Parser.FStrict;
        _codeCompileUnit.UserData["RequireVariableDeclaration"] = Parser.FExplicit;
 
        // Set a flag indicating if we're using the VJS compiler.  See comment in BuildExtractMethod for more information.
        _usingVJSCompiler = (_codeDomProvider.FileExtension == ".jsl");
 
        _sourceDataNamespace = new CodeNamespace(Parser.GeneratedNamespace);
 
        string generatedClassName = GetGeneratedClassName();
 
        if (Parser.BaseTypeName != null) {
 
            Debug.Assert(Parser.CodeFileVirtualPath != null);
 
            // This is the case where the page has a CodeFile attribute
 
            CodeNamespace intermediateNamespace = new CodeNamespace(Parser.BaseTypeNamespace);
            _codeCompileUnit.Namespaces.Add(intermediateNamespace);
            _intermediateClass = new CodeTypeDeclaration(Parser.BaseTypeName);
 
            // Specify the base class in the UserData in case the CodeDom provider needs
            // to reflect on it when generating code from the CodeCompileUnit (VSWhidbey 475294)
            // In design mode, use the default base type (e.g. Page or UserControl) to avoid
            // ending up with a type that can't be serialized to the Venus domain (VSWhidbey 545535)
            if (_designerMode)
                _intermediateClass.UserData["BaseClassDefinition"] = Parser.DefaultBaseType;
            else
                _intermediateClass.UserData["BaseClassDefinition"] = Parser.BaseType;
 
            intermediateNamespace.Types.Add(_intermediateClass);
 
            // Generate a partial class
            _intermediateClass.IsPartial = true;
 
            // Unless we're precompiling for updatable deployment, create the derived class
            if (!PrecompilingForUpdatableDeployment) {
 
                _sourceDataClass = new CodeTypeDeclaration(generatedClassName);
                // VSWhidbey 411701. Always use global type reference for the baseType 
                // when codefile is present.
                _sourceDataClass.BaseTypes.Add(CodeDomUtility.BuildGlobalCodeTypeReference(
                    Util.MakeFullTypeName(Parser.BaseTypeNamespace, Parser.BaseTypeName)));
 
                _sourceDataNamespace.Types.Add(_sourceDataClass);
            }
        }
        else {
 
            // The page is not using code besides
 
            _intermediateClass = new CodeTypeDeclaration(generatedClassName);
            _intermediateClass.BaseTypes.Add(CodeDomUtility.BuildGlobalCodeTypeReference(Parser.BaseType));
            _sourceDataNamespace.Types.Add(_intermediateClass);
 
            // There is only one class, so make both fields point to the same thing
            _sourceDataClass = _intermediateClass;
        }
 
        // Add the derived class namespace after the base partial class so C# parser
        // can still parse the code correctly in case the derived class contains error.
        // VSWhidbey 397646
        _codeCompileUnit.Namespaces.Add(_sourceDataNamespace);
 
        // We don't generate any code during updatable precompilation of a single (inline) page,
        // except for global.asax
        if (PrecompilingForUpdatableDeployment && Parser.CodeFileVirtualPath == null)
            return false;
 
        // Add metadata attributes to the class
        GenerateClassAttributes();
 
        // In VB, always import Microsoft.VisualBasic (VSWhidbey 256475)
        if (_codeDomProvider is Microsoft.VisualBasic.VBCodeProvider)
            _sourceDataNamespace.Imports.Add(new CodeNamespaceImport("Microsoft.VisualBasic"));
 
        // Add all the namespaces
        if (Parser.NamespaceEntries != null) {
            foreach (NamespaceEntry entry in Parser.NamespaceEntries.Values) {
                // Create a line pragma if available
                CodeLinePragma linePragma;
                if (entry.VirtualPath != null) {
                    linePragma = CreateCodeLinePragma(entry.VirtualPath, entry.Line);
                }
                else {
                    linePragma = null;
                }
 
                CodeNamespaceImport nsi = new CodeNamespaceImport(entry.Namespace);
                nsi.LinePragma = linePragma;
 
                _sourceDataNamespace.Imports.Add(nsi);
            }
        }
 
        if (_sourceDataClass != null) {
            // We need to generate a global reference to avoid ambiguities (VSWhidbey 284936)
            string fullClassName = Util.MakeFullTypeName(_sourceDataNamespace.Name, _sourceDataClass.Name);
            CodeTypeReference classTypeRef = CodeDomUtility.BuildGlobalCodeTypeReference(fullClassName);
 
            // Since this is needed in several places, store it in a member variable
            _classTypeExpr = new CodeTypeReferenceExpression(classTypeRef);
        }
 
        // Add the implemented interfaces
        GenerateInterfaces();
 
        // Build various properties, fields, methods
        BuildMiscClassMembers();
 
        // Build the default constructors
        if (!_designerMode && _sourceDataClass != null) {
            _ctor = new CodeConstructor();
            AddDebuggerNonUserCodeAttribute(_ctor);
            _sourceDataClass.Members.Add(_ctor);
            _ctor.Attributes &= ~MemberAttributes.AccessMask;
            _ctor.Attributes |= MemberAttributes.Public;
            BuildDefaultConstructor();
        }
 
        return true;
    }
 
    private void SetInitMethod() {
        Debug.Assert(_ctor != null);
        Debug.Assert(Parser.BaseType != null);
 
        if (BinaryCompatibility.Current.TargetsAtLeastFramework472 &&
            Parser.BaseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Any(c => c.GetParameters().Length > 0)) {
 
            // Create __Init method
            var method = new CodeMemberMethod();
            AddDebuggerNonUserCodeAttribute(method);
            method.Name = InitMethodName;
            method.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            method.ReturnType = new CodeTypeReference(typeof(void));
 
            if (Parser.BaseType.GetConstructor(Type.EmptyTypes) != null) {
                // Invoke __init in default c-tor
                _ctor.Statements.Add(CreateInitInvoke());
            }
            else {
                // if base type doesn't have default constructor, the generated child class should not have either
                _sourceDataClass.Members.Remove(_ctor);
            }
 
            _sourceDataClass.Members.Add(method);
            _initMethod = method;
        }
    }
 
    protected CodeMemberMethod InitMethod {
        get {
            if (!_initMethodSet) {
                SetInitMethod();
                _initMethodSet = true;
            }
 
            return _initMethod ?? _ctor;
        }
    }
 
    protected static CodeMethodInvokeExpression CreateInitInvoke() { 
        var invoke = new CodeMethodInvokeExpression();
        invoke.Method.TargetObject = new CodeThisReferenceExpression();
        invoke.Method.MethodName = InitMethodName;
 
        return invoke;
    }
 
    /*
     * Add metadata attributes to the class
     */
    protected virtual void GenerateClassAttributes() {
        // If this is a debuggable page, generate a
        // CompilerGlobalScopeAttribute attribute (ASURT 33027)
        if (CompilParams.IncludeDebugInformation && _sourceDataClass != null) {
            CodeAttributeDeclaration attribDecl = new CodeAttributeDeclaration(
                "System.Runtime.CompilerServices.CompilerGlobalScopeAttribute");
            _sourceDataClass.CustomAttributes.Add(attribDecl);
        }
    }
 
    /*
     * Generate the list of implemented interfaces
     */
    protected virtual void GenerateInterfaces() {
        if (Parser.ImplementedInterfaces != null) {
            foreach (Type t in Parser.ImplementedInterfaces) {
                _intermediateClass.BaseTypes.Add(new CodeTypeReference(t));
            }
        }
    }
 
    /*
     * Build first-time intialization statements
     */
    protected virtual void BuildInitStatements(CodeStatementCollection trueStatements, CodeStatementCollection topLevelStatements) {
    }
 
 
    /*
     * Build the default constructor
     */
    protected virtual void BuildDefaultConstructor() {
 
        // private static bool __initialized;
        CodeMemberField initializedField = new CodeMemberField(typeof(bool), initializedFieldName);
        initializedField.Attributes |= MemberAttributes.Static;
        _sourceDataClass.Members.Add(initializedField);
        
 
        // if (__intialized == false)
        CodeConditionStatement initializedCondition = new CodeConditionStatement();
        initializedCondition.Condition = new CodeBinaryOperatorExpression(
                                                new CodeFieldReferenceExpression(
                                                    _classTypeExpr,
                                                    initializedFieldName),
                                                CodeBinaryOperatorType.ValueEquality,
                                                new CodePrimitiveExpression(false));
 
        this.BuildInitStatements(initializedCondition.TrueStatements, InitMethod.Statements);
 
        initializedCondition.TrueStatements.Add(new CodeAssignStatement(
                                                    new CodeFieldReferenceExpression(
                                                        _classTypeExpr,
                                                        initializedFieldName),
                                                    new CodePrimitiveExpression(true)));
 
        // i.e. __intialized = true;
        InitMethod.Statements.Add(initializedCondition);
    }
 
        /*
         * Build various properties, fields, methods
         */
        protected virtual void BuildMiscClassMembers() {
 
        // Build the Profile property
        if (NeedProfileProperty)
            BuildProfileProperty();
 
        // Skip the rest if we're only generating the intermediate class
        if (_sourceDataClass == null)
            return;
 
        // Build the injected properties from the global.asax <object> tags
        BuildApplicationObjectProperties();
        BuildSessionObjectProperties();
 
        // Build the injected properties for objects scoped to the page
        BuildPageObjectProperties();
 
        // Add all the <script runat=server> code blocks
        foreach (ScriptBlockData script in Parser.ScriptList) {
 
            // Pad the code block so its generated offset matches the aspx
            string code = script.Script;
            code = code.PadLeft(code.Length + script.Column - 1);
 
            CodeSnippetTypeMember literal = new CodeSnippetTypeMember(code);
            literal.LinePragma = CreateCodeLinePragma(script.VirtualPath, script.Line,
                script.Column, script.Column, script.Script.Length, false);
            _sourceDataClass.Members.Add(literal);
        }
    }
 
    /*
     * Build the Profile property
     */
    private void BuildProfileProperty() {
 
        if (!ProfileManager.Enabled)
            return;
 
        CodeMemberProperty prop;
        string typeName = ProfileBase.GetProfileClassName();
 
        prop = new CodeMemberProperty();
        prop.Attributes &= ~MemberAttributes.AccessMask;
        prop.Attributes &= ~MemberAttributes.ScopeMask;
        prop.Attributes |= MemberAttributes.Final | MemberAttributes.Family;
        prop.Name = "Profile";
 
        if (_designerMode) {
            ApplyEditorBrowsableCustomAttribute(prop);
        }
 
        //if (ProfileBase.GetPropertiesForCompilation().Count == 0)
        //    typeName = "System.Web.Profile.DefaultProfile";
        //else
        //    typeName = "ASP.Profile";
        prop.Type = new CodeTypeReference(typeName);
 
        CodePropertyReferenceExpression propRef = new CodePropertyReferenceExpression(
            new CodeThisReferenceExpression(), "Context");
        propRef = new CodePropertyReferenceExpression(propRef, "Profile");
 
        prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(
            typeName, propRef)));
        _intermediateClass.Members.Add(prop);
    }
 
    // By default, we build the Profile property
    protected virtual bool NeedProfileProperty { get { return true; } }
 
    protected void BuildAccessorProperty(string propName, CodeFieldReferenceExpression fieldRef,
        Type propType, MemberAttributes attributes, CodeAttributeDeclarationCollection attrDeclarations) {
 
        // e.g.
        // [attrDeclaration]
        // public SomeType SomeProp {
        //    get {
        //        return this.__SomeProp;
        //    }
        // }
        CodeMemberProperty prop = new CodeMemberProperty();
        prop.Attributes = attributes;
        prop.Name = propName;
        prop.Type = new CodeTypeReference(propType);
        prop.GetStatements.Add(new CodeMethodReturnStatement(fieldRef));
        prop.SetStatements.Add(new CodeAssignStatement(
            fieldRef, new CodePropertySetValueReferenceExpression()));
 
        if (attrDeclarations != null) {
            prop.CustomAttributes = attrDeclarations;
        }
 
        _sourceDataClass.Members.Add(prop);
    }
 
    protected void BuildFieldAndAccessorProperty(string propName, string fieldName,
        Type propType, bool fStatic, CodeAttributeDeclarationCollection attrDeclarations) {
 
        // e.g. private SomeType __SomeProp;
        CodeMemberField field = new CodeMemberField(propType, fieldName);
        if (fStatic) {
            field.Attributes |= MemberAttributes.Static;
        }
        _sourceDataClass.Members.Add(field);
 
        CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(
            new CodeThisReferenceExpression(), fieldName);
        BuildAccessorProperty(propName, fieldRef, propType, MemberAttributes.Public, attrDeclarations);
    }
 
    /*
     * Helper method used to build the properties of injected
     * global.asax properties.  These look like:
     *   PropType __propName;
     *   protected PropType propName
     *   {
     *       get
     *       {
     *           if (__propName == null)
     *               __propName = [some expression];
     *
     *           return __propName;
     *       }
     *   }
     */
    private void BuildInjectedGetPropertyMethod(string propName,
                                                Type propType,
                                                CodeExpression propertyInitExpression,
                                                bool fPublicProp) {
 
        string fieldName = "cached" + propName;
 
        CodeExpression fieldAccess = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName);
 
        // Add a private field for the object
        _sourceDataClass.Members.Add(new CodeMemberField(propType, fieldName));
 
        CodeMemberProperty prop = new CodeMemberProperty();
        if (fPublicProp) {
            prop.Attributes &= ~MemberAttributes.AccessMask;
            prop.Attributes |= MemberAttributes.Public;
        }
        prop.Name = propName;
        prop.Type = new CodeTypeReference(propType);
 
 
        CodeConditionStatement ifStmt = new CodeConditionStatement();
        ifStmt.Condition = new CodeBinaryOperatorExpression(fieldAccess, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null));
        ifStmt.TrueStatements.Add(new CodeAssignStatement(fieldAccess, propertyInitExpression));
 
        prop.GetStatements.Add(ifStmt);
        prop.GetStatements.Add(new CodeMethodReturnStatement(fieldAccess));
 
        _sourceDataClass.Members.Add(prop);
    }
 
    /*
     * Helper method for building application and session scope injected
     * properties.  If useApplicationState, build application properties, otherwise
     * build session properties.
     */
    private void BuildObjectPropertiesHelper(IDictionary objects, bool useApplicationState) {
 
        IDictionaryEnumerator en = objects.GetEnumerator();
        while (en.MoveNext()) {
            HttpStaticObjectsEntry entry = (HttpStaticObjectsEntry)en.Value;
 
            // e.g. (PropType)Session.StaticObjects["PropName"]
 
            // Use the appropriate collection
            CodePropertyReferenceExpression stateObj = new CodePropertyReferenceExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(),
                                                                                                                               useApplicationState ? "Application" : "Session"),
                                                                                           "StaticObjects");
 
            CodeMethodInvokeExpression getObject = new CodeMethodInvokeExpression(stateObj, "GetObject");
            getObject.Parameters.Add(new CodePrimitiveExpression(entry.Name));
 
 
            Type declaredType = entry.DeclaredType;
            Debug.Assert(!Util.IsLateBoundComClassicType(declaredType));
 
            if (useApplicationState) {
                // for application state use property that does caching in a member
                BuildInjectedGetPropertyMethod(entry.Name, declaredType,
                                               new CodeCastExpression(declaredType, getObject),
                                               false /*fPublicProp*/);
            }
            else {
                // for session state use lookup every time, as one application instance deals with many sessions
                CodeMemberProperty prop = new CodeMemberProperty();
                prop.Name = entry.Name;
                prop.Type = new CodeTypeReference(declaredType);
                prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(declaredType, getObject)));
                _sourceDataClass.Members.Add(prop);
            }
        }
    }
 
    /*
     * Build the injected properties from the global.asax <object> tags
     * declared with scope=application
     */
    private void BuildApplicationObjectProperties() {
        if (Parser.ApplicationObjects != null)
            BuildObjectPropertiesHelper(Parser.ApplicationObjects.Objects, true);
    }
 
    /*
     * Build the injected properties from the global.asax <object> tags
     * declared with scope=session
     */
    private void BuildSessionObjectProperties() {
        if (Parser.SessionObjects != null)
            BuildObjectPropertiesHelper(Parser.SessionObjects.Objects, false);
    }
 
    protected virtual bool IsGlobalAsaxGenerator { get { return false; } }
 
    /*
     * Build the injected properties from the global.asax <object> tags
     * declared with scope=appinstance, or the aspx/ascx tags with scope=page.
     */
    private void BuildPageObjectProperties() {
        if (Parser.PageObjectList == null) return;
 
        foreach (ObjectTagBuilder obj in Parser.PageObjectList) {
 
            CodeExpression propertyInitExpression;
 
            if (obj.Progid != null) {
                // If we are dealing with a COM classic object that hasn't been tlbreg'ed,
                // we need to call HttpServerUtility.CreateObject(progid) to create it
                CodeMethodInvokeExpression createObjectCall = new CodeMethodInvokeExpression();
 
                createObjectCall.Method.TargetObject = new CodePropertyReferenceExpression(
                    new CodeThisReferenceExpression(), "Server");
                createObjectCall.Method.MethodName = "CreateObject";
                createObjectCall.Parameters.Add(new CodePrimitiveExpression(obj.Progid));
 
                propertyInitExpression = createObjectCall;
            }
            else if (obj.Clsid != null) {
                // Same as previous case, but with a clsid instead of a progId
                CodeMethodInvokeExpression createObjectCall = new CodeMethodInvokeExpression();
                createObjectCall.Method.TargetObject = new CodePropertyReferenceExpression(
                    new CodeThisReferenceExpression(), "Server");
                createObjectCall.Method.MethodName = "CreateObjectFromClsid";
                createObjectCall.Parameters.Add(new CodePrimitiveExpression(obj.Clsid));
 
                propertyInitExpression = createObjectCall;
            }
            else {
                propertyInitExpression = new CodeObjectCreateExpression(obj.ObjectType);
            }
 
            // Make the appinstance properties public for global.asax (ASURT 63253)
            BuildInjectedGetPropertyMethod(obj.ID, obj.DeclaredType,
                propertyInitExpression, IsGlobalAsaxGenerator /*fPublicProp*/);
        }
    }
 
    protected CodeLinePragma CreateCodeLinePragma(ControlBuilder builder) {
 
        string virtualPath = builder.PageVirtualPath;
        int line = builder.Line;
        int column = 1;
        int generatedColumn = 1;
        int codeLength = -1;
 
        CodeBlockBuilder codeBlockBuilder = builder as CodeBlockBuilder;
        if (codeBlockBuilder != null) {
            column = codeBlockBuilder.Column;
            codeLength = codeBlockBuilder.Content.Length;
 
            if (codeBlockBuilder.BlockType == CodeBlockType.Code) {
                // If it's a <% ... %> block, the generated column is the same as the source
                generatedColumn = column;
            }
            else {
                // If it's a <%= ... %> block, we always generate '__o = expr' is
                // designer mode, so the column is fixed
                // 
                generatedColumn = BaseTemplateCodeDomTreeGenerator.tempObjectVariable.Length + 
                    GetGeneratedColumnOffset(_codeDomProvider);
            }
        }
 
        return CreateCodeLinePragma(virtualPath, line, column, generatedColumn, codeLength);
    }
 
    internal static int GetGeneratedColumnOffset(CodeDomProvider codeDomProvider) {
        object o = null;
 
        if (_generatedColumnOffsetDictionary == null) {
            _generatedColumnOffsetDictionary = new ListDictionary();
        }
        else {
            o = _generatedColumnOffsetDictionary[codeDomProvider.GetType()];
        }
 
        if (o == null) {
            CodeCompileUnit ccu = new CodeCompileUnit();
 
            CodeNamespace cnamespace = new CodeNamespace("ASP");
            ccu.Namespaces.Add(cnamespace);
 
            CodeTypeDeclaration type = new CodeTypeDeclaration("ColumnOffsetCalculator");
            type.IsClass = true;
            cnamespace.Types.Add(type);
 
            CodeMemberMethod method = new CodeMemberMethod();
            method.ReturnType = new CodeTypeReference(typeof(void));
            method.Name = "GenerateMethod";
            type.Members.Add(method);
 
            CodeStatement simpleAssignment = new CodeAssignStatement(
                new CodeVariableReferenceExpression(BaseTemplateCodeDomTreeGenerator.tempObjectVariable),
                new CodeSnippetExpression(_dummyVariable));
            method.Statements.Add(simpleAssignment);
 
            StringBuilder sb = new StringBuilder();
            StringWriter w = new StringWriter(sb, CultureInfo.InvariantCulture);
 
            codeDomProvider.GenerateCodeFromCompileUnit(ccu, w, null);
 
            StringReader reader = new StringReader(sb.ToString());
            String line = null;
 
            int offset = _defaultColumnOffset;
 
            while ((line = reader.ReadLine()) != null) {
                int index = 0;
                line = line.TrimStart();
                if ((index = line.IndexOf(_dummyVariable, StringComparison.Ordinal)) != -1) {
                    offset = index - BaseTemplateCodeDomTreeGenerator.tempObjectVariable.Length + 1;
                }
            }
 
            // Save the offset per type.
            _generatedColumnOffsetDictionary[codeDomProvider.GetType()] = offset;
 
            return offset;
        }
 
        return (int)o;
    }
 
    protected CodeLinePragma CreateCodeLinePragma(string virtualPath, int lineNumber) {
        return CreateCodeLinePragma(virtualPath, lineNumber, 1, 1, -1, true);
    }
 
    protected CodeLinePragma CreateCodeLinePragma(string virtualPath, int lineNumber,
        int column, int generatedColumn, int codeLength) {
        return CreateCodeLinePragma(virtualPath, lineNumber, column, generatedColumn, codeLength, true);
    }
 
    protected CodeLinePragma CreateCodeLinePragma(string virtualPath, int lineNumber,
        int column, int generatedColumn, int codeLength, bool isCodeNugget) {
 
        // Return null if we're not supposed to generate line pragmas
        if (!Parser.FLinePragmas)
            return null;
 
        // The problem with disabling pragmas in non-debug is that we no longer
        // get line information on compile errors, while in v1 we did. So
        // unless we find a better solution, don't disable pragmas in non-debug
/*
        // Also, don't bother with pragmas unless we're compiling for debugging
        if (!CompilParams.IncludeDebugInformation)
            return null;
*/
 
        if (String.IsNullOrEmpty(virtualPath))
            return null;
 
        if (_designerMode) {
 
            // Only generate pragmas for code blocks in designer mode
            if (codeLength < 0)
                return null;
 
            LinePragmaCodeInfo codeInfo = new LinePragmaCodeInfo();
            codeInfo._startLine = lineNumber;
            codeInfo._startColumn = column;
            codeInfo._startGeneratedColumn = generatedColumn;
            codeInfo._codeLength = codeLength;
            codeInfo._isCodeNugget = isCodeNugget;
            lineNumber = _pragmaIdGenerator++;
 
            if (_linePragmasTable == null)
                _linePragmasTable = new Hashtable();
 
            _linePragmasTable[lineNumber] = codeInfo;
        }
 
        return CreateCodeLinePragmaHelper(virtualPath, lineNumber);
    }
 
    internal static CodeLinePragma CreateCodeLinePragmaHelper(string virtualPath, int lineNumber) {
 
        string pragmaFile = null;
 
        if (UrlPath.IsAbsolutePhysicalPath(virtualPath)) {
 
            // Due to config system limitations, we can end up with virtualPath
            // actually being a physical path.  If that's the case, just use it as is.
            // 
 
            pragmaFile = virtualPath;
        }
        else {
 
            if (_urlLinePragmas) {
 
                // If specified in config, generate URL's for the line pragmas
                // instead of physical path.  This is used for VS debugging.
                // We don't know the server name, so we just used a fixed one.  This should be
                // fine, as VS will ignore the server name.
 
                pragmaFile = ErrorFormatter.MakeHttpLinePragma(virtualPath);
            }
            else {
                try {
                    // Try using the physical path for the line pragma
                    pragmaFile = HostingEnvironment.MapPathInternal(virtualPath);
 
                    // If the physical path doesn't exist, use the URL instead.
                    // This can happen when using a VirtualPathProvider (VSWhidbey 272259)
                    if (!File.Exists(pragmaFile)) {
                        pragmaFile = ErrorFormatter.MakeHttpLinePragma(virtualPath);
                    }
                }
                catch {
                    // If MapPath failed, use the URL instead
                    pragmaFile = ErrorFormatter.MakeHttpLinePragma(virtualPath);
                }
            }
        }
 
        return new CodeLinePragma(pragmaFile, lineNumber);
    }
 
    // Adds [DebuggerNonUserCode] to the method to prevent debugger from stepping into generated code
    protected void AddDebuggerNonUserCodeAttribute(CodeMemberMethod method) {
        if (method == null) return;
        // If LinePragmas is false, the user might want to debug generated code, so we do not add the attribute
        if (!Parser.FLinePragmas) return; 
 
        CodeAttributeDeclaration attributeDeclaration = new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.Diagnostics.DebuggerNonUserCodeAttribute)));
        method.CustomAttributes.Add(attributeDeclaration);
    }
}
 
}