You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by sl...@apache.org on 2023/02/27 16:38:23 UTC

[daffodil] branch main updated: Ignore errors from path expressions that are not descendants of the distinguished root

This is an automated email from the ASF dual-hosted git repository.

slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git


The following commit(s) were added to refs/heads/main by this push:
     new 0205c16de Ignore errors from path expressions that are not descendants of the distinguished root
0205c16de is described below

commit 0205c16defe15a8a390296aff34ccc8f745f50d8
Author: Steve Lawrence <sl...@apache.org>
AuthorDate: Mon Feb 27 10:35:57 2023 -0500

    Ignore errors from path expressions that are not descendants of the distinguished root
    
    It is not uncommon for schemas to create global element, group, or types
    declarations that are not descendants of the distinguished root, and
    which contain path expressions that got up and out of the global
    declaration. This is useful in cases where a schema may want alternative
    distinguished roots, or to have global declarations that can be plugged
    in as if it were a library of schema elements.
    
    However, even if these elements are not referenced from the
    distinguished root, we may still attempt to compile them if the
    checkAllTopLevel flag is set (which is true be default), in which case
    these expressions that reach out of the global declaration can lead to
    schema definition errors that cannot be fixed.
    
    To support these kinds of schemas, this adds a flag to the
    DPathElementCompileInfo indicating which element is the distinguished
    root. If a path goes outside its local root but that root isn't the
    distinguished root, then it must be one of the above mentioned cases,
    and we can throw a PathNoContextException which ignores the error
    outputs a warning.
    
    DAFFODIL-2393
---
 .../daffodil/core/dpath/DFDLExpressionParser.scala |   2 +-
 .../apache/daffodil/core/dpath/Expression.scala    |  44 +++++++--
 .../core/runtime1/ElementBaseRuntime1Mixin.scala   |   4 +
 .../runtime1/dsom/CompiledExpression1.scala        |   1 +
 .../daffodil/runtime1/processors/RuntimeData.scala |   5 +-
 .../section23/dfdl_expressions/expressions2.tdml   |  13 +++
 .../expressions_unused_path_no_context.dfdl.xsd    | 103 ++++++++++++++++++++-
 7 files changed, 158 insertions(+), 14 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/DFDLExpressionParser.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/DFDLExpressionParser.scala
