Improve AST cyclic detection performance (#3330)
This commit is contained in:
parent
56924643be
commit
7e70a91613
|
@ -1340,30 +1340,33 @@ std::string Token::stringifyList(bool varid) const
|
||||||
return stringifyList(varid, false, true, true, true, nullptr, nullptr);
|
return stringifyList(varid, false, true, true, true, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token* checkAstCycle(Token* tok)
|
void Token::astParent(Token* tok)
|
||||||
{
|
{
|
||||||
std::set<const Token*> visited;
|
const Token* tok2 = tok;
|
||||||
visitAstNodes(tok, [&](const Token* child) {
|
while (tok2) {
|
||||||
if (!visited.insert(child).second)
|
if (this == tok2)
|
||||||
throw InternalError(child, "Internal error. AST cyclic dependency.");
|
throw InternalError(this, "Internal error. AST cyclic dependency.");
|
||||||
return ChildrenToVisit::op1_and_op2;
|
tok2 = tok2->astParent();
|
||||||
});
|
|
||||||
while (tok->astParent()) {
|
|
||||||
if (!visited.insert(tok->astParent()).second) // #6838/#6726/#8352 avoid hang on garbage code
|
|
||||||
throw InternalError(tok, "Internal error. AST cyclic dependency.");
|
|
||||||
tok = tok->astParent();
|
|
||||||
}
|
}
|
||||||
return tok;
|
// Clear children to avoid nodes referenced twice
|
||||||
|
if (this->astParent()) {
|
||||||
|
Token* parent = this->astParent();
|
||||||
|
if (parent->astOperand1() == this)
|
||||||
|
parent->mImpl->mAstOperand1 = nullptr;
|
||||||
|
if (parent->astOperand2() == this)
|
||||||
|
parent->mImpl->mAstOperand2 = nullptr;
|
||||||
|
}
|
||||||
|
mImpl->mAstParent = tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Token::astOperand1(Token *tok)
|
void Token::astOperand1(Token *tok)
|
||||||
{
|
{
|
||||||
if (mImpl->mAstOperand1)
|
if (mImpl->mAstOperand1)
|
||||||
mImpl->mAstOperand1->mImpl->mAstParent = nullptr;
|
mImpl->mAstOperand1->astParent(nullptr);
|
||||||
// goto parent operator
|
// goto parent operator
|
||||||
if (tok) {
|
if (tok) {
|
||||||
tok = checkAstCycle(tok);
|
tok = tok->astTop();
|
||||||
tok->mImpl->mAstParent = this;
|
tok->astParent(this);
|
||||||
}
|
}
|
||||||
mImpl->mAstOperand1 = tok;
|
mImpl->mAstOperand1 = tok;
|
||||||
}
|
}
|
||||||
|
@ -1371,11 +1374,11 @@ void Token::astOperand1(Token *tok)
|
||||||
void Token::astOperand2(Token *tok)
|
void Token::astOperand2(Token *tok)
|
||||||
{
|
{
|
||||||
if (mImpl->mAstOperand2)
|
if (mImpl->mAstOperand2)
|
||||||
mImpl->mAstOperand2->mImpl->mAstParent = nullptr;
|
mImpl->mAstOperand2->astParent(nullptr);
|
||||||
// goto parent operator
|
// goto parent operator
|
||||||
if (tok) {
|
if (tok) {
|
||||||
tok = checkAstCycle(tok);
|
tok = tok->astTop();
|
||||||
tok->mImpl->mAstParent = this;
|
tok->astParent(this);
|
||||||
}
|
}
|
||||||
mImpl->mAstOperand2 = tok;
|
mImpl->mAstOperand2 = tok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1278,6 +1278,7 @@ private:
|
||||||
public:
|
public:
|
||||||
void astOperand1(Token *tok);
|
void astOperand1(Token *tok);
|
||||||
void astOperand2(Token *tok);
|
void astOperand2(Token *tok);
|
||||||
|
void astParent(Token* tok);
|
||||||
|
|
||||||
Token * astOperand1() {
|
Token * astOperand1() {
|
||||||
return mImpl->mAstOperand1;
|
return mImpl->mAstOperand1;
|
||||||
|
|
Loading…
Reference in New Issue