package husacct.analyse.task.analyse.csharp.generators;
import husacct.analyse.infrastructure.antlr.csharp.CSharpParser;
import husacct.common.enums.DependencySubTypes;
import org.antlr.runtime.tree.CommonTree;
import org.apache.log4j.Logger;
public class CSharpInvocationGenerator extends CSharpGenerator {
private String from;
private String to = "";
private int lineNumber;
private String belongsToMethod;
private Logger logger = Logger.getLogger(CSharpInvocationGenerator.class);
public CSharpInvocationGenerator(String uniqueClassName) {
from = uniqueClassName;
}
// Is used for call and access; during post-processing, the dependency type is determined.
public void generateConstructorInvocToDomain(CommonTree treeNode, String belongsToMethod) {
this.belongsToMethod = belongsToMethod;
lineNumber = treeNode.getLine();
this.to = "superBaseClass()";
if ((from != null) && (to != null) && !to.equals("") && !SkippableTypes.isSkippable(to)) {
modelService.createMethodInvocation(from, to, lineNumber, belongsToMethod, "InvocConstructor");
}
}
// Is used for call and access; during post-processing, the dependency type is determined.
public void generateMethodInvocToDomain(CommonTree treeNode, String belongsToMethod) {
this.belongsToMethod = belongsToMethod;
lineNumber = treeNode.getLine();
if ((treeNode.getChildCount() > 0)) {
String invocTo = getCompleteToString((CommonTree) treeNode.getChild(0), from, DependencySubTypes.DECL_TYPE_PARAMETER);
this.to = invocTo;
if ((from != null) && (to != null) && !to.equals("") && !SkippableTypes.isSkippable(to)) {
modelService.createMethodInvocation(from, to, lineNumber, belongsToMethod, "InvocMethod");
}
}
}
/* Returns the complete string of an expression of a variable, also in case of chaining call/access combinations.
* In case of a type cast, it does not include the type cast in the returnValue, but it creates a declaration association.
* Use this method to determine the to-string in case in the following cases:
* 1) type declaration of a (local) variable; 2) at both sides of an assignment; 3) at both sides of an comparison.
*/
public String getCompleteToString(CommonTree tree, String belongsToClass, DependencySubTypes dependencySubType) {
/* Test code
if (belongsToClass.contains("CallConstructor_GenericType_MultipleTypeParameters")) {
boolean testPoint = true;
} */
String returnValue = "";
if (tree == null) {
return returnValue;
}
try {
int treeType = tree.getType();
switch(treeType) {
case CSharpParser.MEMBER_ACCESS: case CSharpParser.NAMESPACE_OR_TYPE_NAME: case CSharpParser.NAMESPACE_OR_TYPE_PART: case CSharpParser.SIMPLE_NAME:
boolean isFirstSubString = true;
for (int i = 0; i < tree.getChildCount(); i++) {
String subString= getCompleteToString((CommonTree) tree.getChild(i), belongsToClass, dependencySubType);
if ((subString != null) && !subString.equals("")) {
if (isFirstSubString) {
returnValue += subString;
isFirstSubString = false;
} else {
if (tree.getChild(i).getType() == CSharpParser.TYPE_ARGUMENT_LIST) { // In case of generic classes, add the parameters as <p1>, <p1, p2>, etc.
returnValue += subString;
} else {
returnValue += "." + subString;
}
}
}
}
break;
case CSharpParser.TYPE_ARGUMENT_LIST: // In case of generic classes, add the parameters as <p1>, <p1, p2>, etc.
if (dependencySubType != null) {
addGenericTypeParameters(tree, belongsToClass, dependencySubType);
}
String parameters = "";
int nrOfParameters = tree.getChildCount();
if (nrOfParameters > 0) {
for (int f = 0; f < nrOfParameters; f++) {
String subString= getCompleteToString((CommonTree) tree.getChild(f), belongsToClass, dependencySubType);
if ((subString != null) && subString != null) {
if (f == 0) {
parameters += "p" + 1;
} else {
parameters += ", p" + (f+1);
}
}
}
}
returnValue += "<"+ parameters + ">";
break;
case CSharpParser.ARGUMENT_VALUE: case CSharpParser.UNARY_EXPRESSION: case CSharpParser.TYPE: case CSharpParser.EXPRESSION_STATEMENT: case CSharpParser.VARIABLE_INITIALIZER:
returnValue += getCompleteToString((CommonTree) tree.getChild(0), belongsToClass, dependencySubType);
break;
case CSharpParser.METHOD_INVOCATION:
returnValue += getMethodInvocationString(tree);
break;
case CSharpParser.OBJECT_CREATION_EXPRESSION:
returnValue += getConstructorInvocationString(tree);
break;
case CSharpParser.ARGUMENT:
returnValue += getCompleteToString((CommonTree) tree.getChild(0), belongsToClass, dependencySubType);
createPropertyOrFieldInvocationDomainObject(returnValue, tree.getLine());
break;
case CSharpParser.IDENTIFIER:
returnValue += tree.getText();
break;
case CSharpParser.QUALIFIED_IDENTIFIER: // ? Not encountered within test with Limaki
returnValue = tree.getChild(0).getText();
break;
case CSharpParser.THIS:
returnValue = "";
break;
case CSharpParser.BASE:
returnValue = "superBaseClass";
break;
case CSharpParser.INT: case CSharpParser.INTEGER_LITERAL: case CSharpParser.Decimal_integer_literal: //?
returnValue += "int";
break;
case CSharpParser.STRING_LITERAL: case CSharpParser.STRING:
returnValue += "string";
break;
case CSharpParser.TRUE: case CSharpParser.FALSE: case CSharpParser.BOOL: //?
returnValue += "bool";
break;
case CSharpParser.CHAR:
returnValue += "char";
break;
case CSharpParser.BYTE:
returnValue += "byte";
break;
case CSharpParser.CAST_EXPRESSION: //
returnValue += getCompleteToString((CommonTree) tree.getChild(1), belongsToClass, dependencySubType);
// Create association of typecast-type access
CommonTree typeChild = (CommonTree) tree.getFirstChildWithType(CSharpParser.TYPE);
if (typeChild != null) {
String typeCastTo = getCompleteToString(typeChild, belongsToClass, dependencySubType);
for (int i = 1; i < typeChild.getChildCount(); i++) { // In case of inner classes
typeCastTo = typeCastTo + "." + typeChild.getChild(i).getText();
}
if ((typeCastTo != null) && !typeCastTo.equals("") && !SkippableTypes.isSkippable(typeCastTo)) {
modelService.createDeclarationTypeCast(from, typeCastTo, typeChild.getLine());
}
}
break;
case CSharpParser.DOT: // "."
String left = getCompleteToString((CommonTree) tree.getChild(0), belongsToClass, dependencySubType);
String right = getCompleteToString((CommonTree) tree.getChild(1), belongsToClass, dependencySubType);
if ((left.equals("")) || (right.equals(""))) {
returnValue += left + right;
} else {
returnValue += left + "." + right;
}
break;
}
} catch (Exception e) {
logger.error("Exception: "+ e);
}
return returnValue;
}
private String getMethodInvocationString(CommonTree tree) {
String returnValue = "";
String bodyString = "";
String argumentString = "";
boolean firstArgument = true;
for (int i = 0; i < tree.getChildCount(); i++) {
String argTo = getCompleteToString((CommonTree) tree.getChild(i), from, DependencySubTypes.DECL_TYPE_PARAMETER);
if (tree.getChild(i).getType() != CSharpParser.ARGUMENT) {
if (i == 0) {
bodyString = argTo;
} else {
bodyString = bodyString + "." + argTo;
}
} else {
if (argTo.contains(".") || argTo.contains(",")) { // Currently, arguments with a "." or "," disable the indirect dependency detection algorithm. In case of future improvements: create a FamixArgument object per argument.
argTo = "";
}
if (firstArgument) {
argumentString = argTo;
firstArgument = false;
} else {
argumentString += "," + argTo;
}
}
}
if (!bodyString.equals("")) {
returnValue = bodyString + "(" + argumentString + ")";
}
return returnValue;
}
private String getConstructorInvocationString(CommonTree tree) {
String returnValue = "";
String bodyString = "";
String argumentString = "";
boolean firstArgument = true;
for (int i = 0; i < tree.getChildCount(); i++) {
String subString = getCompleteToString((CommonTree) tree.getChild(i), from, DependencySubTypes.DECL_TYPE_PARAMETER);
if (tree.getChild(i).getType() == CSharpParser.TYPE) {
bodyString = subString;
}
if (tree.getChild(i).getType() == CSharpParser.ARGUMENT) {
if (subString.contains(".") || subString.contains(",")) { // Currently, arguments with a "." or "," disable the indirect dependency detection algorithm. In case of future improvements: create a FamixArgument object per argument.
subString = "";
}
if (firstArgument) {
argumentString = subString;
firstArgument = false;
} else {
argumentString += "," + subString;
}
}
}
if (!bodyString.equals("")) {
returnValue = bodyString + "(" + argumentString + ")";
}
return returnValue;
}
private void createPropertyOrFieldInvocationDomainObject(String invocationTo, int line) {
if ((from != null) && (invocationTo != null) && !invocationTo.equals("") && !SkippableTypes.isSkippable(invocationTo)) {
modelService.createVariableInvocation(from, invocationTo, line, belongsToMethod);
}
}
// Detects generic type parameters, also in complex types, like: HashMap<ProfileDAO, ArrayList<FriendsDAO>>>
private void addGenericTypeParameters(CommonTree genericType, String belongsToClass, DependencySubTypes dependencySubType) {
int numberOfTypeParameters = genericType.getChildCount();
for (int j = 0; j < numberOfTypeParameters; j++) {
CommonTree parameterTypeOfGenericTree = (CommonTree) genericType.getChild(j);
// Check if parameterTypeOfGenericTree contains a generic type arg list. If so, handle it recursively.
CommonTree genericTypeRecursive = CSharpGeneratorToolkit.getFirstDescendantWithType(parameterTypeOfGenericTree, CSharpParser.TYPE_ARGUMENT_LIST);
if (genericTypeRecursive != null) {
addGenericTypeParameters(genericTypeRecursive, belongsToClass, dependencySubType);
} else {
CommonTree qualifiedType = CSharpGeneratorToolkit.getFirstDescendantWithType(parameterTypeOfGenericTree, CSharpParser.NAMESPACE_OR_TYPE_NAME);
if (qualifiedType != null) {
String parameterTypeOfGeneric = getCompleteToString(qualifiedType, from, null); // Last argument = null, since no recursion should take place here.
if ((parameterTypeOfGeneric != null) && (dependencySubType != null)) {
int currentLineNumber = qualifiedType.getLine();
modelService.createTypeParameter(belongsToClass, currentLineNumber, parameterTypeOfGeneric);
}
}
}
}
}
}