Skip to content

Commit 64856b2

Browse files
committed
Fix issue with extend and recursions
1 parent 4d0bc51 commit 64856b2

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

src/extend.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,8 @@ namespace Sass {
17111711
static bool complexSelectorHasExtension(
17121712
Complex_Selector* pComplexSelector,
17131713
Context& ctx,
1714-
ExtensionSubsetMap& subset_map) {
1714+
ExtensionSubsetMap& subset_map,
1715+
std::set<Compound_Selector>& seen) {
17151716

17161717
bool hasExtension = false;
17171718

@@ -1721,16 +1722,18 @@ namespace Sass {
17211722
Compound_Selector* pHead = pIter->head();
17221723

17231724
if (pHead) {
1724-
for (Simple_Selector* pSimple : *pHead) {
1725-
if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(pSimple)) {
1726-
if (Selector_List* sl = dynamic_cast<Selector_List*>(ws->selector())) {
1727-
for (Complex_Selector* cs : sl->elements()) {
1728-
while (cs) {
1729-
if (complexSelectorHasExtension(cs, ctx, subset_map)) {
1730-
hasExtension = true;
1731-
break;
1725+
if (seen.find(*pHead) == seen.end()) {
1726+
for (Simple_Selector* pSimple : *pHead) {
1727+
if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(pSimple)) {
1728+
if (Selector_List* sl = dynamic_cast<Selector_List*>(ws->selector())) {
1729+
for (Complex_Selector* cs : sl->elements()) {
1730+
while (cs) {
1731+
if (complexSelectorHasExtension(cs, ctx, subset_map, seen)) {
1732+
hasExtension = true;
1733+
break;
1734+
}
1735+
cs = cs->tail();
17321736
}
1733-
cs = cs->tail();
17341737
}
17351738
}
17361739
}
@@ -1907,6 +1910,14 @@ namespace Sass {
19071910
This is the equivalent of ruby's CommaSequence.do_extend.
19081911
*/
19091912
Selector_List* Extend::extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething) {
1913+
std::set<Compound_Selector> seen;
1914+
return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
1915+
}
1916+
1917+
/*
1918+
This is the equivalent of ruby's CommaSequence.do_extend.
1919+
*/
1920+
Selector_List* Extend::extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething, std::set<Compound_Selector>& seen) {
19101921

19111922
Selector_List* pNewSelectors = SASS_MEMORY_NEW(ctx.mem, Selector_List, pSelectorList->pstate(), pSelectorList->length());
19121923

@@ -1920,15 +1931,13 @@ namespace Sass {
19201931
// run through the extend code (which does a data model transformation), check if there is anything to extend before doing
19211932
// the extend. We might be able to optimize extendComplexSelector, but this approach keeps us closer to ruby sass (which helps
19221933
// when debugging).
1923-
if (!complexSelectorHasExtension(pSelector, ctx, subset_map)) {
1934+
if (!complexSelectorHasExtension(pSelector, ctx, subset_map, seen)) {
19241935
*pNewSelectors << pSelector;
19251936
continue;
19261937
}
19271938

19281939
extendedSomething = true;
19291940

1930-
std::set<Compound_Selector> seen;
1931-
19321941
Node extendedSelectors = extendComplexSelector(pSelector, ctx, subset_map, seen, isReplace, true);
19331942
if (!pSelector->has_placeholder()) {
19341943
if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
@@ -1955,7 +1964,9 @@ namespace Sass {
19551964
// process tails
19561965
while (cur) {
19571966
// process header
1958-
if (cur->head()) {
1967+
if (cur->head() && seen.find(*cur->head()) == seen.end()) {
1968+
std::set<Compound_Selector> recseen(seen);
1969+
recseen.insert(*cur->head());
19591970
// create a copy since we add multiple items if stuff get unwrapped
19601971
Compound_Selector* cpy_head = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, cur->pstate());
19611972
for (Simple_Selector* hs : *cur->head()) {
@@ -1969,7 +1980,7 @@ namespace Sass {
19691980
// has wrapped selectors
19701981
else {
19711982
// extend the inner list of wrapped selector
1972-
Selector_List* ext_sl = extendSelectorList(sl, ctx, subset_map);
1983+
Selector_List* ext_sl = extendSelectorList(sl, ctx, subset_map, recseen);
19731984
for (size_t i = 0; i < ext_sl->length(); i += 1) {
19741985
if (Complex_Selector* ext_cs = ext_sl->at(i)) {
19751986
// create clones for wrapped selector and the inner list

src/extend.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define SASS_EXTEND_H
33

44
#include <string>
5+
#include <set>
56

67
#include "ast.hpp"
78
#include "operation.hpp"
@@ -23,11 +24,17 @@ namespace Sass {
2324

2425
public:
2526
static Node subweave(Node& one, Node& two, Context& ctx);
27+
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething, std::set<Compound_Selector>& seen);
2628
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething);
2729
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace = false) {
2830
bool extendedSomething = false;
2931
return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething);
3032
}
33+
static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, std::set<Compound_Selector>& seen) {
34+
bool isReplace = false;
35+
bool extendedSomething = false;
36+
return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
37+
}
3138
Extend(Context&, ExtensionSubsetMap&);
3239
~Extend() { }
3340

0 commit comments

Comments
 (0)