diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp index 89900ed4d03a5..6c2ed6c84c6cf 100644 --- a/llvm/lib/Support/Mustache.cpp +++ b/llvm/lib/Support/Mustache.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Mustache.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" #include @@ -23,6 +22,13 @@ static bool isFalsey(const json::Value &V) { (V.getAsArray() && V.getAsArray()->empty()); } +static bool isContextFalsey(const json::Value *V) { + // A missing context (represented by a nullptr) is defined as falsey. + if (!V) + return true; + return isFalsey(*V); +} + static Accessor splitMustacheString(StringRef Str) { // We split the mustache string into an accessor. // For example: @@ -560,14 +566,15 @@ void toMustacheString(const json::Value &Data, raw_ostream &OS) { } } -void ASTNode::render(const json::Value &Data, raw_ostream &OS) { - ParentContext = &Data; +void ASTNode::render(const json::Value &CurrentCtx, raw_ostream &OS) { + // Set the parent context to the incoming context so that we + // can walk up the context tree correctly in findContext(). + ParentContext = &CurrentCtx; const json::Value *ContextPtr = Ty == Root ? ParentContext : findContext(); - const json::Value &Context = ContextPtr ? *ContextPtr : nullptr; switch (Ty) { case Root: - renderChild(Data, OS); + renderChild(CurrentCtx, OS); return; case Text: OS << Body; @@ -575,53 +582,55 @@ void ASTNode::render(const json::Value &Data, raw_ostream &OS) { case Partial: { auto Partial = Partials.find(AccessorValue[0]); if (Partial != Partials.end()) - renderPartial(Data, OS, Partial->getValue().get()); + renderPartial(CurrentCtx, OS, Partial->getValue().get()); return; } case Variable: { auto Lambda = Lambdas.find(AccessorValue[0]); - if (Lambda != Lambdas.end()) - renderLambdas(Data, OS, Lambda->getValue()); - else { + if (Lambda != Lambdas.end()) { + renderLambdas(CurrentCtx, OS, Lambda->getValue()); + } else if (ContextPtr) { EscapeStringStream ES(OS, Escapes); - toMustacheString(Context, ES); + toMustacheString(*ContextPtr, ES); } return; } case UnescapeVariable: { auto Lambda = Lambdas.find(AccessorValue[0]); - if (Lambda != Lambdas.end()) - renderLambdas(Data, OS, Lambda->getValue()); - else - toMustacheString(Context, OS); + if (Lambda != Lambdas.end()) { + renderLambdas(CurrentCtx, OS, Lambda->getValue()); + } else if (ContextPtr) { + toMustacheString(*ContextPtr, OS); + } return; } case Section: { - // Sections are not rendered if the context is falsey. auto SectionLambda = SectionLambdas.find(AccessorValue[0]); bool IsLambda = SectionLambda != SectionLambdas.end(); - if (isFalsey(Context) && !IsLambda) - return; if (IsLambda) { - renderSectionLambdas(Data, OS, SectionLambda->getValue()); + renderSectionLambdas(CurrentCtx, OS, SectionLambda->getValue()); return; } - if (Context.getAsArray()) { - const json::Array *Arr = Context.getAsArray(); + if (isContextFalsey(ContextPtr)) + return; + + if (const json::Array *Arr = ContextPtr->getAsArray()) { for (const json::Value &V : *Arr) renderChild(V, OS); return; } - renderChild(Context, OS); + renderChild(*ContextPtr, OS); return; } case InvertSection: { bool IsLambda = SectionLambdas.contains(AccessorValue[0]); - if (!isFalsey(Context) || IsLambda) - return; - renderChild(Context, OS); + if (isContextFalsey(ContextPtr) && !IsLambda) { + // The context for the children remains unchanged from the parent's, so + // we pass this node's original incoming context. + renderChild(CurrentCtx, OS); + } return; } }