/* * ****************************************************************************** * MontiCore Language Workbench * Copyright (c) 2015, MontiCore, All rights reserved. * * This project is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this project. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************** */ package de.monticore.codegen.mc2cd.transl; import de.monticore.grammar.grammar._ast.*; import de.monticore.umlcd4a.cd4analysis._ast.*; import de.monticore.utils.Link; import de.monticore.ast.ASTNode; import de.monticore.codegen.mc2cd.MC2CDStereotypes; import java.util.Optional; import java.util.Set; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import static de.monticore.codegen.mc2cd.TransformationHelper.getName; import static de.monticore.codegen.mc2cd.TransformationHelper.getUsageName; /** * The CDAttributes generated from AttributeInASTs completely hide any CDAttributes derived from * NonTerminals. * * @author Sebastian Oberhoff */ public class RemoveOverriddenAttributesTranslation implements UnaryOperator<Link<ASTMCGrammar, ASTCDCompilationUnit>> { @Override public Link<ASTMCGrammar, ASTCDCompilationUnit> apply( Link<ASTMCGrammar, ASTCDCompilationUnit> rootLink) { for (Link<ASTNode, ASTCDClass> classLink : rootLink.getLinks(ASTNode.class, ASTCDClass.class)) { classLink.getLinks(ASTNode.class, ASTCDAttribute.class).stream() .filter(attributeLink -> isOverridden(attributeLink.source(), classLink)) .filter(attributeLink -> isNotInherited(attributeLink.target())) .map(Link::target) .forEach(classLink.target().getCDAttributes()::remove); } return rootLink; } private boolean isOverridden(ASTNode source, Link<?, ASTCDClass> classLink) { Optional<String> usageName = getUsageName(classLink.source(), source); Set<ASTAttributeInAST> attributesInASTLinkingToSameClass = attributesInASTLinkingToSameClass( classLink); attributesInASTLinkingToSameClass.remove(source); boolean matchByUsageName = usageName.isPresent() && attributesInASTLinkingToSameClass.stream() .map(ASTAttributeInAST::getName) .filter(Optional::isPresent) .map(Optional::get) .anyMatch(usageName.get()::equals); boolean matchByTypeName = !usageName.isPresent() && attributesInASTLinkingToSameClass.stream() .filter(attributeInAST -> !attributeInAST.getName().isPresent()) .map(ASTAttributeInAST::getGenericType) .map(ASTGenericType::getTypeName) .anyMatch(getName(source).orElse("")::equals); return matchByUsageName || matchByTypeName; } private Set<ASTAttributeInAST> attributesInASTLinkingToSameClass(Link<?, ASTCDClass> link) { return link.rootLink().getLinks(ASTNode.class, ASTCDClass.class).stream() .filter(attributeLink -> attributeLink.target() == link.target()) .flatMap(astRuleLink -> astRuleLink.getLinks(ASTAttributeInAST.class, ASTCDAttribute.class).stream()) .map(Link::source).collect(Collectors.toSet()); } private boolean isNotInherited(ASTCDAttribute cdAttribute) { Optional<ASTModifier> modifier = cdAttribute.getModifier(); if (!modifier.isPresent()) { return true; } Optional<ASTStereotype> stereotype = modifier.get().getStereotype(); if (!stereotype.isPresent()) { return true; } return stereotype.get().getValues().stream() .map(ASTStereoValue::getName) .noneMatch(MC2CDStereotypes.INHERITED.toString()::equals); } }