/* * ****************************************************************************** * 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.symboltable.types; import de.monticore.symboltable.CommonScope; import de.monticore.symboltable.MutableScope; import de.monticore.symboltable.ScopeSpanningSymbol; import de.monticore.symboltable.Symbol; import de.monticore.symboltable.SymbolKind; import de.monticore.symboltable.SymbolPredicate; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.symboltable.resolving.ResolvingInfo; import de.monticore.symboltable.types.references.JTypeReference; import de.se_rwth.commons.logging.Log; import java.util.Collection; import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; import static de.monticore.symboltable.modifiers.AccessModifier.ALL_INCLUSION; import static de.monticore.symboltable.modifiers.BasicAccessModifier.PACKAGE_LOCAL; import static de.monticore.symboltable.modifiers.BasicAccessModifier.PRIVATE; import static de.monticore.symboltable.modifiers.BasicAccessModifier.PROTECTED; /** * @author Pedram Mir Seyed Nazari */ public class CommonJTypeScope extends CommonScope { public CommonJTypeScope(Optional<MutableScope> enclosingScope) { super(enclosingScope, true); } @Override public void setSpanningSymbol(ScopeSpanningSymbol symbol) { checkArgument(symbol instanceof JTypeSymbol); super.setSpanningSymbol(symbol); } @Override @SuppressWarnings("unchecked") public Optional<? extends JTypeSymbol> getSpanningSymbol() { return (Optional <? extends JTypeSymbol>) super.getSpanningSymbol(); } @Override public <T extends Symbol> Optional<T> resolve(String symbolName, SymbolKind kind) { return this.resolve(symbolName, kind, ALL_INCLUSION); } @Override public <T extends Symbol> Optional<T> resolve(String name, SymbolKind kind, AccessModifier modifier) { Optional<T> resolvedSymbol = this.resolveImported(name, kind, modifier); if (!resolvedSymbol.isPresent()) { resolvedSymbol = resolveInSuperTypes(name, kind, modifier); } if (!resolvedSymbol.isPresent()) { // continue with enclosing scope resolvedSymbol = super.resolve(name, kind, modifier); } return resolvedSymbol; } protected <T extends Symbol> Optional<T> resolveInSuperTypes(String name, SymbolKind kind, AccessModifier modifier) { Optional<T> resolvedSymbol = Optional.empty(); final JTypeSymbol spanningSymbol = getSpanningSymbol().get(); // resolve in super class if (spanningSymbol.getSuperClass().isPresent()) { final JTypeSymbol superClass = spanningSymbol.getSuperClass().get().getReferencedSymbol(); resolvedSymbol = resolveInSuperType(name, kind, modifier, superClass); } // resolve in interfaces if (!resolvedSymbol.isPresent()) { for (JTypeReference<? extends JTypeSymbol> interfaceRef : spanningSymbol.getInterfaces()) { final JTypeSymbol interfaze = interfaceRef.getReferencedSymbol(); resolvedSymbol = resolveInSuperType(name, kind, modifier, interfaze); // Stop as soon as symbol is found in an interface. Note that the other option is to // search in all interfaces and throw an ambiguous exception if more than one symbol is // found. => TODO discuss it! if (resolvedSymbol.isPresent()) { break; } } } return resolvedSymbol; } private <T extends Symbol> Optional<T> resolveInSuperType(String name, SymbolKind kind, final AccessModifier modifier, JTypeSymbol superType) { Log.trace("Continue in scope of super class " + superType.getName(), CommonJTypeScope.class .getSimpleName()); // Private symbols cannot be resolved from the super class. So, the modifier must at // least be protected when searching in the super class scope AccessModifier modifierForSuperClass = getModifierForSuperClass(modifier, superType); return superType.getSpannedScope().resolveImported(name, kind, modifierForSuperClass); } private AccessModifier getModifierForSuperClass(AccessModifier modifier, JTypeSymbol superType) { if (modifier.equals(ALL_INCLUSION) || modifier.equals(PRIVATE) || modifier.equals(PACKAGE_LOCAL)) { if (getSpanningSymbol().get().getPackageName().equals(superType.getPackageName())) { return PACKAGE_LOCAL; } else { return PROTECTED; } } return modifier; } @Override @Deprecated public Optional<? extends Symbol> resolve(final SymbolPredicate predicate) { Optional<? extends Symbol> resolvedSymbol = super.resolve(predicate); if (!resolvedSymbol.isPresent()) { final JTypeSymbol spanningSymbol = getSpanningSymbol().get(); final Optional<? extends JTypeReference<? extends JTypeSymbol>> optSuperClass = spanningSymbol.getSuperClass(); if (optSuperClass.isPresent()) { final JTypeSymbol superClass = optSuperClass.get().getReferencedSymbol(); Log.trace("Continue in scope of super class " + superClass.getName(), CommonJTypeScope.class.getSimpleName()); resolvedSymbol = superClass.getSpannedScope().resolve(predicate); } } return resolvedSymbol; } @Override public <T extends Symbol> Optional<T> resolveImported(String name, SymbolKind kind, AccessModifier modifier) { final Collection<T> resolvedSymbols = resolveManyLocally(new ResolvingInfo(getResolvingFilters()), name, kind, modifier, x -> true); if (resolvedSymbols.isEmpty()) { return resolveInSuperTypes(name, kind, modifier); } return getResolvedOrThrowException(resolvedSymbols); } }