/******************************************************************************* * Copyright (c) 2014 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package dtool.engine.analysis; import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue; import static melnorme.utilbox.misc.StringUtil.emptyAsNull; import melnorme.lang.tooling.context.ISemanticContext; import melnorme.lang.tooling.engine.ErrorElement; import melnorme.lang.tooling.engine.ErrorElement.NotAValueErrorElement; import melnorme.lang.tooling.engine.PickedElement; import melnorme.lang.tooling.engine.completion.CompletionScopeLookup; import melnorme.lang.tooling.engine.resolver.INamedElementSemanticData; import melnorme.lang.tooling.symbols.IConcreteNamedElement; import melnorme.lang.tooling.symbols.INamedElement; import melnorme.lang.tooling.symbols.ITypeNamedElement; import org.junit.Test; import dtool.ast.expressions.Expression; /** * A base test for a {@link INamedElement}s. * Each subclass should reimplement each test method as appropriate (even if there is nothing to test). */ public abstract class NamedElement_CommonTest extends CommonNodeSemanticsTest { protected final String ERROR_NotAValue = NotAValueErrorElement.ERROR_IS_NOT_A_VALUE; protected PickedElement<INamedElement> parseNamedElement(String source) { return parseElement(source, getMarkerIndex(source), INamedElement.class); } protected PickedElement<ITypeNamedElement> parseTypeElement(String source) { return parseElement(source, getMarkerIndex(source), ITypeNamedElement.class); } protected int getMarkerIndex(String source) { int index = source.indexOf("xxx"); if(index == -1) { index = source.indexOf("XXX"); } if(index == -1) { index = source.indexOf("Foo"); } assertTrue(index != -1); return index; } /* ----------------- ----------------- */ protected static String expectNotAValue(INamedElement namedElement) { return expectNotAValue(namedElement.getExtendedName()); } protected static PickedElement<INamedElement> picked2(INamedElement namedElement, ISemanticContext context) { return picked(namedElement, namedElement.getElementSemanticContext(context)); } /* ----------------- ----------------- */ @Test public void test_NamedElement() throws Exception { test_NamedElement________(); } public abstract void test_NamedElement________() throws Exception; public static void test_NamedElement(PickedElement<? extends INamedElement> pickedElement, String aliasTarget, String expectedTypeOfValue, String[] expectedMembers) { final INamedElement namedElement = pickedElement.element; // TODO: might want to review this code assertTrue( namedElement.isBuiltinElement() || namedElement.getSemanticContainerKey() != null || namedElement.getElementSemanticContext(null) != null || namedElement.getSemantics(null) != null); if(emptyAsNull(namedElement.getModuleFullName()) == null) { assertTrue(namedElement.getParentNamespace() == null); assertTrue(namedElement.getModuleFullName() == null); } else { if(namedElement.getModuleFullName().equals(namedElement.getFullyQualifiedName())) { assertTrue(namedElement.getParentNamespace() == null); } else { assertTrue(namedElement.getParentNamespace() != null); } } test_resolveConcreteElement(pickedElement, aliasTarget); test_resolveTypeForValueContext(pickedElement, expectedTypeOfValue); if(expectedMembers != null) { test_resolveSearchInMembersScope(pickedElement, expectedMembers); } } public static void test_NamedElement_Alias(PickedElement<? extends INamedElement> pickedElement, String aliasTarget, String expectedTypeOfValue, String[] expectedMembers) { test_NamedElement(pickedElement, aliasTarget, expectedTypeOfValue, expectedMembers); } public static void test_NamedElement_Concrete(PickedElement<? extends INamedElement> pickedElement, String expectedTypeName, String[] expectedMembers) { test_NamedElement(pickedElement, null, expectedTypeName, expectedMembers); } public static void test_NamedElement_Type(PickedElement<? extends ITypeNamedElement> pickedElement, String[] expectedMembers) { test_NamedElement_NonValue(pickedElement, null, expectedMembers); } public static void test_NamedElement_NonValue(PickedElement<? extends INamedElement> pickedElement, String aliasTarget, String[] expectedMembers) { test_NamedElement(pickedElement, aliasTarget, expectNotAValue(pickedElement.element.getName()), expectedMembers); } protected static void test_resolveConcreteElement(PickedElement<? extends INamedElement> pickedElement, String concreteTargetLabel) { final ISemanticContext context = pickedElement.context; final INamedElement namedElement = pickedElement.element; assertTrue(context == namedElement.getElementSemanticContext(context)); checkIsSameResolution( namedElement.getSemantics(context).resolveConcreteElement(), namedElement.getSemantics(context).resolveConcreteElement() ); INamedElementSemanticData semantics = namedElement.getSemantics(context); IConcreteNamedElement concreteElement = semantics.resolveConcreteElement().result; if(concreteElement instanceof ErrorElement) { ErrorElement notFoundError = (ErrorElement) concreteElement; assertTrue(notFoundError.getSemanticContainerKey() == namedElement.getSemanticContainerKey()); assertTrue(notFoundError.getOwnerElement() != null); assertTrue(notFoundError.getLexicalParent() == null); assertTrue(notFoundError.getParentNamespace() == null); } if(concreteTargetLabel == null) { // non-alias elements relsolve to themselves assertTrue(concreteElement == namedElement); } else { checkElementLabel(concreteElement, concreteTargetLabel); } } public static void test_resolveTypeForValueContext(PickedElement<? extends INamedElement> pickedElement, String expectedTypeName) { INamedElement namedElement = pickedElement.element; pickedElement.context._resetSemantics(); INamedElement resolvedType = namedElement.getSemantics(pickedElement.context).getTypeForValueContext(); // Test caching assertTrue(resolvedType == namedElement.getSemantics(pickedElement.context).getTypeForValueContext()); checkElementLabel(resolvedType, expectedTypeName); } /* ----------------- ----------------- */ public static final String[] NO_MEMBERS = strings(); public static final String[] COMMON_PROPERTIES = array( "init", "sizeof", "alignof", "mangleof", "stringof" ); protected static void test_resolveSearchInMembersScope(PickedElement<? extends INamedElement> pickedElement, String... expectedResults) { CompletionScopeLookup search = new CompletionScopeLookup(0, pickedElement.context, ""); search.evaluateInMembersScope(pickedElement.element); resultsChecker(search).checkResults(expectedResults); } protected static PickedElement<Expression> parseExp(String source) { return parseElement(source, Expression.class); } // TODO: need to refactor/review this public static void testExpressionResolution(PickedElement<Expression> expPick, String... expectedResults) { ISemanticContext context = expPick.context; INamedElement expType = expPick.element.resolveTypeOfUnderlyingValue_nonNull(context).originalType; test_resolveSearchInMembersScope(picked2(expType, context), expectedResults); } }