package husacct.analyse.task.analyse.java.analysing;
import java.util.List;
import husacct.analyse.task.analyse.VisibilitySet;
import husacct.analyse.task.analyse.java.parsing.JavaParser.AnnotationTypeDeclarationContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.ClassDeclarationContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.ClassOrInterfaceModifierContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.EnumDeclarationContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.InterfaceDeclarationContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.ModifierContext;
import husacct.analyse.task.analyse.java.parsing.JavaParser.TypeDeclarationContext;
import org.antlr.v4.runtime.tree.ParseTree;
class TypeDeclarationAnalyser extends JavaGenerator {
private String name = "";
private String uniqueName = "";
private String belongsToPackage = "";
private String belongsToClass = "";
private boolean isAbstract = false;
private String visibility = "";
private String sourceFilePath = "";
private int nrOfLinesOfCode = 0; // The top level class gets the total nr of lines of code of the file; inner classes zero.
private boolean isNestedClass = false;
private boolean isInterface = false;
private boolean isEnumeration = false;
public TypeDeclarationAnalyser() {
this.sourceFilePath = CompilationUnitAnalyser.getSourceFilePath();
this.belongsToPackage = CompilationUnitAnalyser.getPackage();
}
/**
* To be used for top level type (class, interface, enum or annotation) within the file.
* @param uniquePackageName
* @param typeDeclaration
* @param sourceFilePath
* @param linesOfCode
* @return
*/
public String analyseTypeDeclaration(TypeDeclarationContext typeDeclaration, int linesOfCode) {
this.nrOfLinesOfCode = linesOfCode;
// Determine this.isAbstract and this.visibility
if (typeDeclaration.classOrInterfaceModifier() != null) {
this.visibility = VisibilitySet.DEFAULT.toString();
for (ClassOrInterfaceModifierContext modifier : typeDeclaration.classOrInterfaceModifier()) {
if (VisibilitySet.isValidVisibillity(modifier.getText())) {
this.visibility = modifier.getText();
} else if (modifier.getText().equals("abstract")) {
this.isAbstract = true;
}
}
}
// Delegate specific types
if (typeDeclaration != null) {
if (typeDeclaration.classDeclaration() != null) {
processClassDeclaration(typeDeclaration.classDeclaration());
} else if (typeDeclaration.interfaceDeclaration() != null) {
processInterfaceDeclaration(typeDeclaration.interfaceDeclaration());
} else if (typeDeclaration.enumDeclaration() != null) {
processEnumDeclaration(typeDeclaration.enumDeclaration());
} else if (typeDeclaration.annotationTypeDeclaration() != null) {
processAnnotationTypeDeclaration(typeDeclaration.annotationTypeDeclaration());
isInterface = true; // Annotation is handled as interface
this.name = typeDeclaration.annotationTypeDeclaration().Identifier().getText();
determineUniqueName();
addTypeToModel();
}
}
// Detect and creates Annotation dependencies
if (typeDeclaration.classOrInterfaceModifier() != null) {
for (ClassOrInterfaceModifierContext modifier : typeDeclaration.classOrInterfaceModifier()) {
if (modifier.annotation() != null) {
new AnnotationAnalyser(modifier.annotation(), this.uniqueName);
}
}
}
return uniqueName;
}
private void processClassDeclaration(ClassDeclarationContext classDeclaration){
if (classDeclaration.Identifier() != null) {
this.name = classDeclaration.Identifier().getText();
determineUniqueName();
addTypeToModel();
// Determine extends clause
if (classDeclaration.typeType() != null) {
if(!classDeclaration.typeType().getText().equals("")) {
String from = this.uniqueName;
String to = classDeclaration.typeType().getText();
int lineNumber = classDeclaration.typeType().start.getLine();
if (!SkippedJavaTypes.isSkippable(to)) {
modelService.createInheritanceDefinition(from, to, lineNumber);
}
}
}
// Determine implements clause
if (classDeclaration.typeList() != null) {
for (ParseTree implementsType : classDeclaration.typeList().children) {
String to = implementsType.getText();
if(!implementsType.getText().equals("") && !implementsType.getText().equals(",")) {
String from = this.uniqueName;
int lineNumber = classDeclaration.typeList().start.getLine();
if (!SkippedJavaTypes.isSkippable(to)) {
modelService.createImplementsDefinition(from, to, lineNumber);
}
}
}
}
// Delegate the body
if (classDeclaration.classBody() != null) {
TypeBodyAnalyser typeBodyAnalyser = new TypeBodyAnalyser(uniqueName);
typeBodyAnalyser.analyseClassBody(classDeclaration.classBody());
}
}
}
private void determineUniqueName() {
if (isNestedClass) {
this.uniqueName = belongsToClass + "." + name;
} else {
if (belongsToPackage.equals("")) {
this.uniqueName = name;
} else {
this.uniqueName = belongsToPackage + "." + name;
}
}
}
private void processInterfaceDeclaration(InterfaceDeclarationContext interfaceDeclaration) {
isInterface = true;
this.name = interfaceDeclaration.Identifier().getText();
determineUniqueName();
addTypeToModel();
// Determine extends clause
if (interfaceDeclaration.typeList() != null) {
for (ParseTree extendsType : interfaceDeclaration.typeList().children) {
String to = extendsType.getText();
if(!extendsType.getText().equals("")) {
String from = this.uniqueName;
int lineNumber = interfaceDeclaration.typeList().start.getLine();
if (!SkippedJavaTypes.isSkippable(to)) {
modelService.createInheritanceDefinition(from, to, lineNumber);
}
}
}
}
// Delegate the body
if ( interfaceDeclaration.interfaceBody() != null) {
TypeBodyAnalyser typeBodyAnalyser = new TypeBodyAnalyser(uniqueName);
typeBodyAnalyser.analyseInterfaceBody(interfaceDeclaration.interfaceBody());
}
}
private void processEnumDeclaration(EnumDeclarationContext enumDeclaration) {
isEnumeration = true;
this.name = enumDeclaration.Identifier().getText();
determineUniqueName();
addTypeToModel();
// Determine implements clause
if (enumDeclaration.typeList() != null) {
for (ParseTree implementsType : enumDeclaration.typeList().children) {
String to = implementsType.getText();
if(!implementsType.getText().equals("")) {
String from = this.uniqueName;
int lineNumber = enumDeclaration.typeList().start.getLine();
if (!SkippedJavaTypes.isSkippable(to)) {
modelService.createImplementsDefinition(from, to, lineNumber);
}
}
}
}
// Delegate the body
if ( enumDeclaration.enumBodyDeclarations() != null) {
TypeBodyAnalyser typeBodyAnalyser = new TypeBodyAnalyser(uniqueName);
typeBodyAnalyser.analyseEnumBody(enumDeclaration.enumConstants(), enumDeclaration.enumBodyDeclarations());
}
}
private void processAnnotationTypeDeclaration(AnnotationTypeDeclarationContext annotationTypeDeclaration) {
isInterface = true; // Annotation is handled as interface
this.name = annotationTypeDeclaration.Identifier().getText();
determineUniqueName();
addTypeToModel();
// Delegate the body
if ( annotationTypeDeclaration.annotationTypeBody() != null) {
TypeBodyAnalyser typeBodyAnalyser = new TypeBodyAnalyser(uniqueName);
typeBodyAnalyser.analyseAnnotationBody(annotationTypeDeclaration.annotationTypeBody());
}
}
/**
* @param typeDeclaration
* @param parentClassName
*/
public void analyseNestedTypeDeclaration(TypeDeclarationContext typeDeclaration, String parentClassName) {
this.isNestedClass = true;
this.belongsToClass = parentClassName;
analyseTypeDeclaration(typeDeclaration, 0);
}
/**
* @param modifierList
* @param classDeclaration
* @param parentClassName
*/
public void analyseNestedClassDeclaration(List<ModifierContext> modifierList, ClassDeclarationContext classDeclaration, String parentClassName) {
this.isNestedClass = true;
this.belongsToClass = parentClassName;
this.visibility = determineVisibility(modifierList);
this.isAbstract = determineIsAbstract(modifierList);
if (classDeclaration != null) {
processClassDeclaration(classDeclaration);
}
}
/**
* To be used for nested interface.
* @param modifierList
* @param interfaceDeclaration
* @param parentClassName
*/
public void analyseNestedInterfaceDeclaration(List<ModifierContext> modifierList, InterfaceDeclarationContext interfaceDeclaration, String parentClassName) {
this.isNestedClass = true;
this.belongsToClass = parentClassName;
this.visibility = determineVisibility(modifierList);
this.isAbstract = determineIsAbstract(modifierList);
if (interfaceDeclaration != null) {
processInterfaceDeclaration(interfaceDeclaration);
}
}
/**
* @param modifierList
* @param enumDeclaration
* @param parentClassName
*/
public void analyseNestedEnumDeclaration(List<ModifierContext> modifierList, EnumDeclarationContext enumDeclaration, String parentClassName) {
this.isNestedClass = true;
this.belongsToClass = parentClassName;
this.visibility = determineVisibility(modifierList);
this.isAbstract = determineIsAbstract(modifierList);
if (enumDeclaration != null) {
processEnumDeclaration(enumDeclaration);
}
}
/**
* @param modifierList
* @param annotationTypeDeclaration
* @param parentClassName
*/
public void analyseNestedAnnotationTypeDeclaration(List<ModifierContext> modifierList, AnnotationTypeDeclarationContext annotationTypeDeclaration, String parentClassName) {
this.isNestedClass = true;
this.belongsToClass = parentClassName;
this.visibility = determineVisibility(modifierList);
this.isAbstract = determineIsAbstract(modifierList);
if (annotationTypeDeclaration != null) {
processAnnotationTypeDeclaration(annotationTypeDeclaration);
}
}
private void addTypeToModel() {
if (!name.equals("") && !belongsToPackage.equals("")) {
modelService.createClass(this.sourceFilePath, this.nrOfLinesOfCode, uniqueName, name, belongsToPackage, isAbstract, isNestedClass, belongsToClass, visibility, isInterface, isEnumeration);
}
}
}