[asp.net] Ignore JavaScript blocks enclosed in HTML comments
[mono.git] / mcs / class / System.Web / System.Web.Compilation / BaseCompiler.cs
1 //
2 // System.Web.Compilation.BaseCompiler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (c) Copyright 2002,2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.CodeDom;
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Reflection;
37 using System.Text;
38 using System.Web.UI;
39 using System.Web.Configuration;
40 using System.IO;
41
42 namespace System.Web.Compilation
43 {
44         abstract class BaseCompiler
45         {
46                 const string DEFAULT_NAMESPACE = "ASP";
47                 internal static Guid HashMD5 = new Guid(0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99);
48                 static BindingFlags replaceableFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
49
50                 TemplateParser parser;
51                 CodeDomProvider provider;
52                 ICodeCompiler compiler;
53                 CodeCompileUnit unit;
54                 CodeNamespace mainNS;
55                 CompilerParameters compilerParameters;
56                 bool isRebuilding = false;
57                 protected Hashtable partialNameOverride = new Hashtable();
58                 protected CodeTypeDeclaration partialClass;
59                 protected CodeTypeReferenceExpression partialClassExpr;
60                 protected CodeTypeDeclaration mainClass;
61                 protected CodeTypeReferenceExpression mainClassExpr;
62                 protected static CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression ();
63
64                 VirtualPath inputVirtualPath;
65                 
66                 public VirtualPath InputVirtualPath {
67                         get {
68                                 if (inputVirtualPath == null)
69                                         inputVirtualPath = new VirtualPath (VirtualPathUtility.Combine (parser.BaseVirtualDir, Path.GetFileName (parser.InputFile)));
70
71                                 return inputVirtualPath;
72                         }
73                 }
74                 
75                 protected BaseCompiler (TemplateParser parser)
76                 {
77                         this.parser = parser;
78                 }
79
80                 protected void AddReferencedAssembly (Assembly asm)
81                 {
82                         if (unit == null || asm == null)
83                                 return;
84
85                         StringCollection refAsm = unit.ReferencedAssemblies;
86                         string asmLocation = asm.Location;
87                         if (!refAsm.Contains (asmLocation))
88                                 refAsm.Add (asmLocation);
89                 }
90                 
91                 internal CodeStatement AddLinePragma (CodeExpression expression, ControlBuilder builder)
92                 {
93                         return AddLinePragma (new CodeExpressionStatement (expression), builder);
94                 }
95                 
96                 internal CodeStatement AddLinePragma (CodeStatement statement, ControlBuilder builder)
97                 {
98                         if (builder == null || statement == null)
99                                 return statement;
100
101                         ILocation location = null;
102
103                         if (!(builder is CodeRenderBuilder))
104                                 location = builder.Location;
105                         
106                         if (location != null)
107                                 return AddLinePragma (statement, location);
108                         else
109                                 return AddLinePragma (statement, builder.Line, builder.FileName);
110                 }
111
112                 internal CodeStatement AddLinePragma (CodeStatement statement, ILocation location)
113                 {
114                         if (location == null || statement == null)
115                                 return statement;
116                         
117                         return AddLinePragma (statement, location.BeginLine, location.Filename);
118                 }
119
120                 bool IgnoreFile (string fileName)
121                 {
122                         if (parser != null && !parser.LinePragmasOn)
123                                 return true;
124                         
125                         return String.Compare (fileName, "@@inner_string@@", StringComparison.OrdinalIgnoreCase) == 0;
126                 }
127                 
128                 internal CodeStatement AddLinePragma (CodeStatement statement, int line, string fileName)
129                 {
130                         if (statement == null || IgnoreFile (fileName))
131                                 return statement;
132                         
133                         statement.LinePragma = new CodeLinePragma (fileName, line);
134                         return statement;                       
135                 }
136
137                 internal CodeTypeMember AddLinePragma (CodeTypeMember member, ControlBuilder builder)
138                 {
139                         if (builder == null || member == null)
140                                 return member;
141
142                         ILocation location = builder.Location;
143                         
144                         if (location != null)
145                                 return AddLinePragma (member, location);
146                         else
147                                 return AddLinePragma (member, builder.Line, builder.FileName);
148                 }
149                 
150                 internal CodeTypeMember AddLinePragma (CodeTypeMember member, ILocation location)
151                 {
152                         if (location == null || member == null)
153                                 return member;
154
155                         return AddLinePragma (member, location.BeginLine, location.Filename);
156                 }
157                 
158                 internal CodeTypeMember AddLinePragma (CodeTypeMember member, int line, string fileName)
159                 {
160                         if (member == null || IgnoreFile (fileName))
161                                 return member;
162                         
163                         member.LinePragma = new CodeLinePragma (fileName, line);
164                         return member;
165                 }
166                 
167                 internal void ConstructType ()
168                 {
169                         unit = new CodeCompileUnit ();
170                         byte[] md5checksum = parser.MD5Checksum;
171
172                         if (md5checksum != null) {
173                                 CodeChecksumPragma pragma = new CodeChecksumPragma ();
174                                 pragma.FileName = parser.InputFile;
175                                 pragma.ChecksumAlgorithmId = HashMD5;
176                                 pragma.ChecksumData = md5checksum;
177
178                                 unit.StartDirectives.Add (pragma);
179                         }
180
181                         if (parser.IsPartial) {
182                                 string partialns = null;
183                                 string partialclasstype = parser.PartialClassName;
184
185                                 int partialdot = partialclasstype.LastIndexOf ('.');
186                                 if (partialdot != -1) {
187                                         partialns = partialclasstype.Substring (0, partialdot);
188                                         partialclasstype = partialclasstype.Substring (partialdot + 1);
189                                 }
190                                 
191                                 CodeNamespace partialNS = new CodeNamespace (partialns);
192                                 partialClass = new CodeTypeDeclaration (partialclasstype);
193                                 partialClass.IsPartial = true;
194                                 partialClassExpr = new CodeTypeReferenceExpression (parser.PartialClassName);
195                                 
196                                 unit.Namespaces.Add (partialNS);
197                                 partialClass.TypeAttributes = TypeAttributes.Public;
198                                 partialNS.Types.Add (partialClass);
199                         }
200
201                         string mainclasstype = parser.ClassName;
202                         string mainns = DEFAULT_NAMESPACE;
203                         int maindot = mainclasstype.LastIndexOf ('.');
204                         if (maindot != -1) {
205                                 mainns = mainclasstype.Substring (0, maindot);
206                                 mainclasstype = mainclasstype.Substring (maindot + 1);
207                         }
208
209                         mainNS = new CodeNamespace (mainns);
210                         mainClass = new CodeTypeDeclaration (mainclasstype);
211                         CodeTypeReference baseTypeRef;
212                         if (partialClass != null) {
213                                 baseTypeRef = new CodeTypeReference (parser.PartialClassName);
214                                 baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
215                         } else {
216                                 baseTypeRef = new CodeTypeReference (parser.BaseType.FullName);
217                                 if (parser.BaseTypeIsGlobal)
218                                         baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
219                         }
220                         mainClass.BaseTypes.Add (baseTypeRef);
221
222                         mainClassExpr = new CodeTypeReferenceExpression (mainns + "." + mainclasstype);
223
224                         unit.Namespaces.Add (mainNS);
225                         mainClass.TypeAttributes = TypeAttributes.Public;
226                         mainNS.Types.Add (mainClass);
227
228                         foreach (object o in parser.Imports.Keys) {
229                                 if (o is string)
230                                         mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
231                         }
232
233                         // StringCollection.Contains has O(n) complexity, but
234                         // considering the number of comparisons we make on
235                         // average and the fact that using an intermediate array
236                         // would be even more costly, this is fine here.
237                         StringCollection refAsm = unit.ReferencedAssemblies;
238                         string asmName;
239                         if (parser.Assemblies != null) {
240                                 foreach (object o in parser.Assemblies) {
241                                         asmName = o as string;
242                                         if (asmName != null && !refAsm.Contains (asmName))
243                                                 refAsm.Add (asmName);
244                                 }
245                         }
246
247                         ArrayList al = WebConfigurationManager.ExtraAssemblies;
248                         if (al != null && al.Count > 0) {
249                                 foreach (object o in al) {
250                                         asmName = o as string;
251                                         if (asmName != null && !refAsm.Contains (asmName))
252                                                 refAsm.Add (asmName);
253                                 }
254                         }
255
256                         IList list = BuildManager.CodeAssemblies;
257                         if (list != null && list.Count > 0) {
258                                 Assembly asm;
259                                 foreach (object o in list) {
260                                         asm = o as Assembly;
261                                         if (o == null)
262                                                 continue;
263                                         asmName = asm.Location;
264                                         if (asmName != null && !refAsm.Contains (asmName))
265                                                 refAsm.Add (asmName);
266                                 }
267                         }
268
269                         // Late-bound generators specifics (as for MonoBASIC/VB.NET)
270                         unit.UserData["RequireVariableDeclaration"] = parser.ExplicitOn;
271                         unit.UserData["AllowLateBound"] = !parser.StrictOn;
272
273                         InitializeType ();
274                         AddInterfaces ();
275                         AddClassAttributes ();
276                         CreateStaticFields ();
277                         AddApplicationAndSessionObjects ();
278                         AddScripts ();
279                         CreateMethods ();
280                         CreateConstructor (null, null);
281                 }
282
283                 internal CodeFieldReferenceExpression GetMainClassFieldReferenceExpression (string fieldName)
284                 {
285                         CodeTypeReference mainClassTypeRef;
286                         mainClassTypeRef = new CodeTypeReference (mainNS.Name + "." + mainClass.Name);
287                         mainClassTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
288
289                         return new CodeFieldReferenceExpression (
290                                 new CodeTypeReferenceExpression (mainClassTypeRef), fieldName);
291                 }
292
293                 protected virtual void InitializeType ()
294                 {}
295                 
296                 protected virtual void CreateStaticFields ()
297                 {
298                         CodeMemberField fld = new CodeMemberField (typeof (bool), "__initialized");
299                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
300                         fld.InitExpression = new CodePrimitiveExpression (false);
301                         mainClass.Members.Add (fld);
302                 }
303
304                 void AssignAppRelativeVirtualPath (CodeConstructor ctor)
305                 {
306                         if (String.IsNullOrEmpty (parser.InputFile))
307                                 return;
308                         
309                         Type baseType = parser.CodeFileBaseClassType;
310                         if (baseType == null)
311                                 baseType = parser.BaseType;
312                         if (baseType == null)
313                                 return;
314                         if (!baseType.IsSubclassOf (typeof (System.Web.UI.TemplateControl)))
315                                 return;
316                         
317                         CodeTypeReference baseTypeRef = new CodeTypeReference (baseType.FullName);
318                         if (parser.BaseTypeIsGlobal)
319                                 baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
320                         
321                         CodeExpression cast = new CodeCastExpression (baseTypeRef, new CodeThisReferenceExpression ());
322                         CodePropertyReferenceExpression arvpProp = new CodePropertyReferenceExpression (cast, "AppRelativeVirtualPath");
323                         CodeAssignStatement arvpAssign = new CodeAssignStatement ();
324                         arvpAssign.Left = arvpProp;
325                         arvpAssign.Right = new CodePrimitiveExpression (VirtualPathUtility.RemoveTrailingSlash (InputVirtualPath.AppRelative));
326                         ctor.Statements.Add (arvpAssign);
327                 }
328                 
329                 protected virtual void CreateConstructor (CodeStatementCollection localVars,
330                                                           CodeStatementCollection trueStmt)
331                 {
332                         CodeConstructor ctor = new CodeConstructor ();
333                         ctor.Attributes = MemberAttributes.Public;
334                         mainClass.Members.Add (ctor);
335
336                         if (localVars != null)
337                                 ctor.Statements.AddRange (localVars);
338
339                         AssignAppRelativeVirtualPath (ctor);
340
341                         CodeFieldReferenceExpression initialized = GetMainClassFieldReferenceExpression ("__initialized");
342                         
343                         CodeBinaryOperatorExpression bin;
344                         bin = new CodeBinaryOperatorExpression (initialized,
345                                                                 CodeBinaryOperatorType.ValueEquality,
346                                                                 new CodePrimitiveExpression (false));
347
348                         CodeAssignStatement assign = new CodeAssignStatement (initialized,
349                                                                               new CodePrimitiveExpression (true));
350
351                         CodeConditionStatement cond = new CodeConditionStatement ();
352                         cond.Condition = bin;
353                         
354                         if (trueStmt != null)
355                                 cond.TrueStatements.AddRange (trueStmt);
356                         cond.TrueStatements.Add (assign);
357                         ctor.Statements.Add (cond);
358                         AddStatementsToConstructor (ctor);
359                 }
360
361                 protected virtual void AddStatementsToConstructor (CodeConstructor ctor)
362                 {
363                 }
364                 
365                 void AddScripts ()
366                 {
367                         if (parser.Scripts == null || parser.Scripts.Count == 0)
368                                 return;
369
370                         ServerSideScript sss;
371                         
372                         foreach (object o in parser.Scripts) {
373                                 sss = o as ServerSideScript;
374
375                                 if (sss == null)
376                                         continue;
377                                 
378                                 mainClass.Members.Add (AddLinePragma (new CodeSnippetTypeMember (sss.Script), sss.Location));
379                         }
380                 }
381                 
382                 protected internal virtual void CreateMethods ()
383                 {
384                 }
385
386                 void InternalCreatePageProperty (string retType, string name, string contextProperty)
387                 {
388                         CodeMemberProperty property = new CodeMemberProperty ();
389                         property.Name = name;
390                         property.Type = new CodeTypeReference (retType);
391                         property.Attributes = MemberAttributes.Family | MemberAttributes.Final;
392
393                         CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
394                         CodeCastExpression cast = new CodeCastExpression ();
395                         ret.Expression = cast;
396                         
397                         CodePropertyReferenceExpression refexp = new CodePropertyReferenceExpression ();
398                         refexp.TargetObject = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Context");
399                         refexp.PropertyName = contextProperty;
400                         
401                         cast.TargetType = new CodeTypeReference (retType);
402                         cast.Expression = refexp;
403                         
404                         property.GetStatements.Add (ret);
405                         if (partialClass == null)
406                                 mainClass.Members.Add (property);
407                         else
408                                 partialClass.Members.Add (property);
409                 }
410                 
411                 protected void CreateProfileProperty ()
412                 {
413                         string retType;
414                         if (AppCodeCompiler.HaveCustomProfile (WebConfigurationManager.GetWebApplicationSection ("system.web/profile") as ProfileSection))
415                                 retType = "ProfileCommon";
416                         else
417                                 retType = "System.Web.Profile.DefaultProfile";
418                         InternalCreatePageProperty (retType, "Profile", "Profile");
419                 }
420                 
421                 protected virtual void AddInterfaces ()
422                 {
423                         if (parser.Interfaces == null)
424                                 return;
425
426                         foreach (object o in parser.Interfaces) {
427                                 if (o is string)
428                                         mainClass.BaseTypes.Add (new CodeTypeReference ((string) o));
429                         }
430                 }
431
432                 protected virtual void AddClassAttributes ()
433                 {
434                 }
435                 
436                 protected virtual void AddApplicationAndSessionObjects ()
437                 {
438                 }
439
440                 /* Utility methods for <object> stuff */
441                 protected void CreateApplicationOrSessionPropertyForObject (Type type,
442                                                                             string propName,
443                                                                             bool isApplication,
444                                                                             bool isPublic)
445                 {
446                         /* if isApplication this generates (the 'cachedapp' field is created earlier):
447                         private MyNS.MyClass app {
448                                 get {
449                                         if ((this.cachedapp == null)) {
450                                                 this.cachedapp = ((MyNS.MyClass)
451                                                         (this.Application.StaticObjects.GetObject("app")));
452                                         }
453                                         return this.cachedapp;
454                                 }
455                         }
456
457                         else, this is for Session:
458                         private MyNS.MyClass ses {
459                                 get {
460                                         return ((MyNS.MyClass) (this.Session.StaticObjects.GetObject("ses")));
461                                 }
462                         }
463
464                         */
465
466                         CodeExpression result = null;
467
468                         CodeMemberProperty prop = new CodeMemberProperty ();
469                         prop.Type = new CodeTypeReference (type);
470                         prop.Name = propName;
471                         if (isPublic)
472                                 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
473                         else
474                                 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
475
476                         CodePropertyReferenceExpression p1;
477                         if (isApplication)
478                                 p1 = new CodePropertyReferenceExpression (thisRef, "Application");
479                         else
480                                 p1 = new CodePropertyReferenceExpression (thisRef, "Session");
481
482                         CodePropertyReferenceExpression p2;
483                         p2 = new CodePropertyReferenceExpression (p1, "StaticObjects");
484
485                         CodeMethodReferenceExpression getobject;
486                         getobject = new CodeMethodReferenceExpression (p2, "GetObject");
487
488                         CodeMethodInvokeExpression invoker;
489                         invoker = new CodeMethodInvokeExpression (getobject,
490                                                 new CodePrimitiveExpression (propName));
491
492                         CodeCastExpression cast = new CodeCastExpression (prop.Type, invoker);
493
494                         if (isApplication) {
495                                 CodeFieldReferenceExpression field;
496                                 field = new CodeFieldReferenceExpression (thisRef, "cached" + propName);
497
498                                 CodeConditionStatement stmt = new CodeConditionStatement();
499                                 stmt.Condition = new CodeBinaryOperatorExpression (field,
500                                                         CodeBinaryOperatorType.IdentityEquality,
501                                                         new CodePrimitiveExpression (null));
502
503                                 CodeAssignStatement assign = new CodeAssignStatement ();
504                                 assign.Left = field;
505                                 assign.Right = cast;
506                                 stmt.TrueStatements.Add (assign);
507                                 prop.GetStatements.Add (stmt);
508                                 result = field;
509                         } else {
510                                 result = cast;
511                         }
512                                                 
513                         prop.GetStatements.Add (new CodeMethodReturnStatement (result));
514                         mainClass.Members.Add (prop);
515                 }
516
517                 protected string CreateFieldForObject (Type type, string name)
518                 {
519                         string fieldName = "cached" + name;
520                         CodeMemberField f = new CodeMemberField (type, fieldName);
521                         f.Attributes = MemberAttributes.Private;
522                         mainClass.Members.Add (f);
523                         return fieldName;
524                 }
525
526                 protected void CreatePropertyForObject (Type type, string propName, string fieldName, bool isPublic)
527                 {
528                         CodeFieldReferenceExpression field = new CodeFieldReferenceExpression (thisRef, fieldName);
529                         CodeMemberProperty prop = new CodeMemberProperty ();
530                         prop.Type = new CodeTypeReference (type);
531                         prop.Name = propName;
532                         if (isPublic)
533                                 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
534                         else
535                                 prop.Attributes = MemberAttributes.Private | MemberAttributes.Final;
536
537                         CodeConditionStatement stmt = new CodeConditionStatement();
538                         stmt.Condition = new CodeBinaryOperatorExpression (field,
539                                                 CodeBinaryOperatorType.IdentityEquality,
540                                                 new CodePrimitiveExpression (null));
541
542                         CodeObjectCreateExpression create = new CodeObjectCreateExpression (prop.Type); 
543                         stmt.TrueStatements.Add (new CodeAssignStatement (field, create));
544                         prop.GetStatements.Add (stmt);
545                         prop.GetStatements.Add (new CodeMethodReturnStatement (field));
546
547                         mainClass.Members.Add (prop);
548                 }
549                 /******/
550
551                 void CheckCompilerErrors (CompilerResults results)
552                 {
553                         if (results.NativeCompilerReturnValue == 0)
554                                 return;
555
556                         string fileText = null;
557                         CompilerErrorCollection errors = results.Errors;
558                         CompilerError ce = (errors != null && errors.Count > 0) ? errors [0] : null;
559                         string inFile = (ce != null) ? ce.FileName : null;
560                         
561                         if (inFile != null && File.Exists (inFile)) {
562                                 using (StreamReader sr = File.OpenText (inFile)) {
563                                         fileText = sr.ReadToEnd ();
564                                 }
565                         } else {
566                                 StringWriter writer = new StringWriter();
567                                 provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
568                                 fileText = writer.ToString ();
569                         }
570                         throw new CompilationException (parser.InputFile, errors, fileText);
571                 }
572
573                 protected string DynamicDir ()
574                 {
575                         return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
576                 }
577
578                 internal static CodeDomProvider CreateProvider (string lang)
579                 {
580                         CompilerParameters par;
581                         string tempdir;
582                         
583                         return CreateProvider (HttpContext.Current, lang, out par, out tempdir);
584                 }
585                 
586                 internal static CodeDomProvider CreateProvider (string lang, out string compilerOptions, out int warningLevel, out string tempdir)
587                 {
588                         return CreateProvider (HttpContext.Current, lang, out compilerOptions, out warningLevel, out tempdir);
589                 }
590                 
591                 internal static CodeDomProvider CreateProvider (HttpContext context, string lang, out string compilerOptions, out int warningLevel, out string tempdir)
592                 {
593                         CodeDomProvider ret;
594                         CompilerParameters par;
595
596                         ret = CreateProvider (context, lang, out par, out tempdir);
597                         if (par != null){
598                                 warningLevel = par.WarningLevel;
599                                 compilerOptions = par.CompilerOptions;
600                         } else {
601                                 warningLevel = 2;
602                                 compilerOptions = String.Empty;
603                         }
604
605                         return ret;
606                 }
607
608                 internal static CodeDomProvider CreateProvider (HttpContext context, string lang, out CompilerParameters par, out string tempdir)
609                 {
610                         CodeDomProvider ret = null;
611                         par = null;
612                         
613                         CompilationSection config = (CompilationSection) WebConfigurationManager.GetWebApplicationSection ("system.web/compilation");
614                         Compiler comp = config.Compilers[lang];
615                         
616                         if (comp == null) {
617                                 CompilerInfo info = CodeDomProvider.GetCompilerInfo (lang);
618                                 if (info != null && info.IsCodeDomProviderTypeValid) {
619                                         ret = info.CreateProvider ();
620                                         par = info.CreateDefaultCompilerParameters ();
621                                 }
622                         } else {
623                                 Type t = HttpApplication.LoadType (comp.Type, true);
624                                 ret = Activator.CreateInstance (t) as CodeDomProvider;
625
626                                 par = new CompilerParameters ();
627                                 par.CompilerOptions = comp.CompilerOptions;
628                                 par.WarningLevel = comp.WarningLevel;
629                         }
630                         tempdir = config.TempDirectory;
631
632                         return ret;
633                 }
634                 
635                 [MonoTODO ("find out how to extract the warningLevel and compilerOptions in the <system.codedom> case")]
636                 public virtual Type GetCompiledType () 
637                 {
638                         Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
639                         if (type != null)
640                                 return type;
641
642                         ConstructType ();
643                         string lang = parser.Language;
644                         string tempdir;
645                         string compilerOptions;
646                         int warningLevel;
647
648                         Provider = CreateProvider (parser.Context, lang, out compilerOptions, out warningLevel, out tempdir);
649                         if (Provider == null)
650                                 throw new HttpException ("Configuration error. Language not supported: " +
651                                                           lang, 500);
652
653                         CompilerParameters parameters = CompilerParameters;
654                         parameters.IncludeDebugInformation = parser.Debug;
655                         parameters.CompilerOptions = compilerOptions + " " + parser.CompilerOptions;
656                         parameters.WarningLevel = warningLevel;
657                         
658                         bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
659
660                         if (tempdir == null || tempdir == "")
661                                 tempdir = DynamicDir ();
662                                 
663                         TempFileCollection tempcoll = new TempFileCollection (tempdir, keepFiles);
664                         parameters.TempFiles = tempcoll;
665                         string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
666                         parameters.OutputAssembly = Path.Combine (DynamicDir (), dllfilename);
667
668                         CompilerResults results = CachingCompiler.Compile (this);
669                         CheckCompilerErrors (results);
670                         Assembly assembly = results.CompiledAssembly;
671                         if (assembly == null) {
672                                 if (!File.Exists (parameters.OutputAssembly)) {
673                                         results.TempFiles.Delete ();
674                                         throw new CompilationException (parser.InputFile, results.Errors,
675                                                 "No assembly returned after compilation!?");
676                                 }
677
678                                 assembly = Assembly.LoadFrom (parameters.OutputAssembly);
679                         }
680
681                         results.TempFiles.Delete ();
682                         Type mainClassType = assembly.GetType (MainClassType, true);
683
684                         if (parser.IsPartial) {
685                                 // With the partial classes, we need to make sure we
686                                 // don't have any methods that should have not been
687                                 // created (because they are accessible from the base
688                                 // types). We cannot do this normally because the
689                                 // codebehind file is actually a partial class and we
690                                 // have no way of identifying the partial class' base
691                                 // type until now.
692                                 if (!isRebuilding && CheckPartialBaseType (mainClassType)) {
693                                         isRebuilding = true;
694                                         parser.RootBuilder.ResetState ();
695                                         return GetCompiledType ();
696                                 }
697                         }
698
699                         return mainClassType;
700                 }
701
702                 internal string MainClassType {
703                         get {
704                                 if (mainClassExpr == null)
705                                         return null;
706
707                                 return mainClassExpr.Type.BaseType;
708                         }
709                 }
710                 
711                 internal bool IsRebuildingPartial
712                 {
713                         get { return isRebuilding; }
714                 }
715
716                 internal bool CheckPartialBaseType (Type type)
717                 {
718                         // Get the base type. If we don't have any (bad thing), we
719                         // don't need to replace ourselves. Also check for the
720                         // core file, since that won't have any either.
721                         Type baseType = type.BaseType;
722                         if (baseType == null || baseType == typeof(System.Web.UI.Page))
723                                 return false;
724
725                         bool rebuild = false;
726
727                         if (CheckPartialBaseFields (type, baseType))
728                                 rebuild = true;
729
730                         if (CheckPartialBaseProperties (type, baseType))
731                                 rebuild = true;
732
733                         return rebuild;
734                 }
735
736                 internal bool CheckPartialBaseFields (Type type, Type baseType)
737                 {
738                         bool rebuild = false;
739
740                         foreach (FieldInfo baseInfo in baseType.GetFields (replaceableFlags)) {
741                                 if (baseInfo.IsPrivate)
742                                         continue;
743
744                                 FieldInfo typeInfo = type.GetField (baseInfo.Name, replaceableFlags);
745
746                                 if (typeInfo != null && typeInfo.DeclaringType == type) {
747                                         partialNameOverride [typeInfo.Name] = true;
748                                         rebuild = true;
749                                 }
750                         }
751
752                         return rebuild;
753                 }
754
755                 internal bool CheckPartialBaseProperties (Type type, Type baseType)
756                 {
757                         bool rebuild = false;
758
759                         foreach (PropertyInfo baseInfo in baseType.GetProperties ()) {
760                                 PropertyInfo typeInfo = type.GetProperty (baseInfo.Name);
761
762                                 if (typeInfo != null && typeInfo.DeclaringType == type) {
763                                         partialNameOverride [typeInfo.Name] = true;
764                                         rebuild = true;
765                                 }
766                         }
767
768                         return rebuild;
769                 }
770
771                 internal CodeDomProvider Provider {
772                         get { return provider; }
773                         set { provider = value; }
774                 }
775
776                 internal ICodeCompiler Compiler {
777                         get { return compiler; }
778                         set { compiler = value; }
779                 }               
780
781                 internal CompilerParameters CompilerParameters {
782                         get {
783                                 if (compilerParameters == null)
784                                         compilerParameters = new CompilerParameters ();
785                                 
786                                 return compilerParameters;
787                         }
788                         
789                         set { compilerParameters = value; }
790                 }
791
792                 internal CodeCompileUnit CompileUnit {
793                         get { return unit; }
794                 }
795
796                 internal CodeTypeDeclaration DerivedType {
797                         get { return mainClass; }
798                 }
799
800                 internal CodeTypeDeclaration BaseType {
801                         get {
802                                 if (partialClass == null)
803                                         return DerivedType;
804                                 return partialClass;
805                         }
806                 }
807
808                 internal TemplateParser Parser {
809                         get { return parser; }
810                 }
811         }
812 }
813