package husacct.analyse.task.analyse.java.analysing; import java.util.ArrayList; import java.util.List; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.log4j.Logger; import husacct.analyse.task.analyse.java.parsing.JavaParser.CreatorContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.ExplicitGenericInvocationContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.ExplicitGenericInvocationSuffixContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.ExpressionContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.ExpressionListContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.FormalParameterContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.InnerCreatorContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.LambdaExpressionContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.LastFormalParameterContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.PrimaryContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.SuperSuffixContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.TypeArgumentsContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.TypeArgumentsOrDiamondContext; import husacct.analyse.task.analyse.java.parsing.JavaParser.TypeTypeContext; import husacct.common.enums.DependencySubTypes; public class ExpressionAnalyser extends JavaGenerator{ /* Functionality: * - Transforms expression in text (expressionText) * - Creates dependencies on arguments * - Creates dependencies on typeArguments * - Nullifies arguments with "."or "'" * - Removes type cast from expressionText * - Replaces "super" by "superBaseClass" */ private static final String superReplacement = "superBaseClass"; // Variables to create associations on arguments private String belongsToClass; private String to = ""; private int lineNumber; private String belongsToMethod; private Logger logger = Logger.getLogger(ExpressionAnalyser.class); public ExpressionAnalyser(String uniqueClassName, String belongsToMethod, ExpressionContext mainExpression) { this.belongsToClass = uniqueClassName; this.belongsToMethod = belongsToMethod; analyseExpression(mainExpression); } // Analyses an ExpressionContext; based on the definition of "expression" in Java7.g4. private void analyseExpression(ExpressionContext mainExpression) { try { if (mainExpression != null) { //String expressionText1 = mainExpression.getText(); if (mainExpression.primary() != null) { if (mainExpression.primary().expression() != null) { analyseExpression(mainExpression.primary().expression()); } else if (mainExpression.primary().Identifier() != null) { analyseElementaryExpression(mainExpression); } else if (mainExpression.primary().arrayType() != null) { analyseElementaryExpression(mainExpression); } else if (mainExpression.primary().literal() != null) { analyseElementaryExpression(mainExpression); } else if (mainExpression.primary().typeType() != null) { analyseElementaryExpression(mainExpression); } } else if (mainExpression.lambdaExpression() != null) { analyseLambdaExpression(mainExpression.lambdaExpression()); } else if ((mainExpression.expression() != null ) && !mainExpression.expression().isEmpty()) { List<ExpressionContext> expressions = mainExpression.expression(); int nrOfExpressions = expressions.size(); if (nrOfExpressions == 1) { analyseElementaryExpression(mainExpression); } else if (nrOfExpressions >= 2 ) { if (mainExpression.getChild(1).getText().equals("[")) { analyseElementaryExpression(mainExpression); } else { for (ExpressionContext expression : expressions) { analyseElementaryExpression(expression); } } } } else if (mainExpression.creator() != null) { this.to = analyseCreator(mainExpression.creator()); this.lineNumber = mainExpression.creator().start.getLine(); addAssociationToModel(); } else { // Should not be possible, based on the grammar. logger.warn(" Unexpected value in: " + belongsToClass + " Line: " + mainExpression.start.getLine()); } } } catch (Exception e) { logger.warn(" Exception while processing: " + belongsToClass + " " + e.getCause().toString()); } } private void analyseElementaryExpression(ExpressionContext expression) { /* Test helper String expressionText2 = expression.getText(); String to_string = this.to; if (belongsToClass.equals("net.sf.jabref.preferences.CustomImportList") && (expression.start.getLine() == 74)) { boolean breakpoint = true; } */ this.to = transformExpressionToString(expression); this.lineNumber = expression.getStart().getLine(); addAssociationToModel(); } /* Builds up a string, based on the values of the children. * If subexpressions are contained, only the first one is transformed to text and included. * Following subexpressions are processed as individual expressions. */ private String transformExpressionToString(ExpressionContext expression) { String to_string = ""; List<ExpressionContext> subExpressions = expression.expression(); int nrOfSubExpressions = subExpressions.size(); if (nrOfSubExpressions == 0) { if (expression.primary() != null) { PrimaryContext primary = expression.primary(); if (primary.expression() != null) { to_string += transformExpressionToString(primary.expression()); } else if (primary.Identifier() != null) { to_string += primary.getText(); } else if (primary.arrayType() != null) { if (primary.arrayType().Identifier() != null) { to_string += primary.arrayType().Identifier().getText(); } else if (primary.arrayType().classOrInterfaceType() != null) { to_string += primary.arrayType().classOrInterfaceType().getText(); } } else if (primary.literal() != null) { if (primary.literal().IntegerLiteral() != null) { to_string += "int"; } else if (primary.literal().FloatingPointLiteral() != null) { to_string += "float"; } else if (primary.literal().CharacterLiteral() != null) { to_string += "char"; } else if (primary.literal().StringLiteral() != null) { to_string += "String"; } else if (primary.literal().BooleanLiteral() != null) { to_string += "boolean"; } } else if (primary.typeType() != null) { to_string += primary.getText(); } else if (primary.getText().equals("super")) { to_string += superReplacement; } } else if (expression.creator() != null) { to_string += analyseCreator(expression.creator()); } } else if (nrOfSubExpressions == 1 ) { to_string += transformSingularExpressionToString(expression); } else if (nrOfSubExpressions >= 2 ) { to_string += transformSingularExpressionToString(expression.expression(0)); for (int i = 1 ; i < nrOfSubExpressions ; i++) { analyseElementaryExpression(expression.expression(i)); } } return to_string; } /* Transforms the expression into a string of useful information for the post processor. * Precondition (taken care of in previous step): There is exactly one child-expression. * Consequently, only these sub-compositions in the definition of "expression"need to be handled. * Basically, all children are included in the resulting string. However not in case of: * 1) a type cast. * 2) an instanceof statement. * 3) an argument that includes "." or ",". */ private String transformSingularExpressionToString(ExpressionContext expression) { // String testString = expression.getText(); String to_string = ""; int childCount = expression.getChildCount(); ExpressionContext subExpression = expression.expression(0); if (childCount == 2) { // In case of subExpression with prefix or postfix text ('!'|'+'|'++', ...) to_string += transformExpressionToString(subExpression); } if (expression.typeType() != null) { if (expression.getChild(0).equals("(")) { // type cast analyseTypeCast(expression.typeType(), DependencySubTypes.REF_TYPE_CAST); } else { // expression instanceof typeType analyseTypeCast(expression.typeType(), DependencySubTypes.REF_TYPE); } to_string += transformExpressionToString(subExpression); } else if ((childCount >= 3) && expression.getChild(childCount - 1).getText().equals(")")) { // Call if ((expression.expressionList() != null)) { // List of arguments String expressionListText = analyseExpressionList(expression.expressionList()); to_string += transformExpressionToString(subExpression) + "(" + expressionListText + ")"; } else if (expression.getChild(childCount - 2).getText().equals("(")) { to_string += transformExpressionToString(subExpression) + "(" + ")"; } else { to_string += transformExpressionToString(subExpression); } } else if (expression.Identifier() != null) { if (expression.Identifier().getText().equals("")) { to_string += transformExpressionToString(subExpression); } else { to_string += transformExpressionToString(subExpression) + "." + expression.Identifier().getText(); } } else if (expression.innerCreator() != null){ to_string += transformExpressionToString(subExpression); String constructorString = analyseInnerCreator(expression.innerCreator()); if (!constructorString.equals("")) { to_string += "." + constructorString; } } else if (expression.superSuffix() != null) { to_string += transformExpressionToString(subExpression); String superSuffixString = analyseSuperSuffix(expression.superSuffix()); if (!superSuffixString.equals("")) { to_string += "." + superReplacement + superSuffixString; } } else if ( expression.explicitGenericInvocation() != null) { to_string += transformExpressionToString(subExpression); String explicitGenericInvString = analyseExplicitGenericInvocation(expression.explicitGenericInvocation()); if (!explicitGenericInvString.equals("")) { to_string += "." + explicitGenericInvString; } } return to_string; } private void addAssociationToModel() { if ((to != null) && !to.trim().equals("") && !SkippedJavaTypes.isSkippable(to)) { modelService.createVariableInvocation(belongsToClass, to, lineNumber, belongsToMethod); } to = ""; lineNumber = 0; } private void analyseLambdaExpression(LambdaExpressionContext lambdaExpression){ if(lambdaExpression.lambdaParameters() != null) { if(lambdaExpression.lambdaParameters().Identifier() != null) { this.to = lambdaExpression.lambdaParameters().Identifier().getText(); this.lineNumber = lambdaExpression.getStart().getLine(); addAssociationToModel(); }else if(lambdaExpression.lambdaParameters().formalParameterList() != null) { if (lambdaExpression.lambdaParameters().formalParameterList().formalParameter() != null) { for (FormalParameterContext parameter : lambdaExpression.lambdaParameters().formalParameterList().formalParameter()) { this.lineNumber = parameter.getStart().getLine(); if (parameter.variableDeclaratorId() != null && parameter.variableDeclaratorId().Identifier() != null) { this.to = parameter.variableDeclaratorId().Identifier().getText(); addAssociationToModel(); } if (parameter.typeType() != null) { this.to = determineTypeOfTypeType(parameter.typeType(), belongsToClass); addAssociationToModel(); } } } if (lambdaExpression.lambdaParameters().formalParameterList().lastFormalParameter() != null) { LastFormalParameterContext parameter = lambdaExpression.lambdaParameters().formalParameterList().lastFormalParameter(); this.lineNumber = parameter.getStart().getLine(); if (parameter.variableDeclaratorId() != null && parameter.variableDeclaratorId().Identifier() != null) { this.to = parameter.variableDeclaratorId().Identifier().getText(); addAssociationToModel(); } if (parameter.typeType() != null) { this.to = determineTypeOfTypeType(parameter.typeType(), belongsToClass); addAssociationToModel(); } } } else if (lambdaExpression.lambdaParameters().inferredFormalParameterList() != null) { if (lambdaExpression.lambdaParameters().inferredFormalParameterList().Identifier() != null) { for (TerminalNode identifier : lambdaExpression.lambdaParameters().inferredFormalParameterList().Identifier()) { this.lineNumber = lambdaExpression.lambdaParameters().inferredFormalParameterList().start.getLine(); this.to = identifier.getText(); addAssociationToModel(); } } } } if(lambdaExpression.lambdaBody() != null) { if(lambdaExpression.lambdaBody().expression() != null) { analyseElementaryExpression(lambdaExpression.lambdaBody().expression()); } else if(lambdaExpression.lambdaBody().block() != null) { new BlockAnalyser(lambdaExpression.lambdaBody().block(), this.belongsToClass, this.belongsToMethod); } } } private void analyseTypeCast(TypeTypeContext typeType, DependencySubTypes dependencySubType) { String typeCastTo = ""; if (typeType != null) { typeCastTo = determineTypeOfTypeType(typeType, belongsToClass); if ((typeCastTo != null) && !typeCastTo.equals("") && !SkippedJavaTypes.isSkippable(typeCastTo)) { modelService.createDeclarationTypeCast(belongsToClass, typeCastTo, typeType.start.getLine()); } } } private String analyseExpressionList(ExpressionListContext expressionList) { // Argument list without () String returnString = ""; if ((expressionList.expression() != null) && !expressionList.expression().isEmpty()) { for(int i = 0 ; i < expressionList.expression().size() ; i++) { ExpressionContext expression = expressionList.expression(i); String argumentText = ""; /* if ((expression.expressionList() != null) && !expression.expressionList().isEmpty()) { argumentText = transformSingularExpressionToString(expression); } else { argumentText = expression.getText(); } */ argumentText = transformExpressionToString(expression); int lineOfArgument = expression.start.getLine(); createDependencyOnArgument(argumentText, lineOfArgument); //Nullify the arguments in the method signature, if needed. Currently, arguments with a "." or "," disable the indirect dependency detection algorithm. In case of future improvements: create a FamixArgument object per argument. if (argumentText.contains(".") || argumentText.contains(",")) { if (i == 0) { returnString = ""; // No change } else { returnString += "," + ""; } } else { if (i == 0) { returnString = argumentText; } else { returnString += "," + argumentText; } } } } return returnString; } private String analyseCreator(CreatorContext creator) { String creatorString = ""; String name = ""; if (creator.createdName() != null) { if (creator.createdName().primitiveType() != null) { name = creator.createdName().getText(); } else { name = transformIdentifierToString(creator.createdName().Identifier()); } if (creator.createdName().typeArgumentsOrDiamond() != null) { for (TypeArgumentsOrDiamondContext typeArgumentsOrDiamond : creator.createdName().typeArgumentsOrDiamond()) { if ((typeArgumentsOrDiamond.typeArguments() != null) && (typeArgumentsOrDiamond.typeArguments().typeArgument() != null)) { List<TypeArgumentsContext> typeArgumentsList = new ArrayList<>(); typeArgumentsList.add(typeArgumentsOrDiamond.typeArguments()); analyseTypeArguments(belongsToClass, typeArgumentsList); } } } } String argumentsString = "()"; if (creator.classCreatorRest() != null) { if (creator.classCreatorRest().arguments() != null) { if (creator.classCreatorRest().arguments().expressionList() != null) { argumentsString = "(" + analyseExpressionList(creator.classCreatorRest().arguments().expressionList()) + ")"; } } if (creator.classCreatorRest().classBody() != null) { new TypeBodyAnalyser(belongsToClass).analyseClassBody(creator.classCreatorRest().classBody());; } } creatorString = name + argumentsString; return creatorString; } private String analyseInnerCreator(InnerCreatorContext creator) { String creatorString = ""; String name = ""; if (creator.Identifier() != null) { name = creator.Identifier().getText(); } String argumentsString = "()"; if (creator.classCreatorRest() != null) { if (creator.classCreatorRest().arguments() != null) { if (creator.classCreatorRest().arguments().expressionList() != null) { argumentsString = "(" + analyseExpressionList(creator.classCreatorRest().arguments().expressionList()) + ")"; } } if (creator.classCreatorRest().classBody() != null) { new TypeBodyAnalyser(belongsToClass).analyseClassBody(creator.classCreatorRest().classBody()); } } creatorString = name + argumentsString; return creatorString; } private String analyseSuperSuffix(SuperSuffixContext superSuffix) { String superSuffixString = ""; String argumentsString = "()"; if (superSuffix.arguments() != null) { if (superSuffix.arguments().expressionList() != null) { argumentsString = "(" + analyseExpressionList(superSuffix.arguments().expressionList()) + ")"; } } String name = ""; if (superSuffix.Identifier() != null) { name = superSuffix.Identifier().getText(); } if (!name.equals("")) { superSuffixString = "."+ name + argumentsString; } else { superSuffixString = argumentsString; } return superSuffixString; } private String analyseExplicitGenericInvocation(ExplicitGenericInvocationContext explicitGenericInvocation) { String explicitGenericInvocationString = ""; if (explicitGenericInvocation.explicitGenericInvocationSuffix() != null) { ExplicitGenericInvocationSuffixContext suffix = explicitGenericInvocation.explicitGenericInvocationSuffix(); if (suffix.superSuffix() != null) { explicitGenericInvocationString = superReplacement + analyseSuperSuffix(suffix.superSuffix()); } else if (suffix.Identifier() != null) { String name = suffix.Identifier().getText(); String argumentsString = "()"; if ((suffix.arguments() != null) && (suffix.arguments().expressionList() != null)) { argumentsString = "(" + analyseExpressionList(suffix.arguments().expressionList()) + ")"; } if ((name != null) && !name.equals("")) { explicitGenericInvocationString = name + argumentsString; } } } return explicitGenericInvocationString; } private void createDependencyOnArgument(String argument, int lineOfArgument) { if ((argument != null) && !argument.trim().equals("") && !SkippedJavaTypes.isSkippable(argument)) { modelService.createVariableInvocation(belongsToClass, argument, lineOfArgument, belongsToMethod); } } }