/* * ****************************************************************************** * 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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.List; import java.util.Optional; import de.monticore.symboltable.mocks.CommonScopeMock; import de.monticore.symboltable.mocks.languages.entity.PropertySymbol; import de.monticore.symboltable.resolving.CommonResolvingFilter; import de.monticore.symboltable.resolving.ResolvedSeveralEntriesException; import de.monticore.symboltable.resolving.ResolvingFilter; import de.monticore.symboltable.types.JTypeSymbol; import de.monticore.symboltable.types.references.CommonJTypeReference; import de.monticore.symboltable.types.references.JTypeReference; import org.junit.Test; /** * * @author Pedram Mir Seyed Nazari */ public class ShadowingTest { @Test public void testLocalScopeDoesNotShadowEnclosingScope() { CommonScope enclosingScope = new CommonScope(false); CommonScope scope = new CommonScope(Optional.of(enclosingScope), false); JTypeReference intReference = new CommonJTypeReference<>("int", JTypeSymbol.KIND, scope); JTypeReference stringReference = new CommonJTypeReference<>("String", JTypeSymbol.KIND, scope); PropertySymbol v1 = new PropertySymbol("var", intReference); enclosingScope.add(v1); PropertySymbol x = new PropertySymbol("x", intReference); enclosingScope.add(x); PropertySymbol v2 = new PropertySymbol("var", stringReference); scope.add(v2); PropertySymbol y = new PropertySymbol("y", stringReference); scope.add(y); ResolvingFilter<PropertySymbol> variableResolvingFilter = CommonResolvingFilter.create(PropertySymbol.KIND); enclosingScope.addResolver(variableResolvingFilter); scope.addResolver(variableResolvingFilter); assertSame(v1, enclosingScope.resolve("var", PropertySymbol.KIND).get()); assertSame(x, enclosingScope.resolve("x", PropertySymbol.KIND).get()); assertSame(x, scope.resolve("x", PropertySymbol.KIND).get()); assertSame(y, scope.resolve("y", PropertySymbol.KIND).get()); try { scope.resolve("var", PropertySymbol.KIND); fail(); } catch (ResolvedSeveralEntriesException e) { assertEquals(2, e.getSymbols().size()); assertTrue(e.getSymbols().contains(v2)); assertTrue(e.getSymbols().contains(v1)); } } @Test public void testShadowingScopeShadowsEnclosingScope() { CommonScope enclosingScope = new CommonScope(false); // is shadowing scope CommonScope scope = new CommonScope(Optional.of(enclosingScope), true); JTypeReference intReference = new CommonJTypeReference<>("int", JTypeSymbol.KIND, scope); JTypeReference stringReference = new CommonJTypeReference<>("String", JTypeSymbol.KIND, scope); PropertySymbol v1 = new PropertySymbol("var", intReference); enclosingScope.add(v1); PropertySymbol x = new PropertySymbol("x", intReference); enclosingScope.add(x); PropertySymbol v2 = new PropertySymbol("var", stringReference); scope.add(v2); PropertySymbol y = new PropertySymbol("y", stringReference); scope.add(y); ResolvingFilter<PropertySymbol> variableResolvingFilter = CommonResolvingFilter.create(PropertySymbol.KIND); enclosingScope.addResolver(variableResolvingFilter); scope.addResolver(variableResolvingFilter); assertSame(v1, enclosingScope.resolve("var", PropertySymbol.KIND).get()); assertSame(x, enclosingScope.resolve("x", PropertySymbol.KIND).get()); assertSame(x, scope.resolve("x", PropertySymbol.KIND).get()); assertSame(y, scope.resolve("y", PropertySymbol.KIND).get()); // shadows enclosing var assertSame(v2, scope.resolve("var", PropertySymbol.KIND).get()); } @Test public void testLocalScopeShadowsGrandEnclosingScopeIfEnclosingIsShadowingScope() { CommonScopeMock grandGrandEnclosingScope = new CommonScopeMock(false); // true would have the same impact CommonScopeMock grandEnclosing = new CommonScopeMock(Optional.of(grandGrandEnclosingScope), true); CommonScopeMock enclosingScope = new CommonScopeMock(Optional.of(grandEnclosing), false); CommonScopeMock scope = new CommonScopeMock(Optional.of(enclosingScope), false); // Set names to simplify testing (see below) grandGrandEnclosingScope.setName("grandGrand"); grandEnclosing.setName("grand"); enclosingScope.setName("enclosing"); scope.setName("scope"); JTypeReference intReference = new CommonJTypeReference<>("int", JTypeSymbol.KIND, scope); PropertySymbol gpVariable = new PropertySymbol("var", intReference); grandGrandEnclosingScope.add(gpVariable); PropertySymbol variable = new PropertySymbol("var", intReference); scope.add(variable); ResolvingFilter<PropertySymbol> variableResolvingFilter = CommonResolvingFilter.create(PropertySymbol.KIND); grandGrandEnclosingScope.addResolver(variableResolvingFilter); enclosingScope.addResolver(variableResolvingFilter); scope.addResolver(variableResolvingFilter); assertSame(gpVariable, grandGrandEnclosingScope.resolve("var", PropertySymbol.KIND).get()); assertSame(gpVariable, enclosingScope.resolve("var", PropertySymbol.KIND).get()); assertSame(variable, scope.resolve("var", PropertySymbol.KIND).get()); final List<MutableScope> involvedScopes = scope.getResolvingInfo().getInvolvedScopes(); // Resolution must stop after the third scope (i.e., grandEnclosing) assertEquals(3, involvedScopes.size()); assertEquals("scope", involvedScopes.get(0).getName().get()); assertEquals("enclosing", involvedScopes.get(1).getName().get()); assertEquals("grand", involvedScopes.get(2).getName().get()); } }