Skip to content

Commit

Permalink
Implement check for invalid extends
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Jan 11, 2016
1 parent 19b24a7 commit 1c13110
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 24 deletions.
9 changes: 8 additions & 1 deletion src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,7 @@ namespace Sass {
Complex_Selector* Complex_Selector::clone(Context& ctx) const
{
Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
cpy->is_optional(this->is_optional());
cpy->media_block(this->media_block());
if (tail()) cpy->tail(tail()->clone(ctx));
return cpy;
Expand All @@ -1176,7 +1177,8 @@ namespace Sass {
Complex_Selector* Complex_Selector::cloneFully(Context& ctx) const
{
Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);

cpy->is_optional(this->is_optional());
cpy->media_block(this->media_block());
if (head()) {
cpy->head(head()->clone(ctx));
}
Expand All @@ -1191,20 +1193,25 @@ namespace Sass {
Compound_Selector* Compound_Selector::clone(Context& ctx) const
{
Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *this);
cpy->is_optional(this->is_optional());
cpy->media_block(this->media_block());
cpy->extended(this->extended());
return cpy;
}

Selector_List* Selector_List::clone(Context& ctx) const
{
Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, *this);
cpy->is_optional(this->is_optional());
cpy->media_block(this->media_block());
return cpy;
}

Selector_List* Selector_List::cloneFully(Context& ctx) const
{
Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
cpy->is_optional(this->is_optional());
cpy->media_block(this->media_block());
for (size_t i = 0, L = length(); i < L; ++i) {
*cpy << (*this)[i]->cloneFully(ctx);
}
Expand Down
2 changes: 2 additions & 0 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2177,6 +2177,7 @@ namespace Sass {
class Compound_Selector : public Selector, public Vectorized<Simple_Selector*> {
private:
SourcesSet sources_;
ADD_PROPERTY(bool, extended);
ADD_PROPERTY(bool, has_parent_reference);
protected:
void adjust_after_pushing(Simple_Selector* s)
Expand All @@ -2188,6 +2189,7 @@ namespace Sass {
Compound_Selector(ParserState pstate, size_t s = 0)
: Selector(pstate),
Vectorized<Simple_Selector*>(s),
extended_(false),
has_parent_reference_(false)
{ }
bool contains_placeholder() {
Expand Down
1 change: 1 addition & 0 deletions src/debugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ inline void debug_ast(AST_Node* node, std::string ind, Env* env)
std::cerr << " <" << selector->hash() << ">";
std::cerr << " [weight:" << longToHex(selector->specificity()) << "]";
std::cerr << " [@media:" << selector->media_block() << "]";
std::cerr << (selector->extended() ? " [extended]": " -");
std::cerr << (selector->is_optional() ? " [is_optional]": " -");
std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
std::cerr << (selector->has_line_break() ? " [line-break]": " -");
Expand Down
43 changes: 20 additions & 23 deletions src/extend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,7 @@ namespace Sass {
for (size_t index = 0; index < pCompound->length(); index++) {
Simple_Selector* pSimpleSelector = (*pCompound)[index];
(*pSels) << pSimpleSelector;
pCompound->extended(true);
}
}

Expand Down Expand Up @@ -1779,29 +1780,6 @@ namespace Sass {
pIter = pIter->tail();
}

if (!hasExtension) {
/* ToDo: don't break stuff
std::stringstream err;
To_String to_string(&ctx);
std::string cwd(Sass::File::get_cwd());
std::string sel1(pComplexSelector->perform(&to_string));
Compound_Selector* pExtendSelector = 0;
for (auto i : subset_map.values()) {
if (i.first == pComplexSelector) {
pExtendSelector = i.second;
break;
}
}
if (!pExtendSelector || !pExtendSelector->is_optional()) {
std::string sel2(pExtendSelector ? pExtendSelector->perform(&to_string) : "[unknown]");
err << "\"" << sel1 << "\" failed to @extend \"" << sel2 << "\"\n";
err << "The selector \"" << sel2 << "\" was not found.\n";
err << "Use \"@extend " << sel2 << " !optional\" if the extend should be able to fail.";
error(err.str(), pExtendSelector ? pExtendSelector->pstate() : pComplexSelector->pstate());
}
*/
}

return hasExtension;
}

Expand Down Expand Up @@ -2071,6 +2049,25 @@ namespace Sass {
for (size_t i = 0, L = b->length(); i < L; ++i) {
(*b)[i]->perform(this);
}
// do final check if everything was extended
// we set `extended` flag on extended selectors
if (b->is_root()) {
// debug_subset_map(subset_map);
for(auto const &it : subset_map.values()) {
Complex_Selector* sel = it.first ? it.first->first() : NULL;
Compound_Selector* ext = it.second ? it.second : NULL;
if (ext && (ext->extended() || ext->is_optional())) continue;
std::string str_sel(sel->to_string());
std::string str_ext(ext->to_string());
// debug_ast(sel, "sel: ");
// debug_ast(ext, "ext: ");
error("\"" + str_sel + "\" failed to @extend \"" + str_ext + "\".\n"
"The selector \"" + str_ext + "\" was not found.\n"
"Use \"@extend " + str_ext + " !optional\" if the"
" extend should be able to fail.", ext->pstate());
}

This comment has been minimized.

Copy link
@wedneyyuri

wedneyyuri Apr 29, 2016

Please, can you warn about this NEW behavior? I lost hours trying to understand why my code wasn't working.

This comment has been minimized.

Copy link
@xzyfer

xzyfer via email Apr 30, 2016

Contributor
}

}

void Extend::operator()(Ruleset* pRuleset)
Expand Down

0 comments on commit 1c13110

Please sign in to comment.