LCOV - code coverage report
Current view: top level - dom/xslt/xpath - txXPathOptimizer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 127 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/Assertions.h"
       7             : #include "txXPathOptimizer.h"
       8             : #include "txExprResult.h"
       9             : #include "nsIAtom.h"
      10             : #include "nsGkAtoms.h"
      11             : #include "txXPathNode.h"
      12             : #include "txExpr.h"
      13             : #include "txIXPathContext.h"
      14             : 
      15           0 : class txEarlyEvalContext : public txIEvalContext
      16             : {
      17             : public:
      18           0 :     explicit txEarlyEvalContext(txResultRecycler* aRecycler)
      19           0 :         : mRecycler(aRecycler)
      20             :     {
      21           0 :     }
      22             : 
      23             :     // txIEvalContext
      24           0 :     nsresult getVariable(int32_t aNamespace, nsIAtom* aLName,
      25             :                          txAExprResult*& aResult)
      26             :     {
      27           0 :         MOZ_CRASH("shouldn't depend on this context");
      28             :     }
      29           0 :     nsresult isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
      30             :     {
      31           0 :         MOZ_CRASH("shouldn't depend on this context");
      32             :     }
      33           0 :     void* getPrivateContext()
      34             :     {
      35           0 :         MOZ_CRASH("shouldn't depend on this context");
      36             :     }
      37           0 :     txResultRecycler* recycler()
      38             :     {
      39           0 :         return mRecycler;
      40             :     }
      41           0 :     void receiveError(const nsAString& aMsg, nsresult aRes)
      42             :     {
      43           0 :     }
      44           0 :     const txXPathNode& getContextNode()
      45             :     {
      46           0 :         MOZ_CRASH("shouldn't depend on this context");
      47             :     }
      48           0 :     uint32_t size()
      49             :     {
      50           0 :         MOZ_CRASH("shouldn't depend on this context");
      51             :     }
      52           0 :     uint32_t position()
      53             :     {
      54           0 :         MOZ_CRASH("shouldn't depend on this context");
      55             :     }
      56             : 
      57             : private:
      58             :     txResultRecycler* mRecycler;
      59             : };
      60             : 
      61             : 
      62             : nsresult
      63           0 : txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr)
      64             : {
      65           0 :     *aOutExpr = nullptr;
      66           0 :     nsresult rv = NS_OK;
      67             : 
      68             :     // First check if the expression will produce the same result
      69             :     // under any context.
      70           0 :     Expr::ExprType exprType = aInExpr->getType();
      71           0 :     if (exprType != Expr::LITERAL_EXPR &&
      72           0 :         !aInExpr->isSensitiveTo(Expr::ANY_CONTEXT)) {
      73           0 :         RefPtr<txResultRecycler> recycler = new txResultRecycler;
      74           0 :         txEarlyEvalContext context(recycler);
      75           0 :         RefPtr<txAExprResult> exprRes;
      76             : 
      77             :         // Don't throw if this fails since it could be that the expression
      78             :         // is or contains an error-expression.
      79           0 :         rv = aInExpr->evaluate(&context, getter_AddRefs(exprRes));
      80           0 :         if (NS_SUCCEEDED(rv)) {
      81           0 :             *aOutExpr = new txLiteralExpr(exprRes);
      82             :         }
      83             : 
      84           0 :         return NS_OK;
      85             :     }
      86             : 
      87             :     // Then optimize sub expressions
      88           0 :     uint32_t i = 0;
      89             :     Expr* subExpr;
      90           0 :     while ((subExpr = aInExpr->getSubExprAt(i))) {
      91           0 :         Expr* newExpr = nullptr;
      92           0 :         rv = optimize(subExpr, &newExpr);
      93           0 :         NS_ENSURE_SUCCESS(rv, rv);
      94           0 :         if (newExpr) {
      95           0 :             delete subExpr;
      96           0 :             aInExpr->setSubExprAt(i, newExpr);
      97             :         }
      98             : 
      99           0 :         ++i;
     100             :     }
     101             : 
     102             :     // Finally see if current expression can be optimized
     103           0 :     switch (exprType) {
     104             :         case Expr::LOCATIONSTEP_EXPR:
     105           0 :             return optimizeStep(aInExpr, aOutExpr);
     106             : 
     107             :         case Expr::PATH_EXPR:
     108           0 :             return optimizePath(aInExpr, aOutExpr);
     109             : 
     110             :         case Expr::UNION_EXPR:
     111           0 :             return optimizeUnion(aInExpr, aOutExpr);
     112             : 
     113             :         default:
     114           0 :             break;
     115             :     }
     116             : 
     117           0 :     return NS_OK;
     118             : }
     119             : 
     120             : nsresult
     121           0 : txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr)
     122             : {
     123           0 :     LocationStep* step = static_cast<LocationStep*>(aInExpr);
     124             : 
     125           0 :     if (step->getAxisIdentifier() == LocationStep::ATTRIBUTE_AXIS) {
     126             :         // Test for @foo type steps.
     127           0 :         txNameTest* nameTest = nullptr;
     128           0 :         if (!step->getSubExprAt(0) &&
     129           0 :             step->getNodeTest()->getType() == txNameTest::NAME_TEST &&
     130             :             (nameTest = static_cast<txNameTest*>(step->getNodeTest()))->
     131           0 :                 mLocalName != nsGkAtoms::_asterisk) {
     132             : 
     133           0 :             *aOutExpr = new txNamedAttributeStep(nameTest->mNamespace,
     134             :                                                  nameTest->mPrefix,
     135           0 :                                                  nameTest->mLocalName);
     136           0 :             return NS_OK; // return since we no longer have a step-object.
     137             :         }
     138             :     }
     139             : 
     140             :     // Test for predicates that can be combined into the nodetest
     141             :     Expr* pred;
     142           0 :     while ((pred = step->getSubExprAt(0)) &&
     143           0 :            !pred->canReturnType(Expr::NUMBER_RESULT) &&
     144           0 :            !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) {
     145           0 :         txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred);
     146           0 :         step->dropFirst();
     147           0 :         step->setNodeTest(predTest);
     148             :     }
     149             : 
     150           0 :     return NS_OK;
     151             : }
     152             : 
     153             : nsresult
     154           0 : txXPathOptimizer::optimizePath(Expr* aInExpr, Expr** aOutExpr)
     155             : {
     156           0 :     PathExpr* path = static_cast<PathExpr*>(aInExpr);
     157             : 
     158             :     uint32_t i;
     159             :     Expr* subExpr;
     160             :     // look for steps like "//foo" that can be turned into "/descendant::foo"
     161             :     // and "//." that can be turned into "/descendant-or-self::node()"
     162           0 :     for (i = 0; (subExpr = path->getSubExprAt(i)); ++i) {
     163           0 :         if (path->getPathOpAt(i) == PathExpr::DESCENDANT_OP &&
     164           0 :             subExpr->getType() == Expr::LOCATIONSTEP_EXPR &&
     165           0 :             !subExpr->getSubExprAt(0)) {
     166           0 :             LocationStep* step = static_cast<LocationStep*>(subExpr);
     167           0 :             if (step->getAxisIdentifier() == LocationStep::CHILD_AXIS) {
     168           0 :                 step->setAxisIdentifier(LocationStep::DESCENDANT_AXIS);
     169           0 :                 path->setPathOpAt(i, PathExpr::RELATIVE_OP);
     170             :             }
     171           0 :             else if (step->getAxisIdentifier() == LocationStep::SELF_AXIS) {
     172           0 :                 step->setAxisIdentifier(LocationStep::DESCENDANT_OR_SELF_AXIS);
     173           0 :                 path->setPathOpAt(i, PathExpr::RELATIVE_OP);
     174             :             }
     175             :         }
     176             :     }
     177             : 
     178             :     // look for expressions that start with a "./"
     179           0 :     subExpr = path->getSubExprAt(0);
     180             :     LocationStep* step;
     181           0 :     if (subExpr->getType() == Expr::LOCATIONSTEP_EXPR &&
     182           0 :         path->getSubExprAt(1) &&
     183           0 :         path->getPathOpAt(1) != PathExpr::DESCENDANT_OP) {
     184           0 :         step = static_cast<LocationStep*>(subExpr);
     185           0 :         if (step->getAxisIdentifier() == LocationStep::SELF_AXIS &&
     186           0 :             !step->getSubExprAt(0)) {
     187           0 :             txNodeTest* test = step->getNodeTest();
     188             :             txNodeTypeTest* typeTest;
     189           0 :             if (test->getType() == txNodeTest::NODETYPE_TEST &&
     190           0 :                 (typeTest = static_cast<txNodeTypeTest*>(test))->
     191           0 :                   getNodeTestType() == txNodeTypeTest::NODE_TYPE) {
     192             :                 // We have a '.' as first step followed by a single '/'.
     193             : 
     194             :                 // Check if there are only two steps. If so, return the second
     195             :                 // as resulting expression.
     196           0 :                 if (!path->getSubExprAt(2)) {
     197           0 :                     *aOutExpr = path->getSubExprAt(1);
     198           0 :                     path->setSubExprAt(1, nullptr);
     199             : 
     200           0 :                     return NS_OK;
     201             :                 }
     202             : 
     203             :                 // Just delete the '.' step and leave the rest of the PathExpr
     204           0 :                 path->deleteExprAt(0);
     205             :             }
     206             :         }
     207             :     }
     208             : 
     209           0 :     return NS_OK;
     210             : }
     211             : 
     212             : nsresult
     213           0 : txXPathOptimizer::optimizeUnion(Expr* aInExpr, Expr** aOutExpr)
     214             : {
     215           0 :     UnionExpr* uni = static_cast<UnionExpr*>(aInExpr);
     216             : 
     217             :     // Check for expressions like "foo | bar" and
     218             :     // "descendant::foo | descendant::bar"
     219             : 
     220             :     nsresult rv;
     221             :     uint32_t current;
     222             :     Expr* subExpr;
     223           0 :     for (current = 0; (subExpr = uni->getSubExprAt(current)); ++current) {
     224           0 :         if (subExpr->getType() != Expr::LOCATIONSTEP_EXPR ||
     225           0 :             subExpr->getSubExprAt(0)) {
     226           0 :             continue;
     227             :         }
     228             : 
     229           0 :         LocationStep* currentStep = static_cast<LocationStep*>(subExpr);
     230           0 :         LocationStep::LocationStepType axis = currentStep->getAxisIdentifier();
     231             : 
     232           0 :         txUnionNodeTest* unionTest = nullptr;
     233             : 
     234             :         // Check if there are any other steps with the same axis and merge
     235             :         // them with currentStep
     236             :         uint32_t i;
     237           0 :         for (i = current + 1; (subExpr = uni->getSubExprAt(i)); ++i) {
     238           0 :             if (subExpr->getType() != Expr::LOCATIONSTEP_EXPR ||
     239           0 :                 subExpr->getSubExprAt(0)) {
     240           0 :                 continue;
     241             :             }
     242             : 
     243           0 :             LocationStep* step = static_cast<LocationStep*>(subExpr);
     244           0 :             if (step->getAxisIdentifier() != axis) {
     245           0 :                 continue;
     246             :             }
     247             : 
     248             :             // Create a txUnionNodeTest if needed
     249           0 :             if (!unionTest) {
     250           0 :                 nsAutoPtr<txNodeTest> owner(unionTest = new txUnionNodeTest);
     251           0 :                 rv = unionTest->addNodeTest(currentStep->getNodeTest());
     252           0 :                 NS_ENSURE_SUCCESS(rv, rv);
     253             : 
     254           0 :                 currentStep->setNodeTest(unionTest);
     255           0 :                 owner.forget();
     256             :             }
     257             : 
     258             :             // Merge the nodetest into the union
     259           0 :             rv = unionTest->addNodeTest(step->getNodeTest());
     260           0 :             NS_ENSURE_SUCCESS(rv, rv);
     261             : 
     262           0 :             step->setNodeTest(nullptr);
     263             : 
     264             :             // Remove the step from the UnionExpr
     265           0 :             uni->deleteExprAt(i);
     266           0 :             --i;
     267             :         }
     268             : 
     269             :         // Check if all expressions were merged into a single step. If so,
     270             :         // return the step as the new expression.
     271           0 :         if (unionTest && current == 0 && !uni->getSubExprAt(1)) {
     272             :             // Make sure the step doesn't get deleted when the UnionExpr is
     273           0 :             uni->setSubExprAt(0, nullptr);
     274           0 :             *aOutExpr = currentStep;
     275             : 
     276             :             // Return right away since we no longer have a union
     277           0 :             return NS_OK;
     278             :         }
     279             :     }
     280             : 
     281           0 :     return NS_OK;
     282             : }

Generated by: LCOV version 1.13