index f67d7b58c..def8e12e7 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/DFDLExpressionParser.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/DFDLExpressionParser.scala
@@ -67,7 +67,7 @@ class DFDLPathExpressionParser[T <: AnyRef](
         case e: PathExpressionNoContextError => {
           host.SDW(
             WarnID.ExpressionCompilationSkipped,
-            s"Expression compilation skipped due to path expression in unreferenced group or complex type: $expr",
+            s"Expression compilation skipped due to path expression in unreferenced element, group, or complex type: $expr",
           )
           new CompiledDPath(RuntimeAbortOp(expr))
         }
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
index b02338771..65424806a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
@@ -868,11 +868,25 @@ sealed abstract class StepExpression(val step: String, val pred: Option[Predicat
   extends Expression {
 
   def relPathErr() = {
-    val err = new RelativePathPastRootError(
-      this.schemaFileLocation,
-      "Relative path '%s' past root element.",
-      this.wholeExpressionText,
-    )
+    // This path expression cannot be compiled because we went past the root. This normally
+    // should be an SDE with a RelativePathPastRootError. However, if we don't have any element
+    // compile infos or the current root is not the distinguished root that Daffodil is
+    // compiling, it means this expression is used on a term that is not a descendent of the
+    // distinguished root. The expression might make sense if a different distinguished root were
+    // compiled and used the term, but we can't tell. But it doesn't matter since this
+    // expression will never be used because it's not a descendent of the distinguished root. So
+    // we can just throw a "no context" exception which outputs a warning and allows Daffodil to
+    // continue compilation.
+    val err =
+      if (compileInfo.elementCompileInfos.isEmpty || !rootElement.isDistinguishedRoot) {
+        new PathExpressionNoContextError()
+      } else {
+        new RelativePathPastRootError(
+          this.schemaFileLocation,
+          "Relative path '%s' past root element.",
+          this.wholeExpressionText,
+        )
+      }
     toss(err)
   }
 
@@ -1252,10 +1266,22 @@ case class NamedStep(s: String, predArg: Option[PredicateExpression])
     val res: Seq[DPathElementCompileInfo] =
       if (isFirstStep) {
         if (isAbsolutePath) {
-          // has to be the root element, but we have to make sure the name matches.
-          val re = rootElement
-          re.findRoot(stepQName, this)
-          Seq(re)
+          if (compileInfo.elementCompileInfos.isEmpty || !rootElement.isDistinguishedRoot) {
+            // If we don't have any element compile infos or the current root is not the
+            // distinguished root that Daffodil is compiling, it means this expression is used
+            // on a term that is not a descendent of the distinguished root. The expression might
+            // make sense if a different distinguished root were compiled and used the term, but
+            // we can't tell. But it doesn't matter since this expression will never be used
+            // because it's not a descendent of the distinguished root. So we can just throw a
+            // "no context" exception which outputs a warning and allows Daffodil to continue
+            // compilation.
+            throw new PathExpressionNoContextError()
+          } else {
+            // Our root is the distinguished root, so ensure that the named step exists as the
+            // root element
+            rootElement.findRoot(stepQName, this)
+          }
+          Seq(rootElement)
         } else {
           // Since we're first we start from the element, or nearest enclosing
           // for this path expression.
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala
index d22f235cd..ba7d0df96 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala
@@ -21,6 +21,7 @@ import org.apache.daffodil.core.dsom.ComplexTypeBase
 import org.apache.daffodil.core.dsom.ElementBase
 import org.apache.daffodil.core.dsom.PrefixLengthQuasiElementDecl
 import org.apache.daffodil.core.dsom.PrimitiveType
+import org.apache.daffodil.core.dsom.Root
 import org.apache.daffodil.core.dsom.SimpleTypeDefBase
 import org.apache.daffodil.lib.schema.annotation.props.gen.LengthKind
 import org.apache.daffodil.lib.schema.annotation.props.gen.Representation
@@ -157,10 +158,13 @@ trait ElementBaseRuntime1Mixin { self: ElementBase =>
       schemaSet.typeCalcMap,
       shortSchemaComponentDesignator,
       isOutputValueCalc,
+      isDistinguishedRoot,
     )
     eci
   }
 
+  private lazy val isDistinguishedRoot = this.isInstanceOf[Root]
+
   override lazy val runtimeData: RuntimeData = elementRuntimeData
   override lazy val termRuntimeData: TermRuntimeData = elementRuntimeData
 
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/CompiledExpression1.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/CompiledExpression1.scala
index 016d93c9a..261d72034 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/CompiledExpression1.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dsom/CompiledExpression1.scala
@@ -365,6 +365,7 @@ class DPathElementCompileInfo(
   typeCalcMap: TypeCalcMap,
   val sscd: String,
   val isOutputValueCalc: Boolean,
+  val isDistinguishedRoot: Boolean,
 ) extends DPathCompileInfo(
     parentsDelay.asInstanceOf[Delay[Seq[DPathCompileInfo]]],
     variableMap,
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala
index 02ca3599a..369f7c2fa 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala
@@ -744,8 +744,9 @@ sealed abstract class ErrorERD(local: String, namespaceURI: String)
       null, // override val unqualifiedPathStepPolicy : UnqualifiedPathStepPolicy,
       null, // typeCalcMap: TypeCalcMap,
       null, // val sscd: String),
-      false,
-    ), // val isOutputValueCalc: Boolean
+      false, // val isOutputValueCalc: Boolean
+      false, // val isDistinguishedRoot: Boolean
+    ),
     null, // SchemaFileLocation
     local, // diagnosticDebugName: String,
     local, // pathArg: => String,
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions2.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions2.tdml
index 22c9db224..6a4f0f588 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions2.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions2.tdml
@@ -300,6 +300,19 @@
       <tdml:warning>Expression compilation skipped</tdml:warning>
       <tdml:warning>value1</tdml:warning>
       <tdml:warning>value2</tdml:warning>
+      <tdml:warning>value3</tdml:warning>
+      <tdml:warning>value4</tdml:warning>
+      <tdml:warning>value5</tdml:warning>
+      <tdml:warning>value6</tdml:warning>
+      <tdml:warning>value7</tdml:warning>
+      <tdml:warning>value8</tdml:warning>
+      <tdml:warning>value9</tdml:warning>
+      <tdml:warning>value10</tdml:warning>
+      <tdml:warning>value11</tdml:warning>
+      <tdml:warning>value12</tdml:warning>
+      <tdml:warning>value13</tdml:warning>
+      <tdml:warning>value14</tdml:warning>
+      <tdml:warning>value15</tdml:warning>
     </tdml:warnings>
   </tdml:parserTestCase>
  
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions_unused_path_no_context.dfdl.xsd b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions_unused_path_no_context.dfdl.xsd
index b685f89b3..859f396f8 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions_unused_path_no_context.dfdl.xsd
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions_unused_path_no_context.dfdl.xsd
@@ -28,20 +28,119 @@
     </xs:appinfo>
   </xs:annotation>
 
+
   <xs:element name="e1" type="xs:int" dfdl:lengthKind="explicit" dfdl:length="1" />
 
-  <xs:group name="unused_group">
+  <xs:group name="unused_group_1">
     <xs:sequence>
       <xs:element name="value1" type="xs:string" dfdl:lengthKind="explicit" dfdl:length="1" />
       <xs:sequence dfdl:terminator="{ ./value1 }" />
     </xs:sequence>
   </xs:group>
 
-  <xs:complexType name="unused_complex_type">
+  <xs:complexType name="unused_complex_type_1">
     <xs:sequence>
       <xs:element name="value2" type="xs:string" dfdl:lengthKind="explicit" dfdl:length="1" />
       <xs:sequence dfdl:terminator="{ ./value2 }"/>
     </xs:sequence>
   </xs:complexType>
 
+
+  <xs:group name="unused_group_2">
+    <xs:sequence>
+      <xs:sequence dfdl:terminator="{ ./value3 }" />
+    </xs:sequence>
+  </xs:group>
+
+  <xs:complexType name="unused_complex_type_2">
+    <xs:sequence>
+      <xs:sequence dfdl:terminator="{ ./value4 }"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="unused_element_2">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:sequence dfdl:terminator="{ ./value5 }"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+
+  <xs:group name="unused_group_3">
+    <xs:sequence>
+      <xs:element name="unused" type="xs:string" dfdl:terminator="{ ../value6 }" />
+    </xs:sequence>
+  </xs:group>
+
+  <xs:complexType name="unused_complex_type_3">
+    <xs:sequence>
+      <xs:element name="unused" type="xs:string" dfdl:terminator="{ ../value7 }" />
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="unused_element_3">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="unused" type="xs:string" dfdl:terminator="{ ../../value8 }" />
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+
+  <xs:element name="unused_element_4">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="value9" type="xs:string" />
+        <xs:element name="nest1">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="nest2" type="xs:string" dfdl:terminator="{ ../../value9 }" />
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:group name="unused_group_5">
+    <xs:sequence>
+      <xs:sequence dfdl:terminator="{ /absolute/value10 }" />
+    </xs:sequence>
+  </xs:group>
+
+  <xs:complexType name="unused_complex_type_5">
+    <xs:sequence>
+      <xs:sequence dfdl:terminator="{ /absolute/value11 }"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="unused_element_5">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:sequence dfdl:terminator="{ /absolute/value12 }"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:group name="unused_group_6">
+    <xs:sequence>
+      <xs:element name="unused" type="xs:string" dfdl:terminator="{ /absolute/value13 }" />
+    </xs:sequence>
+  </xs:group>
+
+  <xs:complexType name="unused_complex_type_6">
+    <xs:sequence>
+      <xs:element name="unused" type="xs:string" dfdl:terminator="{ /absolute/value14 }" />
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:element name="unused_element_6">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="unused" type="xs:string" dfdl:terminator="{ /absolute/value15 }" />
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
 </xs:schema>