All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edelta.refactorings.lib.EdeltaBadSmellsFinder Maven / Gradle / Ivy

The newest version!
package edelta.refactorings.lib;

import com.google.common.collect.Iterables;
import edelta.lib.EdeltaDefaultRuntime;
import edelta.lib.EdeltaRuntime;
import edelta.lib.EdeltaUtils;
import edelta.refactorings.lib.helper.EdeltaFeatureEqualityHelper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ListExtensions;
import org.eclipse.xtext.xbase.lib.MapExtensions;
import org.eclipse.xtext.xbase.lib.Pair;

@SuppressWarnings("all")
public class EdeltaBadSmellsFinder extends EdeltaDefaultRuntime {
  public EdeltaBadSmellsFinder(final EdeltaRuntime other) {
    super(other);
  }

  /**
   * Finds all the features that are structurally equal
   * in the given {@link EPackage}.
   * 
   * Note that this takes into consideration the name and type,
   * but also other properties like lowerBound, unique, etc.
   * 
   * For example, given these EClasses
   * 
   * 
   * C1 {
   *   A1 : EString
   * }
   * 
   * C2 {
   *   A1 : EString
   * }
   * 
* * It returns the map with this entry * *
   * (A1 : EString) -> [ C1:A1, C2:A1 ]
   * 
* * @param ePackage */ public Map> findDuplicatedFeatures(final EPackage ePackage) { final BiPredicate _function = (EStructuralFeature existing, EStructuralFeature current) -> { return new EdeltaFeatureEqualityHelper().equals(existing, current); }; return this.findDuplicatedFeaturesCustom(ePackage, _function); } /** * Allows you to specify the lambda checking for equality of features. * * @param ePackage * @param matcher */ public Map> findDuplicatedFeaturesCustom(final EPackage ePackage, final BiPredicate matcher) { final List allFeatures = EdeltaUtils.allEStructuralFeatures(ePackage); final Map> result = this.findDuplicatedFeaturesInCollection(allFeatures, matcher); final Consumer>> _function = (Map.Entry> it) -> { final Supplier _function_1 = () -> { final Function1 _function_2 = (EStructuralFeature it_1) -> { return EdeltaUtils.getEObjectRepr(it_1); }; String _join = IterableExtensions.join(ListExtensions.map(it.getValue(), _function_2), ", "); return ("Duplicate features: " + _join); }; this.logInfo(_function_1); }; result.entrySet().forEach(_function); return result; } /** * Finds all the features that are structurally equal * in the given collection. * * Note that this takes into consideration the name and type, * but also other properties like lowerBound, unique, etc. * * For example, given these EClasses * *
   * C1 {
   *   A1 : EString
   * }
   * 
   * C2 {
   *   A1 : EString
   * }
   * 
* * And the collection of features [ C1:A1, C2:A1 ] * it returns the map with this entry * *
   * (A1 : EString) -> [ C1:A1, C2:A1 ]
   * 
* * It allows you to specify the lambda checking for equality of features. * * @param features * @param matcher */ public Map> findDuplicatedFeaturesInCollection(final Collection features, final BiPredicate matcher) { final LinkedHashMap> map = CollectionLiterals.>newLinkedHashMap(); for (final EStructuralFeature f : features) { { final Function1>, Boolean> _function = (Map.Entry> it) -> { return Boolean.valueOf(matcher.test(it.getKey(), f)); }; final Map.Entry> existing = IterableExtensions.>>findFirst(map.entrySet(), _function); if ((existing != null)) { List _value = existing.getValue(); _value.add(f); } else { map.put(f, CollectionLiterals.newArrayList(f)); } } } final Function2, Boolean> _function = (EStructuralFeature key, List values) -> { int _size = values.size(); return Boolean.valueOf((_size > 1)); }; return MapExtensions.>filter(map, _function); } /** * If a class has more than one direct subclass, it finds duplicate features in all * of its direct subclasses. * * Returns a map where the key is the class with more than one direct subclass * with duplicate features; the value is another map as returned by * {@link #findDuplicatedFeaturesInCollection(Collection, BiPredicate)} */ public LinkedHashMap>> findDuplicatedFeaturesInSubclasses(final EPackage ePackage) { final LinkedHashMap>> map = CollectionLiterals.>>newLinkedHashMap(); List _allEClasses = EdeltaUtils.allEClasses(ePackage); for (final EClass c : _allEClasses) { { final Iterable directSubclasses = this.directSubclasses(c); final int numOfSubclasses = IterableExtensions.size(directSubclasses); if ((numOfSubclasses > 1)) { final Function1> _function = (EClass it) -> { return it.getEStructuralFeatures(); }; final BiPredicate _function_1 = (EStructuralFeature existing, EStructuralFeature current) -> { return new EdeltaFeatureEqualityHelper().equals(existing, current); }; final Map> candidates = this.findDuplicatedFeaturesInCollection( IterableExtensions.toList(Iterables.concat(IterableExtensions.>map(directSubclasses, _function))), _function_1); final Function2, Boolean> _function_2 = (EStructuralFeature key, List values) -> { int _size = values.size(); return Boolean.valueOf((_size == numOfSubclasses)); }; final Map> duplicates = MapExtensions.>filter(candidates, _function_2); boolean _isEmpty = duplicates.isEmpty(); boolean _not = (!_isEmpty); if (_not) { map.put(c, duplicates); final Consumer>> _function_3 = (Map.Entry> it) -> { final Supplier _function_4 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(c); String _plus = ("In subclasses of " + _eObjectRepr); String _plus_1 = (_plus + ", duplicate features: "); final Function1 _function_5 = (EStructuralFeature it_1) -> { return EdeltaUtils.getEObjectRepr(it_1); }; String _join = IterableExtensions.join(ListExtensions.map(it.getValue(), _function_5), ", "); return (_plus_1 + _join); }; this.logInfo(_function_4); }; duplicates.entrySet().forEach(_function_3); } } } } return map; } /** * Finds all the features corresponding to a redundant container, * that is, a missed opposite reference to the container. * * The result consists of an iterable of pairs where the key * is the reference corresponding to the redundant container * and the value is the reference that should correspond to the * opposite reference. * * For example, if "Bank" has a containment feature "clients", * and the "Client" has a non-containment feature "bank", which * is not set as the opposite of "clients", then the detected * redundant container will be the pair "Client:bank" -> "Bank:clients". * * This form should make the corresponding refactoring trivial to * implement, since all the information are in the pair. */ public Iterable> findRedundantContainers(final EPackage ePackage) { final Function1>> _function = (EClass it) -> { return this.findRedundantContainers(it); }; return Iterables.>concat(ListExtensions.>>map(EdeltaUtils.allEClasses(ePackage), _function)); } /** * see {@link #findRedundantContainers(EPackage)} */ public ArrayList> findRedundantContainers(final EClass cl) { final ArrayList> redundantContainers = CollectionLiterals.>newArrayList(); final Function1 _function = (EReference it) -> { return Boolean.valueOf(it.isContainment()); }; final Iterable containmentReferences = IterableExtensions.filter(cl.getEReferences(), _function); for (final EReference containmentReference : containmentReferences) { { final Function1 _function_1 = (EReference it) -> { return Boolean.valueOf(((((!it.isContainment()) && it.isRequired()) && (it.getEOpposite() == null)) && (it.getEReferenceType() == cl))); }; final EReference redundant = IterableExtensions.head(IterableExtensions.filter(containmentReference.getEReferenceType().getEReferences(), _function_1)); if ((redundant != null)) { Pair _mappedTo = Pair.of(redundant, containmentReference); redundantContainers.add(_mappedTo); final Supplier _function_2 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(containmentReference); String _plus = ("Redundant container: " + _eObjectRepr); String _plus_1 = (_plus + " -> "); String _eObjectRepr_1 = EdeltaUtils.getEObjectRepr(redundant); return (_plus_1 + _eObjectRepr_1); }; this.logInfo(_function_2); } } } return redundantContainers; } /** * see {@link #isDeadClassifier(EClassifier)} */ public List findDeadClassifiers(final EPackage ePackage) { final Function1 _function = (EClassifier it) -> { return Boolean.valueOf(this.isDeadClassifier(it)); }; return IterableExtensions.toList(IterableExtensions.filter(ePackage.getEClassifiers(), _function)); } /** * Whether {@link #doesNotReferToClasses(EClassifier)} and * {@link #isNotReferredByClassifiers(EClassifier)} */ public boolean isDeadClassifier(final EClassifier cl) { final boolean result = (this.doesNotReferToClasses(cl) && this.isNotReferredByClassifiers(cl)); if (result) { final Supplier _function = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(cl); return ("Dead classifier: " + _eObjectRepr); }; this.logInfo(_function); } return result; } /** * Whether the passed EClassifier does not refer to any EClass */ public boolean doesNotReferToClasses(final EClassifier c) { return IterableExtensions.isEmpty(Iterables.filter(EcoreUtil.CrossReferencer.find(CollectionLiterals.newArrayList(c)).keySet(), EClass.class)); } /** * Whether the passed EClassifier is not referred by EClassifiers. */ public boolean isNotReferredByClassifiers(final EClassifier cl) { return EcoreUtil.UsageCrossReferencer.find(cl, EdeltaUtils.packagesToInspect(cl)).isEmpty(); } /** * Returns a map where the key is an EClass (superclass) * and the associated value is a list of subclasses that are * considered matching the "classification by hierarchy" bad smell. */ public Map> findClassificationByHierarchy(final EPackage ePackage) { final Function1 _function = (EClass it) -> { return Boolean.valueOf((((it.getESuperTypes().size() == 1) && it.getEStructuralFeatures().isEmpty()) && this.isNotReferredByClassifiers(it))); }; final Function1 _function_1 = (EClass it) -> { return IterableExtensions.head(it.getESuperTypes()); }; final Function2, Boolean> _function_2 = (EClass base, List subclasses) -> { int _size = subclasses.size(); return Boolean.valueOf((_size > 1)); }; final Map> classification = MapExtensions.>filter(IterableExtensions.groupBy(IterableExtensions.filter(EdeltaUtils.allEClasses(ePackage), _function), _function_1), _function_2); final Consumer>> _function_3 = (Map.Entry> it) -> { final Supplier _function_4 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(it.getKey()); String _plus = ("Classification by hierarchy: " + _eObjectRepr); String _plus_1 = (_plus + " - "); String _plus_2 = (_plus_1 + "subclasses["); final Function1 _function_5 = (EClass it_1) -> { return EdeltaUtils.getEObjectRepr(it_1); }; String _join = IterableExtensions.join(ListExtensions.map(it.getValue(), _function_5), ","); String _plus_3 = (_plus_2 + _join); return (_plus_3 + "]"); }; this.logInfo(_function_4); }; classification.entrySet().forEach(_function_3); return classification; } /** * Finds base classes that should be set as abstract, * since they have subclasses. */ public Iterable findConcreteAbstractMetaclasses(final EPackage ePackage) { final Function1 _function = (EClass cl) -> { return Boolean.valueOf(((!cl.isAbstract()) && this.hasSubclasses(cl))); }; final Iterable classes = IterableExtensions.filter(EdeltaUtils.allEClasses(ePackage), _function); final Consumer _function_1 = (EClass it) -> { final Supplier _function_2 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(it); return ("Concrete abstract class: " + _eObjectRepr); }; this.logInfo(_function_2); }; classes.forEach(_function_1); return classes; } public boolean hasSubclasses(final EClass cl) { boolean _isEmpty = IterableExtensions.isEmpty(this.directSubclasses(cl)); return (!_isEmpty); } public Iterable directSubclasses(final EClass cl) { final Function1 _function = (EStructuralFeature.Setting it) -> { EStructuralFeature _eStructuralFeature = it.getEStructuralFeature(); return Boolean.valueOf((_eStructuralFeature == getEReference("ecore", "EClass", "eSuperTypes"))); }; final Function1 _function_1 = (EStructuralFeature.Setting it) -> { EObject _eObject = it.getEObject(); return ((EClass) _eObject); }; return IterableExtensions.map(IterableExtensions.filter(EcoreUtil.UsageCrossReferencer.find(cl, EdeltaUtils.packagesToInspect(cl)), _function), _function_1); } /** * Finds abstract classes that should be concrete, * since they have no subclasses. */ public Iterable findAbstractConcreteMetaclasses(final EPackage ePackage) { final Function1 _function = (EClass cl) -> { return Boolean.valueOf((cl.isAbstract() && (!this.hasSubclasses(cl)))); }; final Iterable classes = IterableExtensions.filter(EdeltaUtils.allEClasses(ePackage), _function); final Consumer _function_1 = (EClass it) -> { final Supplier _function_2 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(it); return ("Abstract concrete class: " + _eObjectRepr); }; this.logInfo(_function_2); }; classes.forEach(_function_1); return classes; } /** * Finds classes that are abstract though they have only concrete superclasses. */ public Iterable findAbstractSubclassesOfConcreteSuperclasses(final EPackage ePackage) { final Function1 _function = (EClass cl) -> { return Boolean.valueOf(((cl.isAbstract() && (!cl.getESuperTypes().isEmpty())) && IterableExtensions.forall(cl.getESuperTypes(), ((Function1) (EClass it) -> { boolean _isAbstract = it.isAbstract(); return Boolean.valueOf((!_isAbstract)); })))); }; final Iterable classes = IterableExtensions.filter(EdeltaUtils.allEClasses(ePackage), _function); final Consumer _function_1 = (EClass it) -> { final Supplier _function_2 = () -> { String _eObjectRepr = EdeltaUtils.getEObjectRepr(it); return ("Abstract class with concrete superclasses: " + _eObjectRepr); }; this.logInfo(_function_2); }; classes.forEach(_function_1); return classes; } @Override public void performSanityChecks() throws Exception { ensureEPackageIsLoaded("ecore"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy