BaseCompiler.cs 25 KB

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