The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Xslt \ NullErrorHelper

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XslAstAnalyzer.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.Globalization;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Xml.XPath;
  19. using System.Xml.Xsl.Qil;
  20. using System.Xml.Xsl.Runtime;
  21. using System.Xml.Xsl.XPath;
  22. namespace System.Xml.Xsl.Xslt
  23. {
  24.     using TypeFactory = XmlQueryTypeFactory;
  25.     using XPathFunctionInfo = XPathBuilder.FunctionInfo<XPathBuilder.FuncId>;
  26.     using XsltFunctionInfo = XPathBuilder.FunctionInfo<QilGenerator.FuncId>;
  27.    
  28.     // ------------------------------- XslAstAnalyzer -------------------------------
  29.    
  30.     internal class XslAstAnalyzer : XslVisitor<XslFlags>
  31.     {
  32.         private CompilerScopeManager<VarPar> scope;
  33.         private Compiler compiler;
  34.         #if DEBUG
  35.         // List of all variables and parameters
  36.         private List<VarPar> allVarPars = new List<VarPar>();
  37.         #endif
  38.         private int forEachDepth = 0;
  39.         private XPathAnalyzer xpathAnalyzer;
  40.         private ProtoTemplate currentTemplate;
  41.        
  42.         // Type donor of the last analyzed VarPar. Used for optimization of WithParam's.
  43.         private VarPar typeDonor;
  44.        
  45.         // Template dependencies
  46.         private Graph<ProtoTemplate> focusDonors = new Graph<ProtoTemplate>();
  47.         private Dictionary<Template, Stylesheet> dependsOnApplyImports = new Dictionary<Template, Stylesheet>();
  48.         private Graph<ProtoTemplate> sideEffectDonors = new Graph<ProtoTemplate>();
  49.         private Dictionary<QilName, List<ProtoTemplate>> dependsOnMode = new Dictionary<QilName, List<ProtoTemplate>>();
  50.        
  51.         // Data flow graph
  52.         private Graph<VarPar> dataFlow = new Graph<VarPar>();
  53.        
  54.         // Mapping (mode, param name) -> helper vertex in data flow graph
  55.         private Dictionary<ModeName, VarPar> applyTemplatesParams = new Dictionary<ModeName, VarPar>();
  56.        
  57.         // ---------------------------------- Graph<V> ----------------------------------
  58.         /// <summary>
  59.         /// Represents a graph using hashtable of adjacency lists.
  60.         /// </summary>
  61.         /// <typeparam name="V">Vertex type</typeparam>
  62.         internal class Graph<V> : Dictionary<V, List<V>> where V : XslNode
  63.         {
  64.             private static IList<V> empty = (new List<V>()).AsReadOnly();
  65.            
  66.             public IEnumerable<V> GetAdjList(V v)
  67.             {
  68.                 List<V> adjList;
  69.                 if (TryGetValue(v, out adjList) && adjList != null) {
  70.                     return adjList;
  71.                 }
  72.                 return empty;
  73.             }
  74.            
  75.             public void AddEdge(V v1, V v2)
  76.             {
  77.                 // Ignore loops
  78.                 if ((object)v1 == (object)v2) {
  79.                     return;
  80.                 }
  81.                
  82.                 List<V> adjList;
  83.                 if (!TryGetValue(v1, out adjList) || adjList == null) {
  84.                     adjList = this[v1] = new List<V>();
  85.                 }
  86.                
  87.                 // NOTE: We do not check for duplicate edges here
  88.                 adjList.Add(v2);
  89.                 if (!TryGetValue(v2, out adjList)) {
  90.                     this[v2] = null;
  91.                 }
  92.                
  93.                 Debug.WriteLineIf(DiagnosticsSwitches.XslTypeInference.TraceVerbose, v1.TraceName + " -> " + v2.TraceName);
  94.             }
  95.            
  96.             public void PropagateFlag(XslFlags flag)
  97.             {
  98.                 // Clean Stop flags
  99.                 foreach (V v in Keys) {
  100.                     v.Flags &= ~XslFlags.Stop;
  101.                 }
  102.                
  103.                 foreach (V v in Keys) {
  104.                     if ((v.Flags & XslFlags.Stop) == 0) {
  105.                         if ((v.Flags & flag) != 0) {
  106.                             DepthFirstSearch(v, flag);
  107.                         }
  108.                     }
  109.                 }
  110.             }
  111.            
  112.             private void DepthFirstSearch(V v, XslFlags flag)
  113.             {
  114.                 Debug.Assert((v.Flags & XslFlags.Stop) == 0, "Already visited this vertex");
  115.                 v.Flags |= (flag | XslFlags.Stop);
  116.                 foreach (V u in GetAdjList(v)) {
  117.                     if ((u.Flags & XslFlags.Stop) == 0) {
  118.                         DepthFirstSearch(u, flag);
  119.                     }
  120.                     Debug.Assert((u.Flags & flag) == flag, "Flag was not set on an adjacent vertex");
  121.                 }
  122.             }
  123.         }
  124.        
  125.         internal struct ModeName
  126.         {
  127.             public QilName Mode;
  128.             public QilName Name;
  129.            
  130.             public ModeName(QilName mode, QilName name)
  131.             {
  132.                 this.Mode = mode;
  133.                 this.Name = name;
  134.             }
  135.            
  136.             public override int GetHashCode()
  137.             {
  138.                 return Mode.GetHashCode() ^ Name.GetHashCode();
  139.             }
  140.         }
  141.        
  142.         public XslFlags Analyze(Compiler compiler)
  143.         {
  144.             this.compiler = compiler;
  145.             this.scope = new CompilerScopeManager<VarPar>();
  146.             this.xpathAnalyzer = new XPathAnalyzer(compiler, scope);
  147.            
  148.             // Add global parameters and variables to the scope, they are visible everywhere
  149.             foreach (VarPar par in compiler.ExternalPars) {
  150.                 scope.AddVariable(par.Name, par);
  151.             }
  152.             foreach (VarPar var in compiler.GlobalVars) {
  153.                 scope.AddVariable(var.Name, var);
  154.             }
  155.            
  156.             // Visit global parameters and variables, but ignore calculated flags
  157.             foreach (VarPar par in compiler.ExternalPars) {
  158.                 Visit(par);
  159.                 par.Flags |= XslFlags.AnyType;
  160.             }
  161.             foreach (VarPar var in compiler.GlobalVars) {
  162.                 Visit(var);
  163.             }
  164.            
  165.             // Global "naked" current/position/last flags
  166.             XslFlags result = XslFlags.None;
  167.            
  168.             // Visit templates and attribute sets
  169.             foreach (ProtoTemplate tmpl in compiler.AllTemplates) {
  170.                 currentTemplate = tmpl;
  171.                 result |= Visit(tmpl);
  172.             }
  173.            
  174.             // At this point for every local parameter we know whether its default value could be used
  175.             // by one of the callers of its template. Update flags for local parameters accordingly.
  176.             foreach (ProtoTemplate tmpl in compiler.AllTemplates) {
  177.                 foreach (XslNode instr in tmpl.Content) {
  178.                     // Take care of a bizarre case <xsl:template match="/" xml:space="preserve"> <xsl:param name="par"/>
  179.                     if (instr.NodeType == XslNodeType.Text) {
  180.                         continue;
  181.                     }
  182.                     if (instr.NodeType != XslNodeType.Param) {
  183.                         break;
  184.                     }
  185.                    
  186.                     VarPar par = (VarPar)instr;
  187.                     if ((par.Flags & XslFlags.MayBeDefault) != 0) {
  188.                         par.Flags |= par.DefValueFlags;
  189.                     }
  190.                 }
  191.             }
  192.            
  193.             // Infer XPath types for all variables and local parameters by propagating literal
  194.             // types Rtf, Nodeset, Node, Boolean, Number, String through the data flow graph.
  195.             for (int flag = (int)XslFlags.Rtf; flag != 0; flag >>= 1) {
  196.                 dataFlow.PropagateFlag((XslFlags)flag);
  197.             }
  198.             dataFlow = null;
  199.            
  200.             // We need to follow focusDonors graph to propagate focus flags. But first complete
  201.             // dependency graph with dependsOnApplyImports
  202.             foreach (KeyValuePair<Template, Stylesheet> pair in dependsOnApplyImports) {
  203.                 // This is is the precise way to calculated dependencies
  204.                 //foreach (Stylesheet import in pair.Value.Imports) {
  205.                 // AddImportDependencies(import, /*focusDonor:*/pair.Key);
  206.                 //}
  207.                 // For now we assume that xsl:apply-imports needs position()/last()
  208.                 // if at least one template for this mode needs position()/last()
  209.                 // so if compiler.ModeFlags[pair.Key.Mode] has flag XslFlags.Position/Last set
  210.                     /*focusDonor:*/                AddImportDependencies(compiler.PrincipalStylesheet, pair.Key);
  211.             }
  212.             dependsOnApplyImports = null;
  213.             // Finaly done with this.
  214.             if ((result & XslFlags.Current) != 0) {
  215.                 focusDonors.PropagateFlag(XslFlags.Current);
  216.             }
  217.             if ((result & XslFlags.Position) != 0) {
  218.                 focusDonors.PropagateFlag(XslFlags.Position);
  219.             }
  220.             if ((result & XslFlags.Last) != 0) {
  221.                 focusDonors.PropagateFlag(XslFlags.Last);
  222.             }
  223.             if ((result & XslFlags.SideEffects) != 0) {
  224.                 PropagateSideEffectsFlag();
  225.             }
  226.             focusDonors = null;
  227.             sideEffectDonors = null;
  228.             dependsOnMode = null;
  229.            
  230.             // We can do this only after all flags were propagated.
  231.             // Otherwise we can miss case when flag comes to template from attribute-set
  232.             FillModeFlags(compiler.PrincipalStylesheet);
  233.            
  234.             TraceResults();
  235.             return result;
  236.         }
  237.        
  238.         private void AddImportDependencies(Stylesheet sheet, Template focusDonor)
  239.         {
  240.             foreach (Template tmpl in sheet.Templates) {
  241.                 if (tmpl.Mode.Equals(focusDonor.Mode)) {
  242.                     focusDonors.AddEdge(tmpl, focusDonor);
  243.                 }
  244.             }
  245.             foreach (Stylesheet import in sheet.Imports) {
  246.                 AddImportDependencies(import, focusDonor);
  247.             }
  248.         }
  249.        
  250.         private void FillModeFlags(Stylesheet sheet)
  251.         {
  252.             foreach (Template tmpl in sheet.Templates) {
  253.                 Debug.Assert(tmpl.Match != null);
  254.                 XslFlags templateFlags = tmpl.Flags & XslFlags.FocusFilter;
  255.                 if (templateFlags != 0) {
  256.                     XslFlags modeFlags;
  257.                     if (!compiler.ModeFlags.TryGetValue(tmpl.Mode, out modeFlags)) {
  258.                         modeFlags = 0;
  259.                     }
  260.                     compiler.ModeFlags[tmpl.Mode] = modeFlags | templateFlags;
  261.                 }
  262.             }
  263.             foreach (Stylesheet import in sheet.Imports) {
  264.                 FillModeFlags(import);
  265.             }
  266.         }
  267.        
  268.         private void TraceResults()
  269.         {
  270.             #if DEBUG
  271.             if (DiagnosticsSwitches.XslTypeInference.TraceVerbose) {
  272.                 Debug.WriteLine(string.Empty);
  273.                 foreach (ProtoTemplate tmpl in compiler.AllTemplates) {
  274.                     Debug.WriteLine(tmpl.TraceName + " = " + (tmpl.Flags & XslFlags.FocusFilter));
  275.                 }
  276.                
  277.                 Debug.WriteLine(string.Empty);
  278.                 foreach (VarPar varPar in allVarPars) {
  279.                     Debug.WriteLine(varPar.TraceName + " = " + (varPar.Flags & XslFlags.TypeFilter));
  280.                 }
  281.                 Debug.WriteLine(string.Empty);
  282.             }
  283.            
  284.             if (DiagnosticsSwitches.XslTypeInference.TraceInfo) {
  285.                 int current = 0;
  286.                 int position = 0;
  287.                 int last = 0;
  288.                
  289.                 foreach (ProtoTemplate tmpl in compiler.AllTemplates) {
  290.                     if ((tmpl.Flags & XslFlags.Current) != 0) {
  291.                         current++;
  292.                     }
  293.                     if ((tmpl.Flags & XslFlags.Position) != 0) {
  294.                         position++;
  295.                     }
  296.                     if ((tmpl.Flags & XslFlags.Last) != 0) {
  297.                         last++;
  298.                     }
  299.                 }
  300.                
  301.                 int stringType = 0;
  302.                 int numberType = 0;
  303.                 int booleanType = 0;
  304.                 int nodeNotRtfType = 0;
  305.                 int nodesetNotRtfType = 0;
  306.                 int nodeType = 0;
  307.                 int nodesetType = 0;
  308.                 int noneType = 0;
  309.                 int anyType = 0;
  310.                 int totalVarPars = 0;
  311.                
  312.                 foreach (VarPar varPar in allVarPars) {
  313.                     switch (varPar.Flags & XslFlags.TypeFilter) {
  314.                         case XslFlags.String:
  315.                             stringType++;
  316.                             break;
  317.                         case XslFlags.Number:
  318.                             numberType++;
  319.                             break;
  320.                         case XslFlags.Boolean:
  321.                             booleanType++;
  322.                             break;
  323.                         case XslFlags.Node:
  324.                             nodeNotRtfType++;
  325.                             break;
  326.                         case XslFlags.Nodeset:
  327.                             nodesetNotRtfType++;
  328.                             break;
  329.                         case XslFlags.Rtf:
  330.                             nodeType++;
  331.                             break;
  332.                         case XslFlags.Node | XslFlags.Rtf:
  333.                             nodeType++;
  334.                             break;
  335.                         case XslFlags.Node | XslFlags.Nodeset:
  336.                             nodesetNotRtfType++;
  337.                             break;
  338.                         case XslFlags.Nodeset | XslFlags.Rtf:
  339.                             nodesetType++;
  340.                             break;
  341.                         case XslFlags.Node | XslFlags.Nodeset | XslFlags.Rtf:
  342.                             nodesetType++;
  343.                             break;
  344.                         case XslFlags.None:
  345.                             noneType++;
  346.                             break;
  347.                         default:
  348.                             anyType++;
  349.                             break;
  350.                     }
  351.                     totalVarPars++;
  352.                 }
  353.                
  354.                 Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Total => templates/attribute-sets: {0}, variables/parameters: {1}.", compiler.AllTemplates.Count, totalVarPars));
  355.                
  356.                 Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Inferred focus => current: {0}, position: {1}, last: {2}.", current, position, last));
  357.                
  358.                 Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Inferred types => string: {0}, number: {1}, boolean: {2}, node: {3}, node-set: {4}, " + "node-or-rtf: {5}, node-set-or-rtf: {6}, none: {7}, any: {8}.", stringType, numberType, booleanType, nodeNotRtfType, nodesetNotRtfType, nodeType, nodesetType, noneType,
  359.                 anyType));
  360.             }
  361.             #endif
  362.         }
  363.        
  364.         protected override XslFlags Visit(XslNode node)
  365.         {
  366.             // Enter scope
  367.             scope.PushScope();
  368.             NsDecl nsDecl = node.Namespaces;
  369.             while (nsDecl != null) {
  370.                 Debug.Assert(nsDecl.NsUri != null);
  371.                 scope.AddNamespace(nsDecl.Prefix, nsDecl.NsUri);
  372.                 nsDecl = nsDecl.Prev;
  373.             }
  374.            
  375.             XslFlags result = base.Visit(node);
  376.            
  377.             // Exit scope
  378.             scope.PopScope();
  379.            
  380.             // Local variables and parameters must be added to the outer scope
  381.             if (currentTemplate != null && (node.NodeType == XslNodeType.Variable || node.NodeType == XslNodeType.Param)) {
  382.                 scope.AddVariable(node.Name, (VarPar)node);
  383.             }
  384.             Debug.Assert((result & XslFlags.TypeFilter & ~XslFlags.Rtf) == 0, "Instructions always return Rtf. node=" + node.NodeType.ToString() + " result=" + result.ToString());
  385.             return result;
  386.         }
  387.        
  388.         protected override XslFlags VisitChildren(XslNode node)
  389.         {
  390.             XslFlags result = XslFlags.None;
  391.             foreach (XslNode child in node.Content) {
  392.                 result |= this.Visit(child);
  393.             }
  394.             return result;
  395.         }
  396.        
  397.         protected override XslFlags VisitAttributeSet(AttributeSet node)
  398.         {
  399.             // @use-attribute-sets was processed into a sequence of UseAttributeSet nodes,
  400.             // which were prepended to the content of node
  401.             node.Flags = VisitChildren(node);
  402.             return node.Flags;
  403.         }
  404.        
  405.         protected override XslFlags VisitTemplate(Template node)
  406.         {
  407.             // @match does not affect any flags
  408.             //ProcessPattern(match);
  409.             node.Flags = VisitChildren(node);
  410.             return node.Flags;
  411.         }
  412.        
  413.         protected override XslFlags VisitApplyImports(XslNode node)
  414.         {
  415.             Debug.Assert(this.forEachDepth == 0, "xsl:apply-imports cannot be inside of xsl:for-each");
  416.             Debug.Assert(currentTemplate is Template, "xsl:apply-imports can only occur within xsl:template");
  417.             dependsOnApplyImports[(Template)currentTemplate] = (Stylesheet)node.Arg;
  418.             // xsl:apply-imports uses context node and is not in context of any for-each so it requires current
  419.             return XslFlags.HasCalls | XslFlags.Current | XslFlags.Rtf;
  420.         }
  421.        
  422.         protected override XslFlags VisitApplyTemplates(XslNode node)
  423.         {
  424.             Debug.Assert(node.Select != null, "Absent @select should be replaced with 'node()' in XsltLoader");
  425.             XslFlags result = ProcessExpr(node.Select);
  426.            
  427.             foreach (XslNode instr in node.Content) {
  428.                 result |= Visit(instr);
  429.                 if (instr.NodeType == XslNodeType.WithParam) {
  430.                         /*mode:*/                    ModeName mn = new ModeName(node.Name, instr.Name);
  431.                     VarPar modePar;
  432.                    
  433.                     if (!applyTemplatesParams.TryGetValue(mn, out modePar)) {
  434.                         modePar = applyTemplatesParams[mn] = AstFactory.WithParam(instr.Name);
  435.                     }
  436.                    
  437.                     Debug.Assert(typeDonor != null ^ instr.Flags != XslFlags.None);
  438.                    
  439.                     if (typeDonor != null) {
  440.                         dataFlow.AddEdge(typeDonor, modePar);
  441.                     }
  442.                     else {
  443.                         modePar.Flags |= instr.Flags & XslFlags.TypeFilter;
  444.                     }
  445.                 }
  446.             }
  447.            
  448.             if (currentTemplate != null) {
  449.                     /*mode:*/                AddApplyTemplatesEdge(node.Name, currentTemplate);
  450.             }
  451.            
  452.             return XslFlags.HasCalls | XslFlags.Rtf | result;
  453.         }
  454.        
  455.         protected override XslFlags VisitAttribute(NodeCtor node)
  456.         {
  457.             return (XslFlags.Rtf | ProcessAvt(node.NameAvt) | ProcessAvt(node.NsAvt) | VisitChildren(node));
  458.         }
  459.        
  460.         protected override XslFlags VisitCallTemplate(XslNode node)
  461.         {
  462.             XslFlags result = XslFlags.None;
  463.             Template target;
  464.            
  465.             if (!compiler.NamedTemplates.TryGetValue(node.Name, out target)) {
  466.                 Debug.WriteLineIf(DiagnosticsSwitches.XslTypeInference.TraceError, "Unknown template " + node.Name.QualifiedName, "Error");
  467.             }
  468.             else {
  469.                 Debug.Assert(target != null);
  470.                 if (currentTemplate != null) {
  471.                     if (this.forEachDepth == 0) {
  472.                         // Naked xsl:call-template, target would take its focus from currentTemplate
  473.                         focusDonors.AddEdge(target, currentTemplate);
  474.                     }
  475.                     else {
  476.                         // in other cases we need it as donor for side effects flag
  477.                         sideEffectDonors.AddEdge(target, currentTemplate);
  478.                     }
  479.                 }
  480.             }
  481.            
  482.             VarPar[] typeDonors = new VarPar[node.Content.Count];
  483.             int idx = 0;
  484.            
  485.             foreach (XslNode instr in node.Content) {
  486.                 Debug.Assert(instr.NodeType == XslNodeType.WithParam);
  487.                 result |= Visit(instr);
  488.                 Debug.Assert(typeDonor != null ^ instr.Flags != XslFlags.None);
  489.                 typeDonors[idx++] = typeDonor;
  490.             }
  491.            
  492.             // For each xsl:param in the target template find the corresponding xsl:with-param, and:
  493.             // a) if the type of xsl:with-param is known, add it to the type of xsl:param;
  494.             // b) if value of xsl:with-param is a VarPar reference, add an edge connecting it with xsl:param
  495.             // to the data flow graph.
  496.            
  497.             if (target != null) {
  498.                 foreach (XslNode instr in target.Content) {
  499.                     // Take care of a bizarre case <xsl:template match="/" xml:space="preserve"> <xsl:param name="par"/>
  500.                     if (instr.NodeType == XslNodeType.Text) {
  501.                         continue;
  502.                     }
  503.                     if (instr.NodeType != XslNodeType.Param) {
  504.                         break;
  505.                     }
  506.                    
  507.                     VarPar par = (VarPar)instr;
  508.                     VarPar found = null;
  509.                     idx = 0;
  510.                    
  511.                     foreach (XslNode withPar in node.Content) {
  512.                         if (withPar.Name.Equals(par.Name)) {
  513.                             found = (VarPar)withPar;
  514.                             typeDonor = typeDonors[idx];
  515.                             break;
  516.                         }
  517.                         idx++;
  518.                     }
  519.                    
  520.                     if (found != null) {
  521.                         // Found corresponding xsl:with-param, check its type
  522.                         if (typeDonor != null) {
  523.                             // add an edge from its type donor to xsl:param
  524.                             dataFlow.AddEdge(typeDonor, par);
  525.                         }
  526.                         else {
  527.                             par.Flags |= found.Flags & XslFlags.TypeFilter;
  528.                         }
  529.                     }
  530.                     else {
  531.                         // No value was specified for this xsl:param, default value will be used for it
  532.                         par.Flags |= XslFlags.MayBeDefault;
  533.                     }
  534.                 }
  535.             }
  536.            
  537.             return XslFlags.HasCalls | XslFlags.Rtf | result;
  538.         }
  539.        
  540.         //protected override XslFlags VisitChoose(XslNode node) { return VisitChildren(node); }
  541.        
  542.         protected override XslFlags VisitComment(XslNode node)
  543.         {
  544.             return XslFlags.Rtf | VisitChildren(node);
  545.         }
  546.        
  547.         protected override XslFlags VisitCopy(XslNode node)
  548.         {
  549.             // @use-attribute-sets was processed into a sequence of UseAttributeSet nodes,
  550.             // which were prepended to the content of node
  551.             return XslFlags.Current | XslFlags.Rtf | VisitChildren(node);
  552.         }
  553.        
  554.         protected override XslFlags VisitCopyOf(XslNode node)
  555.         {
  556.             return XslFlags.Rtf | ProcessExpr(node.Select);
  557.         }
  558.        
  559.         protected override XslFlags VisitElement(NodeCtor node)
  560.         {
  561.             // @use-attribute-sets was processed into a sequence of UseAttributeSet nodes,
  562.             // which were prepended to the content of node
  563.             return (XslFlags.Rtf | ProcessAvt(node.NameAvt) | ProcessAvt(node.NsAvt) | VisitChildren(node));
  564.         }
  565.        
  566.         protected override XslFlags VisitError(XslNode node)
  567.         {
  568.             return (VisitChildren(node) & ~XslFlags.TypeFilter) | XslFlags.SideEffects;
  569.         }
  570.        
  571.         protected override XslFlags VisitForEach(XslNode node)
  572.         {
  573.             XslFlags result = ProcessExpr(node.Select);
  574.             this.forEachDepth++;
  575.             foreach (XslNode child in node.Content) {
  576.                 if (child.NodeType == XslNodeType.Sort) {
  577.                     result |= Visit(child);
  578.                 }
  579.                 else {
  580.                     // Since for-each creates new focus, the focus flags of its children does not contribute into result
  581.                     result |= Visit(child) & ~XslFlags.FocusFilter;
  582.                 }
  583.             }
  584.             this.forEachDepth--;
  585.             return result;
  586.         }
  587.        
  588.         protected override XslFlags VisitIf(XslNode node)
  589.         {
  590.             return ProcessExpr(node.Select) | VisitChildren(node);
  591.         }
  592.        
  593. /*
  594.         protected override XslFlags VisitKey(Key node) {
  595.             // @match and @use do not affect any flags
  596.             //ProcessPattern(node.Match);
  597.             //ProcessExpr(node.Use);
  598.         }
  599.         */       
  600.        
  601.         //protected override XslFlags VisitList(XslNode node) { return VisitChildren(node); }
  602.        
  603.         protected override XslFlags VisitLiteralAttribute(XslNode node)
  604.         {
  605.             return (XslFlags.Rtf | ProcessAvt(node.Select) | VisitChildren(node));
  606.         }
  607.        
  608.         protected override XslFlags VisitLiteralElement(XslNode node)
  609.         {
  610.             return XslFlags.Rtf | VisitChildren(node);
  611.         }
  612.        
  613.         protected override XslFlags VisitMessage(XslNode node)
  614.         {
  615.             return (VisitChildren(node) & ~XslFlags.TypeFilter) | XslFlags.SideEffects;
  616.         }
  617.        
  618.         //protected override XslFlags VisitNop(XslNode node) { return VisitChildren(node); }
  619.        
  620.         protected override XslFlags VisitNumber(Number node)
  621.         {
  622.             return (XslFlags.Rtf | ProcessPattern(node.Count) | ProcessPattern(node.From) | (node.Value != null ? ProcessExpr(node.Value) : XslFlags.Current) | ProcessAvt(node.Format) | ProcessAvt(node.Lang) | ProcessAvt(node.LetterValue) | ProcessAvt(node.GroupingSeparator) | ProcessAvt(node.GroupingSize));
  623.         }
  624.        
  625.         //protected override XslFlags VisitOtherwise(XslNode node) { return VisitChildren(node); }
  626.        
  627.         protected override XslFlags VisitPI(XslNode node)
  628.         {
  629.             return (XslFlags.Rtf | ProcessAvt(node.Select) | VisitChildren(node));
  630.         }
  631.        
  632.         protected override XslFlags VisitSort(Sort node)
  633.         {
  634.                 // @select is calculated in context of xsl:for-each or xsl:apply-templates,
  635.                 // so it does not affect focus flags
  636.             return (ProcessExpr(node.Select) & ~XslFlags.FocusFilter | ProcessAvt(node.Lang) | ProcessAvt(node.DataType) | ProcessAvt(node.Order) | ProcessAvt(node.CaseOrder));
  637.         }
  638.        
  639.         protected override XslFlags VisitText(Text node)
  640.         {
  641.             return XslFlags.Rtf | VisitChildren(node);
  642.         }
  643.        
  644.         protected override XslFlags VisitUseAttributeSet(XslNode node)
  645.         {
  646.             AttributeSet attSet;
  647.             if (!compiler.AttributeSets.TryGetValue(node.Name, out attSet)) {
  648.                 Debug.WriteLineIf(DiagnosticsSwitches.XslTypeInference.TraceError, "Unknown attribute-set " + node.Name.QualifiedName, "Error");
  649.             }
  650.             else if (currentTemplate != null) {
  651.                 if (this.forEachDepth == 0) {
  652.                     // Naked [xsl:]use-attribute-sets, attSet would take its focus from currentTemplate
  653.                     focusDonors.AddEdge(attSet, currentTemplate);
  654.                 }
  655.                 else {
  656.                     // in other cases we need it as donor for side effects flag
  657.                     sideEffectDonors.AddEdge(attSet, currentTemplate);
  658.                 }
  659.             }
  660.             return XslFlags.HasCalls | XslFlags.Rtf;
  661.         }
  662.        
  663.         protected override XslFlags VisitValueOf(XslNode node)
  664.         {
  665.             return XslFlags.Rtf | ProcessExpr(node.Select);
  666.         }
  667.        
  668.         protected override XslFlags VisitValueOfDoe(XslNode node)
  669.         {
  670.             return XslFlags.Rtf | ProcessExpr(node.Select);
  671.         }
  672.        
  673.         protected override XslFlags VisitParam(VarPar node)
  674.         {
  675.             Template tmpl = currentTemplate as Template;
  676.             if (tmpl != null && tmpl.Match != null) {
  677.                 // This template has 'match' attribute and might be called from built-in template rules,
  678.                 // all xsl:param's will be defaulted in that case
  679.                 node.Flags |= XslFlags.MayBeDefault;
  680.                
  681.                 ModeName mn = new ModeName(tmpl.Mode, node.Name);
  682.                 VarPar par;
  683.                
  684.                 if (!applyTemplatesParams.TryGetValue(mn, out par)) {
  685.                     par = applyTemplatesParams[mn] = AstFactory.WithParam(node.Name);
  686.                 }
  687.                 dataFlow.AddEdge(par, node);
  688.             }
  689.             node.DefValueFlags = ProcessVarPar(node);
  690.             return node.DefValueFlags & ~XslFlags.TypeFilter;
  691.         }
  692.        
  693.         protected override XslFlags VisitVariable(VarPar node)
  694.         {
  695.             node.Flags = ProcessVarPar(node);
  696.             return node.Flags & ~XslFlags.TypeFilter;
  697.         }
  698.        
  699.         protected override XslFlags VisitWithParam(VarPar node)
  700.         {
  701.             node.Flags = ProcessVarPar(node);
  702.             return node.Flags & ~XslFlags.TypeFilter;
  703.         }
  704.        
  705.         private XslFlags ProcessVarPar(VarPar node)
  706.         {
  707.             XslFlags result;
  708.             #if DEBUG
  709.             if (node.NodeType != XslNodeType.WithParam) {
  710.                 allVarPars.Add(node);
  711.             }
  712.             #endif
  713.            
  714.             if (node.Select != null) {
  715.                 if (node.Content.Count != 0) {
  716.                     // In case of incorrect stylesheet, variable or parameter may have both a 'select' attribute and non-empty content
  717.                     // NOTE: This code must be in sync with recovery logic in QilGenerator
  718.                     result = xpathAnalyzer.Analyze(node.Select) | VisitChildren(node) | XslFlags.AnyType;
  719.                     typeDonor = null;
  720.                 }
  721.                 else {
  722.                     result = xpathAnalyzer.Analyze(node.Select);
  723.                     typeDonor = xpathAnalyzer.TypeDonor;
  724.                     Debug.Assert(typeDonor != null ^ result != XslFlags.None);
  725.                     if (typeDonor != null && node.NodeType != XslNodeType.WithParam) {
  726.                         dataFlow.AddEdge(typeDonor, node);
  727.                     }
  728.                 }
  729.             }
  730.             else if (node.Content.Count != 0) {
  731.                 result = XslFlags.Rtf | VisitChildren(node);
  732.                 typeDonor = null;
  733.             }
  734.             else {
  735.                 result = XslFlags.String;
  736.                 typeDonor = null;
  737.             }
  738.             Debug.Assert(typeDonor != null ^ result != XslFlags.None);
  739.             return result;
  740.         }
  741.        
  742.         // Ignores XPath type flags
  743.         private XslFlags ProcessExpr(string expr)
  744.         {
  745.             return xpathAnalyzer.Analyze(expr) & ~XslFlags.TypeFilter;
  746.         }
  747.        
  748.         // Ignores XPath type flags
  749.         private XslFlags ProcessAvt(string avt)
  750.         {
  751.             return xpathAnalyzer.AnalyzeAvt(avt) & ~XslFlags.TypeFilter;
  752.         }
  753.        
  754.         // Ignores XPath type flags and focus flags
  755.         private XslFlags ProcessPattern(string pattern)
  756.         {
  757.             // We need to analyze using of variables in the pattern
  758.             return xpathAnalyzer.Analyze(pattern) & ~XslFlags.TypeFilter & ~XslFlags.FocusFilter;
  759.         }
  760.        
  761.         private void AddApplyTemplatesEdge(QilName mode, ProtoTemplate dependentTemplate)
  762.         {
  763.             List<ProtoTemplate> templates;
  764.             if (!dependsOnMode.TryGetValue(mode, out templates)) {
  765.                 templates = new List<ProtoTemplate>();
  766.                 dependsOnMode.Add(mode, templates);
  767.             }
  768.             else {
  769.                 if (templates[templates.Count - 1] == dependentTemplate) {
  770.                     return;
  771.                     // this is a duplicate
  772.                 }
  773.             }
  774.            
  775.             templates.Add(dependentTemplate);
  776.         }
  777.        
  778.         private void PropagateSideEffectsFlag()
  779.         {
  780.             // Clean Stop flags
  781.             foreach (ProtoTemplate t in focusDonors.Keys) {
  782.                 t.Flags &= ~XslFlags.Stop;
  783.             }
  784.             foreach (ProtoTemplate t in sideEffectDonors.Keys) {
  785.                 t.Flags &= ~XslFlags.Stop;
  786.             }
  787.            
  788.             foreach (ProtoTemplate t in focusDonors.Keys) {
  789.                 if ((t.Flags & XslFlags.Stop) == 0) {
  790.                     if ((t.Flags & XslFlags.SideEffects) != 0) {
  791.                         DepthFirstSearch(t);
  792.                     }
  793.                 }
  794.             }
  795.             foreach (ProtoTemplate t in sideEffectDonors.Keys) {
  796.                 if ((t.Flags & XslFlags.Stop) == 0) {
  797.                     if ((t.Flags & XslFlags.SideEffects) != 0) {
  798.                         DepthFirstSearch(t);
  799.                     }
  800.                 }
  801.             }
  802.         }
  803.        
  804.         private void DepthFirstSearch(ProtoTemplate t)
  805.         {
  806.             Debug.Assert((t.Flags & XslFlags.Stop) == 0, "Already visited this vertex");
  807.             t.Flags |= (XslFlags.SideEffects | XslFlags.Stop);
  808.             List<ProtoTemplate> list;
  809.             foreach (ProtoTemplate u in focusDonors.GetAdjList(t)) {
  810.                 if ((u.Flags & XslFlags.Stop) == 0) {
  811.                     DepthFirstSearch(u);
  812.                 }
  813.                 Debug.Assert((u.Flags & XslFlags.SideEffects) == XslFlags.SideEffects, "Flag was not set on an adjacent vertex");
  814.             }
  815.             foreach (ProtoTemplate u in sideEffectDonors.GetAdjList(t)) {
  816.                 if ((u.Flags & XslFlags.Stop) == 0) {
  817.                     DepthFirstSearch(u);
  818.                 }
  819.                 Debug.Assert((u.Flags & XslFlags.SideEffects) == XslFlags.SideEffects, "Flag was not set on an adjacent vertex");
  820.             }
  821.             Template template = t as Template;
  822.             // This ProteTemplate is Template
  823.             // list - ProtoTemplates that have apply-templatess mode="{template.Mode}"
  824.             if (template != null && dependsOnMode.TryGetValue(template.Mode, out list)) {
  825.                 dependsOnMode.Remove(template.Mode);
  826.                 // to prevent recursion remove this list from dictionary
  827.                 foreach (ProtoTemplate u in list) {
  828.                     if ((u.Flags & XslFlags.Stop) == 0) {
  829.                         DepthFirstSearch(u);
  830.                     }
  831.                     Debug.Assert((u.Flags & XslFlags.SideEffects) == XslFlags.SideEffects, "Flag was not set on an adjacent vertex");
  832.                 }
  833.             }
  834.         }
  835.        
  836.         // ------------------------------- XPathAnalyzer --------------------------------
  837.        
  838.         // Ignores all errors and warnings
  839.         internal struct NullErrorHelper : IErrorHelper
  840.         {
  841.             public void ReportError(string res, params string[] args)
  842.             {
  843.             }
  844.             public void ReportWarning(string res, params string[] args)
  845.             {
  846.             }
  847.         }
  848.        
  849.         internal class XPathAnalyzer : IXPathBuilder<XslFlags>
  850.         {
  851.             private XPathParser<XslFlags> xpathParser = new XPathParser<XslFlags>();
  852.             private CompilerScopeManager<VarPar> scope;
  853.             private Compiler compiler;
  854.            
  855.             // True if the expression needs XSLT's current() node
  856.             private bool xsltCurrentNeeded;
  857.            
  858.             // If the expression is just a reference to some VarPar, like "(($foo))",
  859.             // then this field contains that VarPar, and null otherwise.
  860.             private VarPar typeDonor;
  861.            
  862.             public VarPar TypeDonor {
  863.                 get { return typeDonor; }
  864.             }
  865.            
  866.             public XPathAnalyzer(Compiler compiler, CompilerScopeManager<VarPar> scope)
  867.             {
  868.                 this.compiler = compiler;
  869.                 this.scope = scope;
  870.             }
  871.            
  872.             // Post-condition: typeDonor != null ^ result != XslFlags.None
  873.             public XslFlags Analyze(string xpathExpr)
  874.             {
  875.                 typeDonor = null;
  876.                 if (xpathExpr == null) {
  877.                     return XslFlags.None;
  878.                 }
  879.                 try {
  880.                     // Note that the constructor may throw an exception, for example, in case of the expression "'"
  881.                     xsltCurrentNeeded = false;
  882.                     XPathScanner scanner = new XPathScanner(xpathExpr);
  883.                     XslFlags result = xpathParser.Parse(scanner, this, LexKind.Eof);
  884.                     if (xsltCurrentNeeded) {
  885.                         result |= XslFlags.Current;
  886.                     }
  887.                     return result;
  888.                 }
  889.                 catch (XslLoadException) {
  890.                     return XslFlags.AnyType | XslFlags.FullFocus;
  891.                 }
  892.             }
  893.            
  894.             public XslFlags AnalyzeAvt(string source)
  895.             {
  896.                 typeDonor = null;
  897.                 if (source == null) {
  898.                     return XslFlags.None;
  899.                 }
  900.                 try {
  901.                     xsltCurrentNeeded = false;
  902.                     XslFlags result = XslFlags.None;
  903.                     int pos = 0;
  904.                     while (pos < source.Length) {
  905.                         pos = source.IndexOf('{', pos);
  906.                         if (pos == -1) {
  907.                             break;
  908.                             // no more AVTs
  909.                         }
  910.                         pos++;
  911.                         if (pos < source.Length && source[pos] == '{') {
  912.                             // "{{"
  913.                             pos++;
  914.                             continue;
  915.                         }
  916.                         if (pos < source.Length) {
  917.                             // '{' encountered, parse an expression
  918.                             XPathScanner scanner = new XPathScanner(source, pos);
  919.                             result |= xpathParser.Parse(scanner, this, LexKind.RBrace);
  920.                             pos = scanner.LexStart + 1;
  921.                         }
  922.                     }
  923.                     if (xsltCurrentNeeded) {
  924.                         result |= XslFlags.Current;
  925.                     }
  926.                     return result & ~XslFlags.TypeFilter;
  927.                 }
  928.                 catch (XslLoadException) {
  929.                     return XslFlags.FullFocus;
  930.                 }
  931.             }
  932.            
  933.             // Returns null in case of error
  934.             private VarPar ResolveVariable(string prefix, string name)
  935.             {
  936.                 string ns = ResolvePrefix(prefix);
  937.                 if (ns == null) {
  938.                     return null;
  939.                 }
  940.                 return scope.LookupVariable(name, ns);
  941.             }
  942.            
  943.             // Returns null in case of error
  944.             private string ResolvePrefix(string prefix)
  945.             {
  946.                 // ignoreDefaultNs == true
  947.                 if (prefix.Length == 0) {
  948.                     return string.Empty;
  949.                 }
  950.                 else {
  951.                     return scope.LookupNamespace(prefix);
  952.                 }
  953.             }
  954.            
  955.             public virtual void StartBuild()
  956.             {
  957.             }
  958.            
  959.             public virtual XslFlags EndBuild(XslFlags result)
  960.             {
  961.                 return result;
  962.             }
  963.            
  964.             public virtual XslFlags String(string value)
  965.             {
  966.                 typeDonor = null;
  967.                 return XslFlags.String;
  968.             }
  969.            
  970.             public virtual XslFlags Number(double value)
  971.             {
  972.                 typeDonor = null;
  973.                 return XslFlags.Number;
  974.             }
  975.            
  976.             private static XslFlags[] OperatorType = {XslFlags.AnyType, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Boolean, XslFlags.Number,
  977.                 /*Unknown  */                /*Or        */                /*And      */                /*Eq        */                /*Ne        */                /*Lt        */                /*Le        */                /*Gt        */                /*Ge        */                /*Plus      */                /*Minus    */                /*Multiply  */                /*Divide    */                /*Modulo    */                /*UnaryMinus*/                /*Union    */            XslFlags.Number, XslFlags.Number, XslFlags.Number, XslFlags.Number, XslFlags.Number, XslFlags.Nodeset};
  978.            
  979.             public virtual XslFlags Operator(XPathOperator op, XslFlags left, XslFlags right)
  980.             {
  981.                 typeDonor = null;
  982.                 Debug.Assert(op != XPathOperator.Unknown);
  983.                 XslFlags result = (left | right) & ~XslFlags.TypeFilter;
  984.                 return result | OperatorType[(int)op];
  985.             }
  986.            
  987.             public virtual XslFlags Axis(XPathAxis xpathAxis, XPathNodeType nodeType, string prefix, string name)
  988.             {
  989.                 typeDonor = null;
  990.                 if (xpathAxis == XPathAxis.Self && nodeType == XPathNodeType.All && prefix == null && name == null) {
  991.                     return XslFlags.Current | XslFlags.Node;
  992.                 }
  993.                 else {
  994.                     return XslFlags.Current | XslFlags.Nodeset;
  995.                 }
  996.             }
  997.            
  998.             // "left/right"
  999.             public virtual XslFlags JoinStep(XslFlags left, XslFlags right)
  1000.             {
  1001.                 typeDonor = null;
  1002.                 return (left & ~XslFlags.TypeFilter) | XslFlags.Nodeset;
  1003.                 // "ex:Foo(position())/Bar"
  1004.             }
  1005.            
  1006.             // "nodeset[predicate]"
  1007.             public virtual XslFlags Predicate(XslFlags nodeset, XslFlags predicate, bool isReverseStep)
  1008.             {
  1009.                 typeDonor = null;
  1010.                 return (nodeset & ~XslFlags.TypeFilter) | XslFlags.Nodeset | (predicate & XslFlags.SideEffects);
  1011.                 // "ex:Foo(position())[Bar]"
  1012.             }
  1013.            
  1014.             public virtual XslFlags Variable(string prefix, string name)
  1015.             {
  1016.                 typeDonor = ResolveVariable(prefix, name);
  1017.                 if (typeDonor == null) {
  1018.                     Debug.WriteLineIf(DiagnosticsSwitches.XslTypeInference.TraceError, "Unresolved variable " + Compiler.ConstructQName(prefix, name), "Error");
  1019.                     return XslFlags.AnyType;
  1020.                 }
  1021.                 return XslFlags.None;
  1022.             }
  1023.            
  1024.             public virtual XslFlags Function(string prefix, string name, IList<XslFlags> args)
  1025.             {
  1026.                 typeDonor = null;
  1027.                
  1028.                 XslFlags argsFlags = XslFlags.None;
  1029.                 foreach (XslFlags t in args) {
  1030.                     argsFlags |= t;
  1031.                 }
  1032.                
  1033.                 XslFlags funcFlags = XslFlags.None;
  1034.                
  1035.                 if (prefix.Length == 0) {
  1036.                     XPathFunctionInfo xpathFunc;
  1037.                     XsltFunctionInfo xsltFunc;
  1038.                    
  1039.                     if (XPathBuilder.FunctionTable.TryGetValue(name, out xpathFunc)) {
  1040.                         XPathBuilder.FuncId funcId = xpathFunc.id;
  1041.                         funcFlags = XPathFunctionFlags[(int)funcId];
  1042.                         if (args.Count == 0 && (funcId == XPathBuilder.FuncId.LocalName || funcId == XPathBuilder.FuncId.NamespaceUri || funcId == XPathBuilder.FuncId.Name || funcId == XPathBuilder.FuncId.String || funcId == XPathBuilder.FuncId.Number || funcId == XPathBuilder.FuncId.StringLength || funcId == XPathBuilder.FuncId.Normalize)) {
  1043.                             funcFlags |= XslFlags.Current;
  1044.                         }
  1045.                     }
  1046.                     else if (QilGenerator.FunctionTable.TryGetValue(name, out xsltFunc)) {
  1047.                         QilGenerator.FuncId funcId = xsltFunc.id;
  1048.                         funcFlags = XsltFunctionFlags[(int)funcId];
  1049.                         if (funcId == QilGenerator.FuncId.Current) {
  1050.                             xsltCurrentNeeded = true;
  1051.                         }
  1052.                         else if (funcId == QilGenerator.FuncId.GenerateId && args.Count == 0) {
  1053.                             funcFlags |= XslFlags.Current;
  1054.                         }
  1055.                     }
  1056.                 }
  1057.                 else {
  1058.                     string ns = ResolvePrefix(prefix);
  1059.                     if (ns == XmlReservedNs.NsMsxsl) {
  1060.                         switch (name) {
  1061.                             case "node-set":
  1062.                                 funcFlags = XslFlags.Nodeset;
  1063.                                 break;
  1064.                             case "string-compare":
  1065.                                 funcFlags = XslFlags.Number;
  1066.                                 break;
  1067.                             case "utc":
  1068.                                 funcFlags = XslFlags.String;
  1069.                                 break;
  1070.                             case "format-date":
  1071.                                 funcFlags = XslFlags.String;
  1072.                                 break;
  1073.                             case "format-time":
  1074.                                 funcFlags = XslFlags.String;
  1075.                                 break;
  1076.                             case "local-name":
  1077.                                 funcFlags = XslFlags.String;
  1078.                                 break;
  1079.                             case "namespace-uri":
  1080.                                 funcFlags = XslFlags.String;
  1081.                                 break;
  1082.                             case "number":
  1083.                                 funcFlags = XslFlags.Number;
  1084.                                 break;
  1085.                         }
  1086.                     }
  1087.                     else if (ns == XmlReservedNs.NsExsltCommon) {
  1088.                         switch (name) {
  1089.                             case "node-set":
  1090.                                 funcFlags = XslFlags.Nodeset;
  1091.                                 break;
  1092.                             case "object-type":
  1093.                                 funcFlags = XslFlags.String;
  1094.                                 break;
  1095.                         }
  1096.                     }
  1097.                    
  1098.                     if (funcFlags == XslFlags.None) {
  1099.                         // Unknown function. Can be script function or extension function
  1100.                         funcFlags = XslFlags.AnyType;
  1101.                         if (compiler.Settings.EnableScript && ns != null) {
  1102.                             XmlExtensionFunction scrFunc = compiler.Scripts.ResolveFunction(name, ns, args.Count, new NullErrorHelper());
  1103.                             if (scrFunc != null) {
  1104.                                 XmlQueryType xt = scrFunc.XmlReturnType;
  1105.                                 if (xt == TypeFactory.StringX) {
  1106.                                     funcFlags = XslFlags.String;
  1107.                                 }
  1108.                                 else if (xt == TypeFactory.DoubleX) {
  1109.                                     funcFlags = XslFlags.Number;
  1110.                                 }
  1111.                                 else if (xt == TypeFactory.BooleanX) {
  1112.                                     funcFlags = XslFlags.Boolean;
  1113.                                 }
  1114.                                 else if (xt == TypeFactory.NodeNotRtf) {
  1115.                                     funcFlags = XslFlags.Node;
  1116.                                 }
  1117.                                 else if (xt == TypeFactory.NodeNotRtfS) {
  1118.                                     funcFlags = XslFlags.Nodeset;
  1119.                                 }
  1120.                                 else if (xt == TypeFactory.ItemS) {
  1121.                                     funcFlags = XslFlags.AnyType;
  1122.                                 }
  1123.                                 else if (xt == TypeFactory.Empty) {
  1124.                                     funcFlags = XslFlags.Nodeset;
  1125.                                 }
  1126.                                 else {
  1127.                                     Debug.Fail("Unexpected XmlQueryType for script function: " + xt.ToString());
  1128.                                 }
  1129.                             }
  1130.                         }
  1131.                         funcFlags |= XslFlags.SideEffects;
  1132.                     }
  1133.                 }
  1134.                
  1135.                 return (argsFlags & ~XslFlags.TypeFilter) | funcFlags;
  1136.             }
  1137.            
  1138.             #region XPath Function Flags
  1139.             private static XslFlags[] XPathFunctionFlags = {XslFlags.Number | XslFlags.Last, XslFlags.Number | XslFlags.Position, XslFlags.Number, XslFlags.String, XslFlags.String, XslFlags.String, XslFlags.String, XslFlags.Number, XslFlags.Boolean, XslFlags.Boolean,
  1140.             XslFlags.Boolean, XslFlags.Boolean, XslFlags.Nodeset | XslFlags.Current, XslFlags.String, XslFlags.Boolean, XslFlags.Boolean, XslFlags.String, XslFlags.String, XslFlags.String, XslFlags.Number,
  1141.                 /*Last              */                /*Position          */                /*Count            */                /*LocalName        */                // | XslFlags.Current if 0 args
  1142.                 /*NamespaceUri      */                // | XslFlags.Current if 0 args
  1143.                 /*Name              */                // | XslFlags.Current if 0 args
  1144.                 /*String            */                // | XslFlags.Current if 0 args
  1145.                 /*Number            */                // | XslFlags.Current if 0 args
  1146.                 /*Boolean          */                /*True              */                /*False            */                /*Not              */                /*Id                */                /*Concat            */                /*StartsWith        */                /*Contains          */                /*SubstringBefore  */                /*SubstringAfter    */                /*Substring        */                /*StringLength      */                // | XslFlags.Current if 0 args
  1147.                 /*Normalize        */                // | XslFlags.Current if 0 args
  1148.                 /*Translate        */                /*Lang              */                /*Sum              */                /*Floor            */                /*Ceiling          */                /*Round            */            XslFlags.String, XslFlags.String, XslFlags.Boolean | XslFlags.Current, XslFlags.Number, XslFlags.Number, XslFlags.Number, XslFlags.Number};
  1149.             #endregion
  1150.            
  1151.             #region Xslt Function Flags
  1152.                 /*Current          */                // xsltCurrentNeeded = true
  1153.                 /*Document          */                /*Key              */                /*FormatNumber      */                /*UnparsedEntityUri */                // | XslFlags.Current if it is implemented
  1154.                 /*GenerateId        */                // | XslFlags.Current if 0 args
  1155.                 /*SystemProperty    */                /*ElementAvailable  */                /*FunctionAvailable */            private static XslFlags[] XsltFunctionFlags = {XslFlags.Node, XslFlags.Nodeset, XslFlags.Nodeset | XslFlags.Current, XslFlags.String, XslFlags.String, XslFlags.String, XslFlags.String | XslFlags.Number, XslFlags.Boolean, XslFlags.Boolean};
  1156.             #endregion
  1157.         }
  1158.     }
  1159. }

Developer Fusion