1 // sass.hpp must go before all system headers to get the
2 // __EXTENSIONS__ fix on Solaris.
3 #include "sass.hpp"
4 #include "ast.hpp"
5 
6 #include "util_string.hpp"
7 
8 namespace Sass {
9 
10   // ##########################################################################
11   // To compare/debug against libsass you can use debugger.hpp:
12   // c++: std::cerr << "result " << debug_vec(compound) << "\n";
13   // dart: stderr.writeln("result " + compound.toString());
14   // ##########################################################################
15 
16   // ##########################################################################
17   // Returns whether [list1] is a superselector of [list2].
18   // That is, whether [list1] matches every element that
19   // [list2] matches, as well as possibly additional elements.
20   // ##########################################################################
21   bool listIsSuperslector(
22     const sass::vector<ComplexSelectorObj>& list1,
23     const sass::vector<ComplexSelectorObj>& list2);
24 
25   // ##########################################################################
26   // Returns whether [complex1] is a superselector of [complex2].
27   // That is, whether [complex1] matches every element that
28   // [complex2] matches, as well as possibly additional elements.
29   // ##########################################################################
30   bool complexIsSuperselector(
31     const sass::vector<SelectorComponentObj>& complex1,
32     const sass::vector<SelectorComponentObj>& complex2);
33 
34   // ##########################################################################
35   // Returns all pseudo selectors in [compound] that have
36   // a selector argument, and that have the given [name].
37   // ##########################################################################
selectorPseudoNamed(CompoundSelectorObj compound,sass::string name)38   sass::vector<PseudoSelectorObj> selectorPseudoNamed(
39     CompoundSelectorObj compound, sass::string name)
40   {
41     sass::vector<PseudoSelectorObj> rv;
42     for (SimpleSelectorObj sel : compound->elements()) {
43       if (PseudoSelectorObj pseudo = Cast<PseudoSelector>(sel)) {
44         if (pseudo->isClass() && pseudo->selector()) {
45           if (sel->name() == name) {
46             rv.push_back(sel);
47           }
48         }
49       }
50     }
51     return rv;
52   }
53   // EO selectorPseudoNamed
54 
55   // ##########################################################################
56   // Returns whether [simple1] is a superselector of [simple2].
57   // That is, whether [simple1] matches every element that
58   // [simple2] matches, as well as possibly additional elements.
59   // ##########################################################################
simpleIsSuperselector(const SimpleSelectorObj & simple1,const SimpleSelectorObj & simple2)60   bool simpleIsSuperselector(
61     const SimpleSelectorObj& simple1,
62     const SimpleSelectorObj& simple2)
63   {
64     // If they are equal they are superselectors
65     if (ObjEqualityFn(simple1, simple2)) {
66       return true;
67     }
68     // Some selector pseudoclasses can match normal selectors.
69     if (const PseudoSelector* pseudo = Cast<PseudoSelector>(simple2)) {
70       if (pseudo->selector() && isSubselectorPseudo(pseudo->normalized())) {
71         for (auto complex : pseudo->selector()->elements()) {
72           // Make sure we have exacly one items
73           if (complex->length() != 1) {
74             return false;
75           }
76           // That items must be a compound selector
77           if (auto compound = Cast<CompoundSelector>(complex->at(0))) {
78             // It must contain the lhs simple selector
79             if (!compound->contains(simple1)) {
80               return false;
81             }
82           }
83         }
84         return true;
85       }
86     }
87     return false;
88   }
89   // EO simpleIsSuperselector
90 
91   // ##########################################################################
92   // Returns whether [simple] is a superselector of [compound].
93   // That is, whether [simple] matches every element that
94   // [compound] matches, as well as possibly additional elements.
95   // ##########################################################################
simpleIsSuperselectorOfCompound(const SimpleSelectorObj & simple,const CompoundSelectorObj & compound)96   bool simpleIsSuperselectorOfCompound(
97     const SimpleSelectorObj& simple,
98     const CompoundSelectorObj& compound)
99   {
100     for (SimpleSelectorObj simple2 : compound->elements()) {
101       if (simpleIsSuperselector(simple, simple2)) {
102         return true;
103       }
104     }
105     return false;
106   }
107   // EO simpleIsSuperselectorOfCompound
108 
109   // ##########################################################################
110   // ##########################################################################
typeIsSuperselectorOfCompound(const TypeSelectorObj & type,const CompoundSelectorObj & compound)111   bool typeIsSuperselectorOfCompound(
112     const TypeSelectorObj& type,
113     const CompoundSelectorObj& compound)
114   {
115     for (const SimpleSelectorObj& simple : compound->elements()) {
116       if (const TypeSelectorObj& rhs = Cast<TypeSelector>(simple)) {
117         if (*type != *rhs) return true;
118       }
119     }
120     return false;
121   }
122   // EO typeIsSuperselectorOfCompound
123 
124   // ##########################################################################
125   // ##########################################################################
idIsSuperselectorOfCompound(const IDSelectorObj & id,const CompoundSelectorObj & compound)126   bool idIsSuperselectorOfCompound(
127     const IDSelectorObj& id,
128     const CompoundSelectorObj& compound)
129   {
130     for (const SimpleSelectorObj& simple : compound->elements()) {
131       if (const IDSelectorObj& rhs = Cast<IDSelector>(simple)) {
132         if (*id != *rhs) return true;
133       }
134     }
135     return false;
136   }
137   // EO idIsSuperselectorOfCompound
138 
139   // ##########################################################################
140   // ##########################################################################
pseudoIsSuperselectorOfPseudo(const PseudoSelectorObj & pseudo1,const PseudoSelectorObj & pseudo2,const ComplexSelectorObj & parent)141   bool pseudoIsSuperselectorOfPseudo(
142     const PseudoSelectorObj& pseudo1,
143     const PseudoSelectorObj& pseudo2,
144     const ComplexSelectorObj& parent
145   )
146   {
147     if (!pseudo2->selector()) return false;
148     if (pseudo1->name() == pseudo2->name()) {
149       SelectorListObj list = pseudo2->selector();
150       return listIsSuperslector(list->elements(), { parent });
151     }
152     return false;
153   }
154   // EO pseudoIsSuperselectorOfPseudo
155 
156   // ##########################################################################
157   // ##########################################################################
pseudoNotIsSuperselectorOfCompound(const PseudoSelectorObj & pseudo1,const CompoundSelectorObj & compound2,const ComplexSelectorObj & parent)158   bool pseudoNotIsSuperselectorOfCompound(
159     const PseudoSelectorObj& pseudo1,
160     const CompoundSelectorObj& compound2,
161     const ComplexSelectorObj& parent)
162   {
163     for (const SimpleSelectorObj& simple2 : compound2->elements()) {
164       if (const TypeSelectorObj& type2 = Cast<TypeSelector>(simple2)) {
165         if (const CompoundSelectorObj& compound1 = Cast<CompoundSelector>(parent->last())) {
166           if (typeIsSuperselectorOfCompound(type2, compound1)) return true;
167         }
168       }
169       else if (const IDSelectorObj& id2 = Cast<IDSelector>(simple2)) {
170         if (const CompoundSelectorObj& compound1 = Cast<CompoundSelector>(parent->last())) {
171           if (idIsSuperselectorOfCompound(id2, compound1)) return true;
172         }
173       }
174       else if (const PseudoSelectorObj& pseudo2 = Cast<PseudoSelector>(simple2)) {
175         if (pseudoIsSuperselectorOfPseudo(pseudo1, pseudo2, parent)) return true;
176       }
177     }
178     return false;
179   }
180   // pseudoNotIsSuperselectorOfCompound
181 
182   // ##########################################################################
183   // Returns whether [pseudo1] is a superselector of [compound2].
184   // That is, whether [pseudo1] matches every element that [compound2]
185   // matches, as well as possibly additional elements. This assumes that
186   // [pseudo1]'s `selector` argument is not `null`. If [parents] is passed,
187   // it represents the parents of [compound2]. This is relevant for pseudo
188   // selectors with selector arguments, where we may need to know if the
189   // parent selectors in the selector argument match [parents].
190   // ##########################################################################
selectorPseudoIsSuperselector(const PseudoSelectorObj & pseudo1,const CompoundSelectorObj & compound2,sass::vector<SelectorComponentObj>::const_iterator parents_from,sass::vector<SelectorComponentObj>::const_iterator parents_to)191   bool selectorPseudoIsSuperselector(
192     const PseudoSelectorObj& pseudo1,
193     const CompoundSelectorObj& compound2,
194     // ToDo: is this really the most convenient way to do this?
195     sass::vector<SelectorComponentObj>::const_iterator parents_from,
196     sass::vector<SelectorComponentObj>::const_iterator parents_to)
197   {
198 
199     // ToDo: move normalization function
200     sass::string name(Util::unvendor(pseudo1->name()));
201 
202     if (name == "matches" || name == "any") {
203       sass::vector<PseudoSelectorObj> pseudos =
204         selectorPseudoNamed(compound2, pseudo1->name());
205       SelectorListObj selector1 = pseudo1->selector();
206       for (PseudoSelectorObj pseudo2 : pseudos) {
207         SelectorListObj selector = pseudo2->selector();
208         if (selector1->isSuperselectorOf(selector)) {
209           return true;
210         }
211       }
212 
213       for (ComplexSelectorObj complex1 : selector1->elements()) {
214         sass::vector<SelectorComponentObj> parents;
215         for (auto cur = parents_from; cur != parents_to; cur++) {
216           parents.push_back(*cur);
217         }
218         parents.push_back(compound2);
219         if (complexIsSuperselector(complex1->elements(), parents)) {
220           return true;
221         }
222       }
223 
224     }
225     else if (name == "has" || name == "host" || name == "host-context" || name == "slotted") {
226       sass::vector<PseudoSelectorObj> pseudos =
227         selectorPseudoNamed(compound2, pseudo1->name());
228       SelectorListObj selector1 = pseudo1->selector();
229       for (PseudoSelectorObj pseudo2 : pseudos) {
230         SelectorListObj selector = pseudo2->selector();
231         if (selector1->isSuperselectorOf(selector)) {
232           return true;
233         }
234       }
235 
236     }
237     else if (name == "not") {
238       for (ComplexSelectorObj complex : pseudo1->selector()->elements()) {
239         if (!pseudoNotIsSuperselectorOfCompound(pseudo1, compound2, complex)) return false;
240       }
241       return true;
242     }
243     else if (name == "current") {
244       sass::vector<PseudoSelectorObj> pseudos =
245         selectorPseudoNamed(compound2, "current");
246       for (PseudoSelectorObj pseudo2 : pseudos) {
247         if (ObjEqualityFn(pseudo1, pseudo2)) return true;
248       }
249 
250     }
251     else if (name == "nth-child" || name == "nth-last-child") {
252       for (auto simple2 : compound2->elements()) {
253         if (PseudoSelectorObj pseudo2 = simple2->getPseudoSelector()) {
254           if (pseudo1->name() != pseudo2->name()) continue;
255           if (!ObjEqualityFn(pseudo1->argument(), pseudo2->argument())) continue;
256           if (pseudo1->selector()->isSuperselectorOf(pseudo2->selector())) return true;
257         }
258       }
259       return false;
260     }
261 
262     return false;
263 
264   }
265   // EO selectorPseudoIsSuperselector
266 
267   // ##########################################################################
268   // Returns whether [compound1] is a superselector of [compound2].
269   // That is, whether [compound1] matches every element that [compound2]
270   // matches, as well as possibly additional elements. If [parents] is
271   // passed, it represents the parents of [compound2]. This is relevant
272   // for pseudo selectors with selector arguments, where we may need to
273   // know if the parent selectors in the selector argument match [parents].
274   // ##########################################################################
compoundIsSuperselector(const CompoundSelectorObj & compound1,const CompoundSelectorObj & compound2,const sass::vector<SelectorComponentObj>::const_iterator parents_from,const sass::vector<SelectorComponentObj>::const_iterator parents_to)275   bool compoundIsSuperselector(
276     const CompoundSelectorObj& compound1,
277     const CompoundSelectorObj& compound2,
278     // ToDo: is this really the most convenient way to do this?
279     const sass::vector<SelectorComponentObj>::const_iterator parents_from,
280     const sass::vector<SelectorComponentObj>::const_iterator parents_to)
281   {
282     // Every selector in [compound1.components] must have
283     // a matching selector in [compound2.components].
284     for (SimpleSelectorObj simple1 : compound1->elements()) {
285       PseudoSelectorObj pseudo1 = Cast<PseudoSelector>(simple1);
286       if (pseudo1 && pseudo1->selector()) {
287         if (!selectorPseudoIsSuperselector(pseudo1, compound2, parents_from, parents_to)) {
288           return false;
289         }
290       }
291       else if (!simpleIsSuperselectorOfCompound(simple1, compound2)) {
292         return false;
293       }
294     }
295     // [compound1] can't be a superselector of a selector
296     // with pseudo-elements that [compound2] doesn't share.
297     for (SimpleSelectorObj simple2 : compound2->elements()) {
298       PseudoSelectorObj pseudo2 = Cast<PseudoSelector>(simple2);
299       if (pseudo2 && pseudo2->isElement()) {
300         if (!simpleIsSuperselectorOfCompound(pseudo2, compound1)) {
301           return false;
302         }
303       }
304     }
305     return true;
306   }
307   // EO compoundIsSuperselector
308 
309   // ##########################################################################
310   // Returns whether [compound1] is a superselector of [compound2].
311   // That is, whether [compound1] matches every element that [compound2]
312   // matches, as well as possibly additional elements. If [parents] is
313   // passed, it represents the parents of [compound2]. This is relevant
314   // for pseudo selectors with selector arguments, where we may need to
315   // know if the parent selectors in the selector argument match [parents].
316   // ##########################################################################
compoundIsSuperselector(const CompoundSelectorObj & compound1,const CompoundSelectorObj & compound2,const sass::vector<SelectorComponentObj> & parents)317   bool compoundIsSuperselector(
318     const CompoundSelectorObj& compound1,
319     const CompoundSelectorObj& compound2,
320     const sass::vector<SelectorComponentObj>& parents)
321   {
322     return compoundIsSuperselector(
323       compound1, compound2,
324       parents.begin(), parents.end()
325     );
326   }
327   // EO compoundIsSuperselector
328 
329   // ##########################################################################
330   // Returns whether [complex1] is a superselector of [complex2].
331   // That is, whether [complex1] matches every element that
332   // [complex2] matches, as well as possibly additional elements.
333   // ##########################################################################
complexIsSuperselector(const sass::vector<SelectorComponentObj> & complex1,const sass::vector<SelectorComponentObj> & complex2)334   bool complexIsSuperselector(
335     const sass::vector<SelectorComponentObj>& complex1,
336     const sass::vector<SelectorComponentObj>& complex2)
337   {
338 
339     // Selectors with trailing operators are neither superselectors nor subselectors.
340     if (!complex1.empty() && Cast<SelectorCombinator>(complex1.back())) return false;
341     if (!complex2.empty() && Cast<SelectorCombinator>(complex2.back())) return false;
342 
343     size_t i1 = 0, i2 = 0;
344     while (true) {
345 
346       size_t remaining1 = complex1.size() - i1;
347       size_t remaining2 = complex2.size() - i2;
348 
349       if (remaining1 == 0 || remaining2 == 0) {
350         return false;
351       }
352       // More complex selectors are never
353       // superselectors of less complex ones.
354       if (remaining1 > remaining2) {
355         return false;
356       }
357 
358       // Selectors with leading operators are
359       // neither superselectors nor subselectors.
360       if (Cast<SelectorCombinator>(complex1[i1])) {
361         return false;
362       }
363       if (Cast<SelectorCombinator>(complex2[i2])) {
364         return false;
365       }
366 
367       CompoundSelectorObj compound1 = Cast<CompoundSelector>(complex1[i1]);
368       CompoundSelectorObj compound2 = Cast<CompoundSelector>(complex2.back());
369 
370       if (remaining1 == 1) {
371         sass::vector<SelectorComponentObj>::const_iterator parents_to = complex2.end();
372         sass::vector<SelectorComponentObj>::const_iterator parents_from = complex2.begin();
373         std::advance(parents_from, i2 + 1); // equivalent to dart `.skip(i2 + 1)`
374         bool rv = compoundIsSuperselector(compound1, compound2, parents_from, parents_to);
375         sass::vector<SelectorComponentObj> pp;
376 
377         sass::vector<SelectorComponentObj>::const_iterator end = parents_to;
378         sass::vector<SelectorComponentObj>::const_iterator beg = parents_from;
379         while (beg != end) {
380           pp.push_back(*beg);
381           beg++;
382         }
383 
384         return rv;
385       }
386 
387       // Find the first index where `complex2.sublist(i2, afterSuperselector)`
388       // is a subselector of [compound1]. We stop before the superselector
389       // would encompass all of [complex2] because we know [complex1] has
390       // more than one element, and consuming all of [complex2] wouldn't
391       // leave anything for the rest of [complex1] to match.
392       size_t afterSuperselector = i2 + 1;
393       for (; afterSuperselector < complex2.size(); afterSuperselector++) {
394         SelectorComponentObj component2 = complex2[afterSuperselector - 1];
395         if (CompoundSelectorObj compound2 = Cast<CompoundSelector>(component2)) {
396           sass::vector<SelectorComponentObj>::const_iterator parents_to = complex2.begin();
397           sass::vector<SelectorComponentObj>::const_iterator parents_from = complex2.begin();
398           // complex2.take(afterSuperselector - 1).skip(i2 + 1)
399           std::advance(parents_from, i2 + 1); // equivalent to dart `.skip`
400           std::advance(parents_to, afterSuperselector); // equivalent to dart `.take`
401           if (compoundIsSuperselector(compound1, compound2, parents_from, parents_to)) {
402             break;
403           }
404         }
405       }
406       if (afterSuperselector == complex2.size()) {
407         return false;
408       }
409 
410       SelectorComponentObj component1 = complex1[i1 + 1],
411         component2 = complex2[afterSuperselector];
412 
413       SelectorCombinatorObj combinator1 = Cast<SelectorCombinator>(component1);
414       SelectorCombinatorObj combinator2 = Cast<SelectorCombinator>(component2);
415 
416       if (!combinator1.isNull()) {
417 
418         if (combinator2.isNull()) {
419           return false;
420         }
421         // `.a ~ .b` is a superselector of `.a + .b`,
422         // but otherwise the combinators must match.
423         if (combinator1->isGeneralCombinator()) {
424           if (combinator2->isChildCombinator()) {
425             return false;
426           }
427         }
428         else if (*combinator1 != *combinator2) {
429           return false;
430         }
431 
432         // `.foo > .baz` is not a superselector of `.foo > .bar > .baz` or
433         // `.foo > .bar .baz`, despite the fact that `.baz` is a superselector of
434         // `.bar > .baz` and `.bar .baz`. Same goes for `+` and `~`.
435         if (remaining1 == 3 && remaining2 > 3) {
436           return false;
437         }
438 
439         i1 += 2; i2 = afterSuperselector + 1;
440 
441       }
442       else if (!combinator2.isNull()) {
443         if (!combinator2->isChildCombinator()) {
444           return false;
445         }
446         i1 += 1; i2 = afterSuperselector + 1;
447       }
448       else {
449         i1 += 1; i2 = afterSuperselector;
450       }
451     }
452 
453     return false;
454 
455   }
456   // EO complexIsSuperselector
457 
458   // ##########################################################################
459   // Like [complexIsSuperselector], but compares [complex1]
460   // and [complex2] as though they shared an implicit base
461   // [SimpleSelector]. For example, `B` is not normally a
462   // superselector of `B A`, since it doesn't match elements
463   // that match `A`. However, it *is* a parent superselector,
464   // since `B X` is a superselector of `B A X`.
465   // ##########################################################################
complexIsParentSuperselector(const sass::vector<SelectorComponentObj> & complex1,const sass::vector<SelectorComponentObj> & complex2)466   bool complexIsParentSuperselector(
467     const sass::vector<SelectorComponentObj>& complex1,
468     const sass::vector<SelectorComponentObj>& complex2)
469   {
470     // Try some simple heuristics to see if we can avoid allocations.
471     if (complex1.empty() && complex2.empty()) return false;
472     if (Cast<SelectorCombinator>(complex1.front())) return false;
473     if (Cast<SelectorCombinator>(complex2.front())) return false;
474     if (complex1.size() > complex2.size()) return false;
475     // TODO(nweiz): There's got to be a way to do this without a bunch of extra allocations...
476     sass::vector<SelectorComponentObj> cplx1(complex1);
477     sass::vector<SelectorComponentObj> cplx2(complex2);
478     CompoundSelectorObj base = SASS_MEMORY_NEW(CompoundSelector, "[tmp]");
479     cplx1.push_back(base); cplx2.push_back(base);
480     return complexIsSuperselector(cplx1, cplx2);
481   }
482   // EO complexIsParentSuperselector
483 
484   // ##########################################################################
485   // Returns whether [list] has a superselector for [complex].
486   // That is, whether an item in [list] matches every element that
487   // [complex] matches, as well as possibly additional elements.
488   // ##########################################################################
listHasSuperslectorForComplex(sass::vector<ComplexSelectorObj> list,ComplexSelectorObj complex)489   bool listHasSuperslectorForComplex(
490     sass::vector<ComplexSelectorObj> list,
491     ComplexSelectorObj complex)
492   {
493     // Return true if every [complex] selector on [list2]
494     // is a super selector of the full selector [list1].
495     for (ComplexSelectorObj lhs : list) {
496       if (complexIsSuperselector(lhs->elements(), complex->elements())) {
497         return true;
498       }
499     }
500     return false;
501   }
502   // listIsSuperslectorOfComplex
503 
504   // ##########################################################################
505   // Returns whether [list1] is a superselector of [list2].
506   // That is, whether [list1] matches every element that
507   // [list2] matches, as well as possibly additional elements.
508   // ##########################################################################
listIsSuperslector(const sass::vector<ComplexSelectorObj> & list1,const sass::vector<ComplexSelectorObj> & list2)509   bool listIsSuperslector(
510     const sass::vector<ComplexSelectorObj>& list1,
511     const sass::vector<ComplexSelectorObj>& list2)
512   {
513     // Return true if every [complex] selector on [list2]
514     // is a super selector of the full selector [list1].
515     for (ComplexSelectorObj complex : list2) {
516       if (!listHasSuperslectorForComplex(list1, complex)) {
517         return false;
518       }
519     }
520     return true;
521   }
522   // EO listIsSuperslector
523 
524   // ##########################################################################
525   // Implement selector methods (dispatch to functions)
526   // ##########################################################################
isSuperselectorOf(const SelectorList * sub) const527   bool SelectorList::isSuperselectorOf(const SelectorList* sub) const
528   {
529     return listIsSuperslector(elements(), sub->elements());
530   }
isSuperselectorOf(const ComplexSelector * sub) const531   bool ComplexSelector::isSuperselectorOf(const ComplexSelector* sub) const
532   {
533     return complexIsSuperselector(elements(), sub->elements());
534   }
535 
536   // ##########################################################################
537   // ##########################################################################
538 
539 }
540