blob: c09780dd92d58a1b4a01f0f5da9c24949203576c [file] [log] [blame]
//
// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/DetectRecursion.h"
DetectRecursion::FunctionNode::FunctionNode(const TString& fname)
: name(fname),
visit(PreVisit)
{
}
const TString& DetectRecursion::FunctionNode::getName() const
{
return name;
}
void DetectRecursion::FunctionNode::addCallee(
DetectRecursion::FunctionNode* callee)
{
for (size_t i = 0; i < callees.size(); ++i) {
if (callees[i] == callee)
return;
}
callees.push_back(callee);
}
bool DetectRecursion::FunctionNode::detectRecursion()
{
ASSERT(visit == PreVisit);
visit = InVisit;
for (size_t i = 0; i < callees.size(); ++i) {
switch (callees[i]->visit) {
case InVisit:
// cycle detected, i.e., recursion detected.
return true;
case PostVisit:
break;
case PreVisit: {
bool recursion = callees[i]->detectRecursion();
if (recursion)
return true;
break;
}
default:
UNREACHABLE();
break;
}
}
visit = PostVisit;
return false;
}
DetectRecursion::DetectRecursion()
: currentFunction(NULL)
{
}
DetectRecursion::~DetectRecursion()
{
for (size_t i = 0; i < functions.size(); ++i)
delete functions[i];
}
bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node)
{
switch (node->getOp())
{
case EOpPrototype:
// Function declaration.
// Don't add FunctionNode here because node->getName() is the
// unmangled function name.
break;
case EOpFunction: {
// Function definition.
if (visit == PreVisit) {
currentFunction = findFunctionByName(node->getName());
if (currentFunction == NULL) {
currentFunction = new FunctionNode(node->getName());
functions.push_back(currentFunction);
}
}
break;
}
case EOpFunctionCall: {
// Function call.
if (visit == PreVisit) {
ASSERT(currentFunction != NULL);
FunctionNode* func = findFunctionByName(node->getName());
if (func == NULL) {
func = new FunctionNode(node->getName());
functions.push_back(func);
}
currentFunction->addCallee(func);
}
break;
}
default:
break;
}
return true;
}
DetectRecursion::ErrorCode DetectRecursion::detectRecursion()
{
FunctionNode* main = findFunctionByName("main(");
if (main == NULL)
return kErrorMissingMain;
if (main->detectRecursion())
return kErrorRecursion;
return kErrorNone;
}
DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName(
const TString& name)
{
for (size_t i = 0; i < functions.size(); ++i) {
if (functions[i]->getName() == name)
return functions[i];
}
return NULL;
}