<commit_before>package com.incquerylabs.evm.jdt.uml.transformation.rules

import com.incquerylabs.evm.jdt.JDTEventAtom
import com.incquerylabs.evm.jdt.JDTEventSourceSpecification
import com.incquerylabs.evm.jdt.JDTRule
import com.incquerylabs.evm.jdt.fqnutil.JDTQualifiedName
import com.incquerylabs.evm.jdt.fqnutil.UMLQualifiedName
import com.incquerylabs.evm.jdt.job.JDTJobFactory
import com.incquerylabs.evm.jdt.transactions.JDTTransactionalActivationState
import com.incquerylabs.evm.jdt.uml.transformation.rules.filters.CompilationUnitFilter
import com.incquerylabs.evm.jdt.uml.transformation.rules.visitors.CrossReferenceUpdateVisitor
import com.incquerylabs.evm.jdt.uml.transformation.rules.visitors.TypeVisitor
import com.incquerylabs.evm.jdt.umlmanipulator.UMLModelAccess
import java.util.Optional
import org.apache.log4j.Level
import org.apache.log4j.Logger
import org.eclipse.incquery.runtime.evm.api.ActivationLifeCycle
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.IJavaElement
import org.eclipse.jdt.core.IJavaElementDelta
import org.eclipse.jdt.core.IJavaProject
import org.eclipse.jdt.core.IPackageFragment
import org.eclipse.jdt.core.dom.AST
import org.eclipse.jdt.core.dom.ASTNode
import org.eclipse.jdt.core.dom.ASTParser
import org.eclipse.uml2.uml.Class
import org.eclipse.incquery.runtime.evm.specific.job.EnableJob
import org.eclipse.incquery.runtime.evm.specific.Jobs
import org.eclipse.uml2.uml.Operation

class TransactionalCompilationUnitRule extends JDTRule {
	extension Logger logger = Logger.getLogger(this.class)
	extension val UMLModelAccess umlModelAccess
	val TypeVisitor typeVisitor
	val CrossReferenceUpdateVisitor crossReferenceUpdateVisitor
	
	new(JDTEventSourceSpecification eventSourceSpecification, ActivationLifeCycle activationLifeCycle, IJavaProject project, UMLModelAccess umlModelAccess, JDTJobFactory jobFactory) {
		super(eventSourceSpecification, activationLifeCycle, project, jobFactory)
		this.umlModelAccess = umlModelAccess
		this.typeVisitor = new TypeVisitor(umlModelAccess)
		this.crossReferenceUpdateVisitor = new CrossReferenceUpdateVisitor(umlModelAccess)
		this.filter = new CompilationUnitFilter(this.filter)
		this.logger.level = Level.DEBUG
	}
	
