a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
814 lines
24 KiB
C#
814 lines
24 KiB
C#
//
|
|
// System.Web.Compilation.BaseCompiler
|
|
//
|
|
// Authors:
|
|
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
|
|
//
|
|
// (c) Copyright 2002,2003 Ximian, Inc (http://www.ximian.com)
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Web.UI;
|
|
using System.Web.Configuration;
|
|
using System.IO;
|
|
|
|
namespace System.Web.Compilation
|
|
{
|
|
abstract class BaseCompiler
|
|
{
|
|
const string DEFAULT_NAMESPACE = "ASP";
|
|
internal static Guid HashMD5 = new Guid(0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99);
|
|
static BindingFlags replaceableFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
|
|
|
TemplateParser parser;
|
|
CodeDomProvider provider;
|
|
ICodeCompiler compiler;
|
|
CodeCompileUnit unit;
|
|
CodeNamespace mainNS;
|
|
CompilerParameters compilerParameters;
|
|
bool isRebuilding = false;
|
|
protected Hashtable partialNameOverride = new Hashtable();
|
|
protected CodeTypeDeclaration partialClass;
|
|
protected CodeTypeReferenceExpression partialClassExpr;
|
|
protected CodeTypeDeclaration mainClass;
|
|
protected CodeTypeReferenceExpression mainClassExpr;
|
|
protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
|
|
|
|
VirtualPath inputVirtualPath;
|
|
|
|
public VirtualPath InputVirtualPath {
|
|
get {
|
|
if (inputVirtualPath == null)
|
|
inputVirtualPath = new VirtualPath (VirtualPathUtility.Combine (parser.BaseVirtualDir, Path.GetFileName (parser.InputFile)));
|
|
|
|
return inputVirtualPath;
|
|
}
|
|
}
|
|
|
|
protected BaseCompiler (TemplateParser parser)
|
|
{
|
|
this.parser = parser;
|
|
}
|
|
|
|
protected void AddReferencedAssembly (Assembly asm)
|
|
{
|
|
if (unit == null || asm == null)
|
|
return;
|
|
|
|
StringCollection refAsm = unit.ReferencedAssemblies;
|
|
string asmLocation = asm.Location;
|
|
if (!refAsm.Contains (asmLocation))
|
|
refAsm.Add (asmLocation);
|
|
}
|
|
|
|
internal CodeStatement AddLinePragma (CodeExpression expression, ControlBuilder builder)
|
|
{
|
|
return AddLinePragma (new CodeExpressionStatement (expression), builder);
|
|
}
|
|
|
|
internal CodeStatement AddLinePragma (CodeStatement statement, ControlBuilder builder)
|
|
{
|
|
if (builder == null || statement == null)
|
|
return statement;
|
|
|
|
ILocation location = null;
|
|
|
|
if (!(builder is CodeRenderBuilder))
|
|
location = builder.Location;
|
|
|
|
if (location != null)
|
|
return AddLinePragma (statement, location);
|
|
else
|
|
return AddLinePragma (statement, builder.Line, builder.FileName);
|
|
}
|
|
|
|
internal CodeStatement AddLinePragma (CodeStatement statement, ILocation location)
|
|
{
|
|
if (location == null || statement == null)
|
|
return statement;
|
|
|
|
return AddLinePragma (statement, location.BeginLine, location.Filename);
|
|
}
|
|
|
|
bool IgnoreFile (string fileName)
|
|
{
|
|
if (parser != null && !parser.LinePragmasOn)
|
|
return true;
|
|
|
|
return String.Compare (fileName, "@@inner_string@@", StringComparison.OrdinalIgnoreCase) == 0;
|
|
}
|
|
|
|
internal CodeStatement AddLinePragma (CodeStatement statement, int line, string fileName)
|
|
{
|
|
if (statement == null || IgnoreFile (fileName))
|
|
return statement;
|
|
|
|
statement.LinePragma = new CodeLinePragma (fileName, line);
|
|
return statement;
|
|
}
|
|
|
|
internal CodeTypeMember AddLinePragma (CodeTypeMember member, ControlBuilder builder)
|
|
{
|
|
if (builder == null || member == null)
|
|
return member;
|
|
|
|
ILocation location = builder.Location;
|
|
|
|
if (location != null)
|
|
return AddLinePragma (member, location);
|
|
else
|
|
return AddLinePragma (member, builder.Line, builder.FileName);
|
|
}
|
|
|
|
internal CodeTypeMember AddLinePragma (CodeTypeMember member, ILocation location)
|
|
{
|
|
if (location == null || member == null)
|
|
return member;
|
|
|
|
return AddLinePragma (member, location.BeginLine, location.Filename);
|
|
}
|
|
|
|
internal CodeTypeMember AddLinePragma (CodeTypeMember member, int line, string fileName)
|
|
{
|
|
if (member == null || IgnoreFile (fileName))
|
|
return member;
|
|
|
|
member.LinePragma = new CodeLinePragma (fileName, line);
|
|
return member;
|
|
}
|
|
|
|
internal void ConstructType ()
|
|
{
|
|
unit = new CodeCompileUnit ();
|
|
byte[] md5checksum = parser.MD5Checksum;
|
|
|
|
if (md5checksum != null) {
|
|
CodeChecksumPragma pragma = new CodeChecksumPragma ();
|
|
pragma.FileName = parser.InputFile;
|
|
pragma.ChecksumAlgorithmId = HashMD5;
|
|
pragma.ChecksumData = md5checksum;
|
|
|
|
unit.StartDirectives.Add (pragma);
|
|
}
|
|
|
|
if (parser.IsPartial) {
|
|
string partialns = null;
|
|
string partialclasstype = parser.PartialClassName;
|
|
|
|
int partialdot = partialclasstype.LastIndexOf ('.');
|
|
if (partialdot != -1) {
|
|
partialns = partialclasstype.Substring (0, partialdot);
|
|
partialclasstype = partialclasstype.Substring (partialdot + 1);
|
|
}
|
|
|
|
CodeNamespace partialNS = new CodeNamespace (partialns);
|
|
partialClass = new CodeTypeDeclaration (partialclasstype);
|
|
partialClass.IsPartial = true;
|
|
partialClassExpr = new CodeTypeReferenceExpression (parser.PartialClassName);
|
|
|
|
unit.Namespaces.Add (partialNS);
|
|
partialClass.TypeAttributes = TypeAttributes.Public;
|
|
partialNS.Types.Add (partialClass);
|
|
}
|
|
|
|
string mainclasstype = parser.ClassName;
|
|
string mainns = DEFAULT_NAMESPACE;
|
|
int maindot = mainclasstype.LastIndexOf ('.');
|
|
if (maindot != -1) {
|
|
mainns = mainclasstype.Substring (0, maindot);
|
|
mainclasstype = mainclasstype.Substring (maindot + 1);
|
|
}
|
|
|
|
mainNS = new CodeNamespace (mainns);
|
|
mainClass = new CodeTypeDeclaration (mainclasstype);
|
|
CodeTypeReference baseTypeRef;
|
|
if (partialClass != null) {
|
|
baseTypeRef = new CodeTypeReference (parser.PartialClassName);
|
|
baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
|
|
} else {
|
|
baseTypeRef = new CodeTypeReference (parser.BaseType.FullName);
|
|
if (parser.BaseTypeIsGlobal)
|
|
baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
|
|
}
|
|
mainClass.BaseTypes.Add (baseTypeRef);
|
|
|
|
mainClassExpr = new CodeTypeReferenceExpression (mainns + "." + mainclasstype);
|
|
|
|
unit.Namespaces.Add (mainNS);
|
|
mainClass.TypeAttributes = TypeAttributes.Public;
|
|
mainNS.Types.Add (mainClass);
|
|
|
|
foreach (object o in parser.Imports.Keys) {
|
|
if (o is string)
|
|
mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
|
|
}
|
|
|
|
// StringCollection.Contains has O(n) complexity, but
|
|
// considering the number of comparisons we make on
|
|
// average and the fact that using an intermediate array
|
|
// would be even more costly, this is fine here.
|
|
StringCollection refAsm = unit.ReferencedAssemblies;
|
|
string asmName;
|
|
if (parser.Assemblies != null) {
|
|
foreach (object o in parser.Assemblies) {
|
|
asmName = o as string;
|
|
if (asmName != null && !refAsm.Contains (asmName))
|
|
refAsm.Add (asmName);
|
|
}
|
|
}
|
|
|
|
ArrayList al = WebConfigurationManager.ExtraAssemblies;
|
|
if (al != null && al.Count > 0) {
|
|
foreach (object o in al) {
|
|
asmName = o as string;
|
|
if (asmName != null && !refAsm.Contains (asmName))
|
|
refAsm.Add (asmName);
|
|
}
|
|
}
|
|
|
|
IList list = BuildManager.CodeAssemblies;
|
|
if (list != null && list.Count > 0) {
|
|
Assembly asm;
|
|
foreach (object o in list) {
|
|
asm = o as Assembly;
|
|
if (o == null)
|
|
continue;
|
|
asmName = asm.Location;
|
|
if (asmName != null && !refAsm.Contains (asmName))
|
|
refAsm.Add (asmName);
|
|
}
|
|
}
|
|
|
|
// Late-bound generators specifics (as for MonoBASIC/VB.NET)
|
|
unit.UserData["RequireVariableDeclaration"] = parser.ExplicitOn;
|
|
unit.UserData["AllowLateBound"] = !parser.StrictOn;
|
|
|
|
InitializeType ();
|
|
AddInterfaces ();
|
|
AddClassAttributes ();
|
|
CreateStaticFields ();
|
|
AddApplicationAndSessionObjects ();
|
|
AddScripts ();
|
|
CreateMethods ();
|
|
CreateConstructor (null, null);
|
|
}
|
|
|
|
internal CodeFieldReferenceExpression GetMainClassFieldReferenceExpression (string fieldName)
|
|
{
|
|
CodeTypeReference mainClassTypeRef;
|
|
mainClassTypeRef = new CodeTypeReference (mainNS.Name + "." + mainClass.Name);
|
|
mainClassTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
|
|
|
|
return new CodeFieldReferenceExpression (
|
|
new CodeTypeReferenceExpression (mainClassTypeRef), fieldName);
|
|
}
|
|
|
|
protected virtual void InitializeType ()
|
|
{}
|
|
|
|
protected virtual void CreateStaticFields ()
|
|
{
|
|
CodeMemberField fld = new CodeMemberField (typeof (bool), "__initialized");
|
|
fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
|
|
fld.InitExpression = new CodePrimitiveExpression (false);
|
|
mainClass.Members.Add (fld);
|
|
}
|
|
|
|
void AssignAppRelativeVirtualPath (CodeConstructor ctor)
|
|
{
|
|
if (String.IsNullOrEmpty (parser.InputFile))
|
|
return;
|
|
|
|
Type baseType = parser.CodeFileBaseClassType;
|
|
if (baseType == null)
|
|
baseType = parser.BaseType;
|
|
if (baseType == null)
|
|
return;
|
|
if (!baseType.IsSubclassOf (typeof (System.Web.UI.TemplateControl)))
|
|
return;
|
|
|
|
CodeTypeReference baseTypeRef = new CodeTypeReference (baseType.FullName);
|
|
if (parser.BaseTypeIsGlobal)
|
|
baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
|
|
|
|
CodeExpression cast = new CodeCastExpression (baseTypeRef, new CodeThisReferenceExpression ());
|
|
CodePropertyReferenceExpression arvpProp = new CodePropertyReferenceExpression (cast, "AppRelativeVirtualPath");
|
|
CodeAssignStatement arvpAssign = new CodeAssignStatement ();
|
|
arvpAssign.Left = arvpProp;
|
|
arvpAssign.Right = new CodePrimitiveExpression (VirtualPathUtility.RemoveTrailingSlash (InputVirtualPath.AppRelative));
|
|
ctor.Statements.Add (arvpAssign);
|
|
}
|
|
|
|
protected virtual void CreateConstructor (CodeStatementCollection localVars,
|
|
CodeStatementCollection trueStmt)
|
|
{
|
|
CodeConstructor ctor = new CodeConstructor ();
|
|
ctor.Attributes = MemberAttributes.Public;
|
|
mainClass.Members.Add (ctor);
|
|
|
|
if (localVars != null)
|
|
ctor.Statements.AddRange (localVars);
|
|
|
|
AssignAppRelativeVirtualPath (ctor);
|
|
|
|
CodeFieldReferenceExpression initialized = GetMainClassFieldReferenceExpression ("__initialized");
|
|
|
|
CodeBinaryOperatorExpression bin;
|
|
bin = new CodeBinaryOperatorExpression (initialized,
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression (false));
|
|
|
|
CodeAssignStatement assign = new CodeAssignStatement (initialized,
|
|
new CodePrimitiveExpression (true));
|
|
|
|
CodeConditionStatement cond = new CodeConditionStatement ();
|
|
cond.Condition = bin;
|
|
|
|
if (trueStmt != null)
|
|
cond.TrueStatements.AddRange (trueStmt);
|
|
cond.TrueStatements.Add (assign);
|
|
ctor.Statements.Add (cond);
|
|
AddStatementsToConstructor (ctor);
|
|
}
|
|
|
|
protected virtual void AddStatementsToConstructor (CodeConstructor ctor)
|
|
{
|
|
}
|
|
|
|
void AddScripts ()
|
|
{
|
|
if (parser.Scripts == null || parser.Scripts.Count == 0)
|
|
return;
|
|
|
|
ServerSideScript sss;
|
|
|
|
foreach (object o in parser.Scripts) {
|
|
sss = o as ServerSideScript;
|
|
|
|
if (sss == null)
|
|
continue;
|
|
|
|
mainClass.Members.Add (AddLinePragma (new CodeSnippetTypeMember (sss.Script), sss.Location));
|
|
}
|
|
}
|
|
|
|
protected internal virtual void CreateMethods ()
|
|
{
|
|
}
|
|
|
|
void InternalCreatePageProperty (string retType, string name, string contextProperty)
|
|
{
|
|
CodeMemberProperty property = new CodeMemberProperty ();
|
|
property.Name = name;
|
|
property.Type = new CodeTypeReference (retType);
|
|
property.Attributes = MemberAttributes.Family | MemberAttributes.Final;
|
|
|
|
CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
|
|
CodeCastExpression cast = new CodeCastExpression ();
|
|
ret.Expression = cast;
|
|
|
|
CodePropertyReferenceExpression refexp = new CodePropertyReferenceExpression ();
|
|
refexp.TargetObject = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Context");
|
|
refexp.PropertyName = contextProperty;
|
|
|
|
cast.TargetType = new CodeTypeReference (retType);
|
|
cast.Expression = refexp;
|
|
|
|
property.GetStatements.Add (ret);
|
|
if (partialClass == null)
|
|
mainClass.Members.Add (property);
|
|
else
|
|
partialClass.Members.Add (property);
|
|
}
|
|
|
|
protected void CreateProfileProperty ()
|
|
{
|
|
string retType;
|
|
if (AppCodeCompiler.HaveCustomProfile (WebConfigurationManager.GetWebApplicationSection ("system.web/profile") as ProfileSection))
|
|
retType = "ProfileCommon";
|
|
else
|
|
retType = "System.Web.Profile.DefaultProfile";
|
|
InternalCreatePageProperty (retType, "Profile", "Profile");
|
|
}
|
|
|
|
protected virtual void AddInterfaces ()
|
|
{
|
|
if (parser.Interfaces == null)
|
|
return;
|
|
|
|
foreach (object o in parser.Interfaces) {
|
|
if (o is string)
|
|
mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
|
|
}
|
|
}
|
|
|
|
protected virtual void AddClassAttributes ()
|
|
{
|
|
}
|
|
|
|
protected virtual void AddApplicationAndSessionObjects ()
|
|
{
|
|
}
|
|
|
|
/* Utility methods for <object> stuff */
|
|
protected void CreateApplicationOrSessionPropertyForObject (Type type,
|
|
string propName,
|
|
bool isApplication,
|
|
bool isPublic)
|
|
{
|
|
/* if isApplication this generates (the 'cachedapp' field is created earlier):
|
|
private MyNS.MyClass app {
|
|
get {
|
|
if ((this.cachedapp == null)) {
|
|
this.cachedapp = ((MyNS.MyClass)
|
|
(this.Application.StaticObjects.GetObject("app")));
|
|
}
|
|
return this.cachedapp;
|
|
}
|
|
}
|
|
|
|
else, this is for Session:
|
|
private MyNS.MyClass ses {
|
|
get {
|
|
return ((MyNS.MyClass) (this.Session.StaticObjects.GetObject("ses")));
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
CodeExpression result = null;
|
|
|
|
CodeMemberProperty prop = new CodeMemberProperty ();
|
|
prop.Type = new CodeTypeReference (type);
|
|
prop.Name = propName;
|
|
if (isPublic)
|
|
prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
else
|
|
prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
|
|
|
|
CodePropertyReferenceExpression p1;
|
|
if (isApplication)
|
|
p1 = new CodePropertyReferenceExpression (thisRef, "Application");
|
|
else
|
|
p1 = new CodePropertyReferenceExpression (thisRef, "Session");
|
|
|
|
CodePropertyReferenceExpression p2;
|
|
p2 = new CodePropertyReferenceExpression (p1, "StaticObjects");
|
|
|
|
CodeMethodReferenceExpression getobject;
|
|
getobject = new CodeMethodReferenceExpression (p2, "GetObject");
|
|
|
|
CodeMethodInvokeExpression invoker;
|
|
invoker = new CodeMethodInvokeExpression (getobject,
|
|
new CodePrimitiveExpression (propName));
|
|
|
|
CodeCastExpression cast = new CodeCastExpression (prop.Type, invoker);
|
|
|
|
if (isApplication) {
|
|
CodeFieldReferenceExpression field;
|
|
field = new CodeFieldReferenceExpression (thisRef, "cached" + propName);
|
|
|
|
CodeConditionStatement stmt = new CodeConditionStatement();
|
|
stmt.Condition = new CodeBinaryOperatorExpression (field,
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression (null));
|
|
|
|
CodeAssignStatement assign = new CodeAssignStatement ();
|
|
assign.Left = field;
|
|
assign.Right = cast;
|
|
stmt.TrueStatements.Add (assign);
|
|
prop.GetStatements.Add (stmt);
|
|
result = field;
|
|
} else {
|
|
result = cast;
|
|
}
|
|
|
|
prop.GetStatements.Add (new CodeMethodReturnStatement (result));
|
|
mainClass.Members.Add (prop);
|
|
}
|
|
|
|
protected string CreateFieldForObject (Type type, string name)
|
|
{
|
|
string fieldName = "cached" + name;
|
|
CodeMemberField f = new CodeMemberField (type, fieldName);
|
|
f.Attributes = MemberAttributes.Private;
|
|
mainClass.Members.Add (f);
|
|
return fieldName;
|
|
}
|
|
|
|
protected void CreatePropertyForObject (Type type, string propName, string fieldName, bool isPublic)
|
|
{
|
|
CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, fieldName);
|
|
CodeMemberProperty prop = new CodeMemberProperty ();
|
|
prop.Type = new CodeTypeReference (type);
|
|
prop.Name = propName;
|
|
if (isPublic)
|
|
prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
else
|
|
prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
|
|
|
|
CodeConditionStatement stmt = new CodeConditionStatement();
|
|
stmt.Condition = new CodeBinaryOperatorExpression (field,
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression (null));
|
|
|
|
CodeObjectCreateExpression create = new CodeObjectCreateExpression (prop.Type);
|
|
stmt.TrueStatements.Add (new CodeAssignStatement (field, create));
|
|
prop.GetStatements.Add (stmt);
|
|
prop.GetStatements.Add (new CodeMethodReturnStatement (field));
|
|
|
|
mainClass.Members.Add (prop);
|
|
}
|
|
/******/
|
|
|
|
void CheckCompilerErrors (CompilerResults results)
|
|
{
|
|
if (results.NativeCompilerReturnValue == 0)
|
|
return;
|
|
|
|
string fileText = null;
|
|
CompilerErrorCollection errors = results.Errors;
|
|
CompilerError ce = (errors != null && errors.Count > 0) ? errors [0] : null;
|
|
string inFile = (ce != null) ? ce.FileName : null;
|
|
|
|
if (inFile != null && File.Exists (inFile)) {
|
|
using (StreamReader sr = File.OpenText (inFile)) {
|
|
fileText = sr.ReadToEnd ();
|
|
}
|
|
} else {
|
|
StringWriter writer = new StringWriter();
|
|
provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
|
|
fileText = writer.ToString ();
|
|
}
|
|
throw new CompilationException (parser.InputFile, errors, fileText);
|
|
}
|
|
|
|
protected string DynamicDir ()
|
|
{
|
|
return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
|
|
}
|
|
|
|
internal static CodeDomProvider CreateProvider (string lang)
|
|
{
|
|
CompilerParameters par;
|
|
string tempdir;
|
|
|
|
return CreateProvider (HttpContext.Current, lang, out par, out tempdir);
|
|
}
|
|
|
|
internal static CodeDomProvider CreateProvider (string lang, out string compilerOptions, out int warningLevel, out string tempdir)
|
|
{
|
|
return CreateProvider (HttpContext.Current, lang, out compilerOptions, out warningLevel, out tempdir);
|
|
}
|
|
|
|
internal static CodeDomProvider CreateProvider (HttpContext context, string lang, out string compilerOptions, out int warningLevel, out string tempdir)
|
|
{
|
|
CodeDomProvider ret;
|
|
CompilerParameters par;
|
|
|
|
ret = CreateProvider (context, lang, out par, out tempdir);
|
|
if (par != null){
|
|
warningLevel = par.WarningLevel;
|
|
compilerOptions = par.CompilerOptions;
|
|
} else {
|
|
warningLevel = 2;
|
|
compilerOptions = String.Empty;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
internal static CodeDomProvider CreateProvider (HttpContext context, string lang, out CompilerParameters par, out string tempdir)
|
|
{
|
|
CodeDomProvider ret = null;
|
|
par = null;
|
|
|
|
CompilationSection config = (CompilationSection) WebConfigurationManager.GetWebApplicationSection ("system.web/compilation");
|
|
Compiler comp = config.Compilers[lang];
|
|
|
|
if (comp == null) {
|
|
CompilerInfo info = CodeDomProvider.GetCompilerInfo (lang);
|
|
if (info != null && info.IsCodeDomProviderTypeValid) {
|
|
ret = info.CreateProvider ();
|
|
par = info.CreateDefaultCompilerParameters ();
|
|
}
|
|
} else {
|
|
Type t = HttpApplication.LoadType (comp.Type, true);
|
|
ret = Activator.CreateInstance (t) as CodeDomProvider;
|
|
|
|
par = new CompilerParameters ();
|
|
par.CompilerOptions = comp.CompilerOptions;
|
|
par.WarningLevel = comp.WarningLevel;
|
|
}
|
|
tempdir = config.TempDirectory;
|
|
|
|
return ret;
|
|
}
|
|
|
|
[MonoTODO ("find out how to extract the warningLevel and compilerOptions in the <system.codedom> case")]
|
|
public virtual Type GetCompiledType ()
|
|
{
|
|
Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
|
|
if (type != null)
|
|
return type;
|
|
|
|
ConstructType ();
|
|
string lang = parser.Language;
|
|
string tempdir;
|
|
string compilerOptions;
|
|
int warningLevel;
|
|
|
|
Provider = CreateProvider (parser.Context, lang, out compilerOptions, out warningLevel, out tempdir);
|
|
if (Provider == null)
|
|
throw new HttpException ("Configuration error. Language not supported: " +
|
|
lang, 500);
|
|
|
|
CompilerParameters parameters = CompilerParameters;
|
|
parameters.IncludeDebugInformation = parser.Debug;
|
|
parameters.CompilerOptions = compilerOptions + " " + parser.CompilerOptions;
|
|
parameters.WarningLevel = warningLevel;
|
|
|
|
bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
|
|
|
|
if (tempdir == null || tempdir == "")
|
|
tempdir = DynamicDir ();
|
|
|
|
TempFileCollection tempcoll = new TempFileCollection (tempdir, keepFiles);
|
|
parameters.TempFiles = tempcoll;
|
|
string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
|
|
parameters.OutputAssembly = Path.Combine (DynamicDir (), dllfilename);
|
|
|
|
CompilerResults results = CachingCompiler.Compile (this);
|
|
CheckCompilerErrors (results);
|
|
Assembly assembly = results.CompiledAssembly;
|
|
if (assembly == null) {
|
|
if (!File.Exists (parameters.OutputAssembly)) {
|
|
results.TempFiles.Delete ();
|
|
throw new CompilationException (parser.InputFile, results.Errors,
|
|
"No assembly returned after compilation!?");
|
|
}
|
|
|
|
assembly = Assembly.LoadFrom (parameters.OutputAssembly);
|
|
}
|
|
|
|
results.TempFiles.Delete ();
|
|
Type mainClassType = assembly.GetType (MainClassType, true);
|
|
|
|
if (parser.IsPartial) {
|
|
// With the partial classes, we need to make sure we
|
|
// don't have any methods that should have not been
|
|
// created (because they are accessible from the base
|
|
// types). We cannot do this normally because the
|
|
// codebehind file is actually a partial class and we
|
|
// have no way of identifying the partial class' base
|
|
// type until now.
|
|
if (!isRebuilding && CheckPartialBaseType (mainClassType)) {
|
|
isRebuilding = true;
|
|
parser.RootBuilder.ResetState ();
|
|
return GetCompiledType ();
|
|
}
|
|
}
|
|
|
|
return mainClassType;
|
|
}
|
|
|
|
internal string MainClassType {
|
|
get {
|
|
if (mainClassExpr == null)
|
|
return null;
|
|
|
|
return mainClassExpr.Type.BaseType;
|
|
}
|
|
}
|
|
|
|
internal bool IsRebuildingPartial
|
|
{
|
|
get { return isRebuilding; }
|
|
}
|
|
|
|
internal bool CheckPartialBaseType (Type type)
|
|
{
|
|
// Get the base type. If we don't have any (bad thing), we
|
|
// don't need to replace ourselves. Also check for the
|
|
// core file, since that won't have any either.
|
|
Type baseType = type.BaseType;
|
|
if (baseType == null || baseType == typeof(System.Web.UI.Page))
|
|
return false;
|
|
|
|
bool rebuild = false;
|
|
|
|
if (CheckPartialBaseFields (type, baseType))
|
|
rebuild = true;
|
|
|
|
if (CheckPartialBaseProperties (type, baseType))
|
|
rebuild = true;
|
|
|
|
return rebuild;
|
|
}
|
|
|
|
internal bool CheckPartialBaseFields (Type type, Type baseType)
|
|
{
|
|
bool rebuild = false;
|
|
|
|
foreach (FieldInfo baseInfo in baseType.GetFields (replaceableFlags)) {
|
|
if (baseInfo.IsPrivate)
|
|
continue;
|
|
|
|
FieldInfo typeInfo = type.GetField (baseInfo.Name, replaceableFlags);
|
|
|
|
if (typeInfo != null && typeInfo.DeclaringType == type) {
|
|
partialNameOverride [typeInfo.Name] = true;
|
|
rebuild = true;
|
|
}
|
|
}
|
|
|
|
return rebuild;
|
|
}
|
|
|
|
internal bool CheckPartialBaseProperties (Type type, Type baseType)
|
|
{
|
|
bool rebuild = false;
|
|
|
|
foreach (PropertyInfo baseInfo in baseType.GetProperties ()) {
|
|
PropertyInfo typeInfo = type.GetProperty (baseInfo.Name);
|
|
|
|
if (typeInfo != null && typeInfo.DeclaringType == type) {
|
|
partialNameOverride [typeInfo.Name] = true;
|
|
rebuild = true;
|
|
}
|
|
}
|
|
|
|
return rebuild;
|
|
}
|
|
|
|
internal CodeDomProvider Provider {
|
|
get { return provider; }
|
|
set { provider = value; }
|
|
}
|
|
|
|
internal ICodeCompiler Compiler {
|
|
get { return compiler; }
|
|
set { compiler = value; }
|
|
}
|
|
|
|
internal CompilerParameters CompilerParameters {
|
|
get {
|
|
if (compilerParameters == null)
|
|
compilerParameters = new CompilerParameters ();
|
|
|
|
return compilerParameters;
|
|
}
|
|
|
|
set { compilerParameters = value; }
|
|
}
|
|
|
|
internal CodeCompileUnit CompileUnit {
|
|
get { return unit; }
|
|
}
|
|
|
|
internal CodeTypeDeclaration DerivedType {
|
|
get { return mainClass; }
|
|
}
|
|
|
|
internal CodeTypeDeclaration BaseType {
|
|
get {
|
|
if (partialClass == null)
|
|
return DerivedType;
|
|
return partialClass;
|
|
}
|
|
}
|
|
|
|
internal TemplateParser Parser {
|
|
get { return parser; }
|
|
}
|
|
}
|
|
}
|
|
|