tuna-master/joern/src/main/java/udg/useDefAnalysis/ASTDefUseAnalyzer.java
package udg.useDefAnalysis;

import udg.ASTProvider;
import udg.useDefAnalysis.environments.*;
import udg.useDefGraph.UseOrDef;

import java.util.*;

/**
 * The ASTDefUseAnalyzer determines symbol uses and definitions performed in a
 * given AST. It is currently run on statement ASTs as the core step in the
 * construction of the symbol graph (UDG).
 * */

public class ASTDefUseAnalyzer
{

	Stack<UseDefEnvironment> environmentStack = new Stack<UseDefEnvironment>();
	HashSet<UseOrDef> useDefsOfBlock = new HashSet<UseOrDef>();
	TaintSources taintSources = new TaintSources();

	/**
	 * Analyze an AST to determine the symbols used and defined by each AST
	 * node.
	 * 
	 * */

	public Collection<UseOrDef> analyzeAST(ASTProvider astProvider)
	{
		reset();
		traverseAST(astProvider);
		return useDefsOfBlock;
	}

	/**
	 * Inform the ASTAnalyzer about (callee, argNum)-pairs that define their
	 * arguments. For example, 'recv' defines its first argument.
	 * */

	public void addTaintSource(String callee, int argNum)
	{
		taintSources.add(callee, argNum);
	}

	private void reset()
	{
		environmentStack.clear();
		useDefsOfBlock.clear();
	}

	private void traverseAST(ASTProvider astProvider)
	{
		UseDefEnvironment env = createUseDefEnvironment(astProvider);
		env.setASTProvider(astProvider);
		traverseASTChildren(astProvider, env);
	}

	private void traverseASTChildren(ASTProvider astProvider,
			UseDefEnvironment env)
	{

		int numChildren = astProvider.getChildCount();

		environmentStack.push(env);
		for (int i = 0; i < numChildren; i++)
		{
			ASTProvider childProvider = astProvider.getChild(i);
			traverseAST(childProvider);

			Collection<UseOrDef> toEmit = env
					.useOrDefsFromSymbols(childProvider);
			emitUseOrDefs(toEmit);
		}
		environmentStack.pop();

		reportUpstream(env);
	}

	/**
	 * Creates a UseDefEnvironment for a given AST node.
	 * */

	private UseDefEnvironment createUseDefEnvironment(ASTProvider astProvider)
	{

		String nodeType = astProvider.getTypeAsString();

		switch (nodeType)
		{
			case "AssignmentExpr":
				return new AssignmentEnvironment();
			case "IncDecOp":
				return new IncDecEnvironment();
			case "IdentifierDecl":
			case "Parameter":
				return new DeclEnvironment();

			case "CallExpression":
				return createCallEnvironment(astProvider);

			case "Argument":
				return createArgumentEnvironment(astProvider);

			case "PtrMemberAccess":
				return new PtrMemberAccessEnvironment();

			case "MemberAccess":
				return new MemberAccessEnvironment();

			case "Condition":
			case "ReturnStatement":
				return new UseEnvironment();

			case "ArrayIndexing":
				return new ArrayIndexingEnvironment();

			case "UnaryOp":
				return new UnaryOpEnvironment();
				
			case "Identifier":
				return new IdentifierEnvironment();

			default:
				return new UseDefEnvironment();
		}
	}

	private UseDefEnvironment createCallEnvironment(ASTProvider astProvider)
	{
		CallEnvironment callEnv = new CallEnvironment();
		// inform calls of any arguments it might taint

		String callee = astProvider.getChild(0).getEscapedCodeStr();
		if (taintSources.isTaintSource(callee))
		{
			List<Integer> taintedArgs = taintSources
					.getTaintedArgsForCallee(callee);
			callEnv.setTaintedArgs(taintedArgs);
		}
		return callEnv;
	}

	private ArgumentEnvironment createArgumentEnvironment(
			ASTProvider astProvider)
	{
		ArgumentEnvironment argEnv = new ArgumentEnvironment();
		CallEnvironment callEnv = (CallEnvironment) environmentStack
				.get(environmentStack.size() - 2);

		if (callEnv.isArgumentTainted(astProvider.getChildNumber()))
			argEnv.setIsTainted();

		return argEnv;
	}

	/**
	 * Gets upstream symbols from environment and passes them to
	 * parent-environment by calling addChildSymbols on the parent. Asks
	 * parent-environment to generate useOrDefs and emit them.
	 * */

	private void reportUpstream(UseDefEnvironment env)
	{

		LinkedList<String> symbols = env.upstreamSymbols();
		ASTProvider astProvider = env.getASTProvider();

		try
		{
			UseDefEnvironment parentEnv = environmentStack.peek();
			parentEnv.addChildSymbols(symbols, astProvider);
		}
		catch (EmptyStackException ex)
		{
			// stack is empty, we've reached the root.
			// Nothing to do.
		}
	}

	private void emitUseOrDefs(Collection<UseOrDef> toEmit)
	{
		for (UseOrDef useOrDef : toEmit)
			useDefsOfBlock.add(useOrDef);
	}

}