	override initialize() {
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.DELETED)[activation, context |
			debug('''Compilation unit is deleted: «activation.atom.element»''')
			try {
				val compilationUnit = activation.atom.element as ICompilationUnit
				compilationUnit.deleteCorrespondingClass
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit''', e)
			}
		]))
		
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.COMMITTED)[activation, context |
			val atom = activation.atom
			debug('''Compilation unit is modified: «activation.atom.element»''')
			try{
				atom.transform
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit''', e)
			}
		]))
		
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.DEPENDENCY_UPDATED)[activation, context |
			val atom = activation.atom
			debug('''Cross references are updated in compilation unit: «activation.atom.element»''')
			try{
				atom.updateCrossReferences
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit cross references''', e)
			}
		]))
	}
	
	def transform(JDTEventAtom atom) {
		val element = atom.element as ICompilationUnit
		val optionalDelta = atom.delta
		var ASTNode ast
		if(!optionalDelta.present) {
			debug('''Delta was not present in the event atom: «element»''')
			ast = element.ast
		} else {
			ast = optionalDelta.map[ delta |
				delta.ast
			].orElseThrow[
				new IllegalStateException('''AST was null, compilation unit is not transformed: «element»''')
			]
		}
		typeVisitor.clearVisitedElements
		ast.accept(typeVisitor)
		
		val visitedElements = typeVisitor.visitedElements
		val visitedClasses = visitedElements.filter(Class)
		val operationsOfVisitedClasses = visitedClasses.map[
			ownedOperations
		].flatten
		val associationsOfVisitedClasses = visitedClasses.map[
			getAssociationsOf(it)
		].flatten
		val operationsToRemove = operationsOfVisitedClasses.filter[
			!visitedElements.contains(it)
		]
		val associationsToRemove = associationsOfVisitedClasses.filter[
			!visitedElements.contains(it)
		]
		operationsToRemove.forEach[
			removeOperation
		]
		associationsToRemove.forEach[
			removeAssociation
		]
		
		return
	}
	
	def deleteCorrespondingClass(ICompilationUnit element) {
		val umlQualifiedName = element.getUmlClassQualifiedName
		val umlClass = findClass(umlQualifiedName)
		umlClass.ifPresent[
			val associations = getAssociationsOf(it)
			associations.forEach[
				removeAssociation
			]
		]
		
		umlClass.ifPresent[
			removeClass
		]
	}
	
	private def getAssociationsOf(Class umlClass) {
		val associations = umlClass.ownedAttributes.map[ attribute |
			Optional::ofNullable(attribute.association)
		].filter[isPresent].map[get]
		
		return associations
	}
	
	def updateCrossReferences(JDTEventAtom atom) {
		val element = atom.element as ICompilationUnit
		val ast = element.ast
		ast.accept(crossReferenceUpdateVisitor)
		return
	}
	
	def getUmlClassQualifiedName(ICompilationUnit compilationUnit) {
		val packageFragment = compilationUnit.parent
		if(!(packageFragment instanceof IPackageFragment)) {
			throw new IllegalArgumentException('''Compilation unit is not in a package: «compilationUnit»''')<commit_msg>Fixed issue with deleting associations<commit_after>package com.incquerylabs.evm.jdt.uml.transformation.rules

import com.google.common.collect.ImmutableList
import com.incquerylabs.evm.jdt.JDTEventAtom
import com.incquerylabs.evm.jdt.JDTEventSourceSpecification
import com.incquerylabs.evm.jdt.JDTRule
import com.incquerylabs.evm.jdt.fqnutil.JDTQualifiedName
import com.incquerylabs.evm.jdt.fqnutil.UMLQualifiedName
import com.incquerylabs.evm.jdt.job.JDTJobFactory
import com.incquerylabs.evm.jdt.transactions.JDTTransactionalActivationState
import com.incquerylabs.evm.jdt.uml.transformation.rules.filters.CompilationUnitFilter
import com.incquerylabs.evm.jdt.uml.transformation.rules.visitors.CrossReferenceUpdateVisitor
import com.incquerylabs.evm.jdt.uml.transformation.rules.visitors.TypeVisitor
import com.incquerylabs.evm.jdt.umlmanipulator.UMLModelAccess
import java.util.Optional
import org.apache.log4j.Level
import org.apache.log4j.Logger
import org.eclipse.incquery.runtime.evm.api.ActivationLifeCycle
import org.eclipse.incquery.runtime.evm.specific.Jobs
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.IJavaElement
import org.eclipse.jdt.core.IJavaElementDelta
import org.eclipse.jdt.core.IJavaProject
import org.eclipse.jdt.core.IPackageFragment
import org.eclipse.jdt.core.dom.AST
import org.eclipse.jdt.core.dom.ASTNode
import org.eclipse.jdt.core.dom.ASTParser
import org.eclipse.uml2.uml.Class

class TransactionalCompilationUnitRule extends JDTRule {
	extension Logger logger = Logger.getLogger(this.class)
	extension val UMLModelAccess umlModelAccess
	val TypeVisitor typeVisitor
	val CrossReferenceUpdateVisitor crossReferenceUpdateVisitor
	
	new(JDTEventSourceSpecification eventSourceSpecification, ActivationLifeCycle activationLifeCycle, IJavaProject project, UMLModelAccess umlModelAccess, JDTJobFactory jobFactory) {
		super(eventSourceSpecification, activationLifeCycle, project, jobFactory)
		this.umlModelAccess = umlModelAccess
		this.typeVisitor = new TypeVisitor(umlModelAccess)
		this.crossReferenceUpdateVisitor = new CrossReferenceUpdateVisitor(umlModelAccess)
		this.filter = new CompilationUnitFilter(this.filter)
		this.logger.level = Level.DEBUG
	}
	
	override initialize() {
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.DELETED)[activation, context |
			debug('''Compilation unit is deleted: «activation.atom.element»''')
			try {
				val compilationUnit = activation.atom.element as ICompilationUnit
				compilationUnit.deleteCorrespondingClass
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit''', e)
			}
		]))
		
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.COMMITTED)[activation, context |
			val atom = activation.atom
			debug('''Compilation unit is modified: «activation.atom.element»''')
			try{
				atom.transform
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit''', e)
			}
		]))
		
		jobs.add(Jobs.newEnableJob(createJob(JDTTransactionalActivationState.DEPENDENCY_UPDATED)[activation, context |
			val atom = activation.atom
			debug('''Cross references are updated in compilation unit: «activation.atom.element»''')
			try{
				atom.updateCrossReferences
			} catch (IllegalArgumentException e) {
				error('''Error during updating compilation unit cross references''', e)
			}
		]))
	}
	
	def transform(JDTEventAtom atom) {
		val element = atom.element as ICompilationUnit
		val optionalDelta = atom.delta
		var ASTNode ast
		if(!optionalDelta.present) {
			debug('''Delta was not present in the event atom: «element»''')
			ast = element.ast
		} else {
			ast = optionalDelta.map[ delta |
				delta.ast
			].orElseThrow[
				new IllegalStateException('''AST was null, compilation unit is not transformed: «element»''')
			]
		}
		typeVisitor.clearVisitedElements
		ast.accept(typeVisitor)
		
		val visitedElements = typeVisitor.visitedElements
		val visitedClasses = visitedElements.filter(Class)
		val operationsOfVisitedClasses = visitedClasses.map[
			ownedOperations
		].flatten
		val associationsOfVisitedClasses = visitedClasses.map[
			getAssociationsOf(it)
		].flatten
		val operationsToRemove = ImmutableList::copyOf(operationsOfVisitedClasses.filter[
			!visitedElements.contains(it)
		])
		val associationsToRemove = ImmutableList::copyOf(associationsOfVisitedClasses.filter[
			!visitedElements.contains(it)
		])
		operationsToRemove.forEach[
			removeOperation
		]
		associationsToRemove.forEach[
			removeAssociation
		]
		
		return
	}
	
	def deleteCorrespondingClass(ICompilationUnit element) {
		val umlQualifiedName = element.getUmlClassQualifiedName
		val umlClass = findClass(umlQualifiedName)
		umlClass.ifPresent[
			val associations = ImmutableList::copyOf(getAssociationsOf(it))
			associations.forEach[
				removeAssociation
			]
		]
		
		umlClass.ifPresent[
			removeClass
		]
	}
	
	private def getAssociationsOf(Class umlClass) {
		val associations = umlClass.ownedAttributes.map[ attribute |
			Optional::ofNullable(attribute.association)
		].filter[isPresent].map[get]
		
		return associations
	}
	
	def updateCrossReferences(JDTEventAtom atom) {
		val element = atom.element as ICompilationUnit
		val ast = element.ast
		ast.accept(crossReferenceUpdateVisitor)
		return
	}
	
	def getUmlClassQualifiedName(ICompilationUnit compilationUnit) {
		val packageFragment = compilationUnit.parent
		if(!(packageFragment instanceof IPackageFragment)) {
			throw new IllegalArgumentException('''Compilation unit is not in a package: «compilationUnit»''')
{'fraction_non_alphanumeric': 0.08723327954097185, 'fraction_numerical': 0.0006275775506544738, 'mean_word_length': 5.470417633410673, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '266173', 'n_tokens_mistral': 3753, 'n_tokens_neox': 3357, 'n_words': 640}