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