From 5fdf1a42775d14df452e9f33cd99dd50805f2920 Mon Sep 17 00:00:00 2001 From: mmews Date: Wed, 28 Feb 2024 15:58:03 +0100 Subject: [PATCH] migrate migrate --- .../scoping/utils/ExpressionExtensions.java | 135 +++++++++++++ .../scoping/utils/ExpressionExtensions.xtend | 118 ----------- .../utils/LocallyKnownTypesScopingHelper.java | 187 ++++++++++++++++++ .../LocallyKnownTypesScopingHelper.xtend | 170 ---------------- .../n4js/scoping/utils/ScopesHelper.java | 94 +++++++++ .../n4js/scoping/utils/ScopesHelper.xtend | 89 --------- 6 files changed, 416 insertions(+), 377 deletions(-) create mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.java delete mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.xtend create mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.java delete mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.xtend create mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.java delete mode 100644 plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.xtend diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.java new file mode 100644 index 0000000000..c858e94f64 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.java @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * 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: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.scoping.utils; + +import static org.eclipse.xtext.xbase.lib.IterableExtensions.last; + +import java.util.Arrays; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.n4JS.AssignmentExpression; +import org.eclipse.n4js.n4JS.AssignmentOperator; +import org.eclipse.n4js.n4JS.BinaryLogicalExpression; +import org.eclipse.n4js.n4JS.CommaExpression; +import org.eclipse.n4js.n4JS.Expression; +import org.eclipse.n4js.n4JS.ParenExpression; +import org.eclipse.n4js.n4JS.PostfixExpression; +import org.eclipse.n4js.n4JS.UnaryExpression; +import org.eclipse.n4js.n4JS.UnaryOperator; +import org.eclipse.xtext.EcoreUtil2; + +/** + * General utility methods for expressions. + */ +public class ExpressionExtensions { + + /** + * Returns true if the subExpression actually is the left hand side expression of an assignment expression, that is + * its value could be changed when the assignment is evaluated. I.e. the subExpression could be returned by ancestor + * expression, e.g., if the subExpression is an operand of a binary logical expression. This method returns false, + * if the subExpression is an assignment expression itself! + *

+ * Note that neither assignments nor conditional expression return any of their operands! + */ + public static boolean isLeftHandSide(EObject subExpression) { + if (subExpression == null || subExpression instanceof AssignmentExpression) { + return false; + } + EObject expr = subExpression; + while (expr.eContainer() != null && isPotentialEvalResult(expr.eContainer(), expr)) { + expr = expr.eContainer(); + } + return expr.eContainer() instanceof AssignmentExpression && + ((AssignmentExpression) expr.eContainer()).getLhs() == expr; + } + + /** + * Does the argument occur as operand in a (prefix or postfix) ++ or -- operation? + *

+ * The increment and decrement operators "conceptually" involve both read- and write-access, unlike the LHS of a + * simple assignment. Granted, '+=' and similar compound assignments can be seen as comprising read- and + * write-access. + */ + public static boolean isIncOrDecTarget(EObject subExpression) { + if (subExpression == null || subExpression instanceof AssignmentExpression) { + return false; + } + EObject expr = subExpression; + while (expr.eContainer() != null && isPotentialEvalResult(expr.eContainer(), expr)) { + expr = expr.eContainer(); + } + if (expr.eContainer() instanceof PostfixExpression) { + return true; + } + if (expr.eContainer() instanceof UnaryExpression) { + UnaryExpression ue = (UnaryExpression) expr.eContainer(); + if (ue.getOp() == UnaryOperator.INC || ue.getOp() == UnaryOperator.DEC) { + return true; + } + } + return false; + } + + /***/ + public static boolean isBothReadFromAndWrittenTo(EObject expr) { + if (isLeftHandSide(expr)) { + AssignmentExpression a = EcoreUtil2.getContainerOfType(expr, AssignmentExpression.class); + return a.getOp() != AssignmentOperator.ASSIGN; + } + return isIncOrDecTarget(expr); + } + + /** + * Returns true if the (value of the) subExpression could be returned by container expression, e.g., if the + * subExpression is an operand of a binary logical expression. + *

+ * Most types of expressions return false here. Note that neither assignments nor conditional expression return any + * of their operands, thus, both type of expressions always return false as well. + *

+ * Example: the unparenthesized {@code arr[0]} below {@link #isLeftHandSide} although its direct container isn't an + * assignment but a {@link ParenExpression} + * + *

+	 * {@code
+	 * var arr = [1];
+	 * (arr[0]) = 6;
+	 * console.log(arr[0])
+	 * }
+	 * 
+ */ + private static boolean isPotentialEvalResult(final EObject container, final EObject childExpression) { + if (container instanceof ParenExpression && childExpression instanceof Expression) { + return isPotentialEvalResult((ParenExpression) container, (Expression) childExpression); + } else if (container instanceof BinaryLogicalExpression && childExpression instanceof Expression) { + return isPotentialEvalResult((BinaryLogicalExpression) container, (Expression) childExpression); + } else if (container instanceof CommaExpression && childExpression instanceof Expression) { + return isPotentialEvalResult((CommaExpression) container, (Expression) childExpression); + } else if (container != null && childExpression != null) { + return false; + } else { + throw new IllegalArgumentException("Unhandled parameter types: " + + Arrays.asList(container, childExpression).toString()); + } + } + + private static boolean isPotentialEvalResult(ParenExpression container, Expression childExpression) { + return childExpression != null && childExpression.eContainer() == container; + } + + private static boolean isPotentialEvalResult(BinaryLogicalExpression container, Expression childExpression) { + return childExpression != null && childExpression.eContainer() == container; + } + + private static boolean isPotentialEvalResult(CommaExpression container, Expression childExpression) { + return container != null && last(container.getExprs()) == childExpression; + } + +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.xtend deleted file mode 100644 index 15b5bb7917..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ExpressionExtensions.xtend +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * 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: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.scoping.utils - -import org.eclipse.n4js.n4JS.AssignmentExpression -import org.eclipse.n4js.n4JS.BinaryLogicalExpression -import org.eclipse.n4js.n4JS.CommaExpression -import org.eclipse.n4js.n4JS.Expression -import org.eclipse.emf.ecore.EObject -import org.eclipse.n4js.n4JS.ParenExpression -import org.eclipse.n4js.n4JS.PostfixExpression -import org.eclipse.n4js.n4JS.UnaryExpression -import org.eclipse.n4js.n4JS.UnaryOperator -import org.eclipse.n4js.n4JS.AssignmentOperator -import org.eclipse.xtext.EcoreUtil2 - -/** - * General utitility methods for expressions. - */ -class ExpressionExtensions { - - /** - * Returns true if the subExpression actually is the left hand side expression of an assignment expression, that is - * its value could be changed when the assignment is evaluated. I.e. the subExpression - * could be returned by ancestor expression, e.g., if the subExpression is - * an operand of a binary logical expression. - * This method returns false, if the subExpression is an assignment expression itself! - *

- * Note that neither assignments nor conditional expression return any of their operands! - */ - static def boolean isLeftHandSide(EObject subExpression) { - if (subExpression === null || subExpression instanceof AssignmentExpression) { - return false; - } - var EObject expr = subExpression; - while (expr.eContainer!==null && isPotentialEvalResult(expr.eContainer, expr)) { - expr = expr.eContainer; - } - return expr !== null && expr.eContainer instanceof AssignmentExpression && - (expr.eContainer as AssignmentExpression).lhs == expr - } - - - /** - * Does the argument occur as operand in a (prefix or postfix) ++ or -- operation? - *

- * The increment and decrement operators "conceptually" involve both read- and write-access, - * unlike the LHS of a simple assignment. Granted, '+=' and similar compound assignments can be seen - * as comprising read- and write-access. - */ - static def boolean isIncOrDecTarget(EObject subExpression) { - if (subExpression === null || subExpression instanceof AssignmentExpression) { - return false; - } - var EObject expr = subExpression; - while (expr.eContainer!==null && isPotentialEvalResult(expr.eContainer, expr)) { - expr = expr.eContainer; - } - if (expr.eContainer instanceof PostfixExpression) { - return true - } - if (expr.eContainer instanceof UnaryExpression) { - val ue = expr.eContainer as UnaryExpression; - if (ue.op == UnaryOperator.INC || ue.op === UnaryOperator.DEC) { - return true - } - } - return false - } - - static def boolean isBothReadFromAndWrittenTo(EObject expr) { - if (isLeftHandSide(expr)) { - val a = EcoreUtil2.getContainerOfType(expr, AssignmentExpression) - return a.op !== AssignmentOperator.ASSIGN - } - return isIncOrDecTarget(expr) - } - - /** - * Returns true if the (value of the) subExpression could be returned by container expression, e.g., if the subExpression is - * an operand of a binary logical expression. - *

- * Most types of expressions return false here. Note that neither assignments nor conditional expression return any of their operands, thus, both type of expressions - * always return false as well. - *

- * Example: the unparenthesized {@code arr[0]} below {@link #isLeftHandSide} although its direct container isn't an assignment but a {@link ParenExpression} - *

-	 * {@code
-	 * var arr = [1];
-	 * (arr[0]) = 6;
-	 * console.log(arr[0])
-	 * }
-	 * 
- */ - private static def dispatch boolean isPotentialEvalResult(EObject container, EObject childExpression) { - return false; - } - - private static def dispatch boolean isPotentialEvalResult(ParenExpression container, Expression childExpression) { - return childExpression !== null && childExpression.eContainer === container; - } - - private static def dispatch boolean isPotentialEvalResult(BinaryLogicalExpression container, Expression childExpression) { - return childExpression !== null && childExpression.eContainer === container; - } - - private static def dispatch boolean isPotentialEvalResult(CommaExpression container, Expression childExpression) { - return container !== null && container.exprs.last === childExpression; - } -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.java new file mode 100644 index 0000000000..50447bcca7 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.java @@ -0,0 +1,187 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * 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: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.scoping.utils; + +import static org.eclipse.xtext.xbase.lib.IterableExtensions.filter; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.map; + +import java.util.function.Function; +import java.util.function.Supplier; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.n4JS.N4NamespaceDeclaration; +import org.eclipse.n4js.n4JS.Script; +import org.eclipse.n4js.resource.N4JSCache; +import org.eclipse.n4js.scoping.N4JSScopeProvider; +import org.eclipse.n4js.scoping.imports.ImportedElementsScopingHelper; +import org.eclipse.n4js.ts.typeRefs.FunctionTypeExpression; +import org.eclipse.n4js.ts.types.AbstractNamespace; +import org.eclipse.n4js.ts.types.TClassifier; +import org.eclipse.n4js.ts.types.TEnum; +import org.eclipse.n4js.ts.types.TModule; +import org.eclipse.n4js.ts.types.TStructMember; +import org.eclipse.n4js.ts.types.TStructMethod; +import org.eclipse.n4js.ts.types.Type; +import org.eclipse.xtext.resource.EObjectDescription; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.impl.SingletonScope; + +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +/** + * Helper for {@link N4JSScopeProvider N4JSScopeProvider} using {@link ImportedElementsScopingHelper + * ImportedElementsScopingHelper} for providing scope for types provider. + */ +public class LocallyKnownTypesScopingHelper { + + @Inject + N4JSCache cache; + + @Inject + ImportedElementsScopingHelper importedElementsScopingHelper; + + @Inject + ScopeSnapshotHelper scopeSnapshotHelper; + + /** Returns the type itself and type variables in case the type is generic. */ + public IScope scopeWithTypeAndItsTypeVariables(IScope parent, Type type, boolean staticAccess) { + IScope result = parent; + if (type != null) { + + // add the type itself + if (type.getName() != null && type instanceof TClassifier) { + // note that functions cannot be used as type references + result = new SingletonScope(EObjectDescription.create(type.getName(), type), result); + } + + // add the type variables + if (type.isGeneric()) { + if (type instanceof TClassifier && staticAccess) { + // error case: type variables of a classifier cannot be accessed from static members + // e.g. class C { static x: T; } + // --> return same scope as in success case, but wrap descriptions with a + // WrongStaticAccessorDescription + Function wrapEODs = dscr -> new WrongStaticAccessDescription( + dscr, staticAccess); + result = scopeSnapshotHelper.scopeForEObjects("scopeWithTypeAndItsTypeVariables-1", + type, result, type.getTypeVars(), wrapEODs); + } else { + // success case: simply add type variables to scope + result = scopeSnapshotHelper.scopeForEObjects("scopeWithTypeAndItsTypeVariables-2", type, result, + type.getTypeVars()); + } + } + } + + return result; + } + + /** Returns the type variables if the TStructMethod is generic. */ + public IScope scopeWithTypeVarsOfTStructMethod(IScope parent, TStructMethod m) { + TStructMember mDef = m.getDefinedMember(); + if (mDef instanceof TStructMethod) { + if (((TStructMethod) mDef).isGeneric()) { + return scopeSnapshotHelper.scopeForEObjects("scopeWithTypeVarsOfTStructMethod", mDef, parent, + ((TStructMethod) mDef).getTypeVars()); + } + } + return parent; + } + + /** Returns the type variables if the function type expression is generic. */ + public IScope scopeWithTypeVarsOfFunctionTypeExpression(IScope parent, FunctionTypeExpression funTypeExpr) { + if (funTypeExpr != null && funTypeExpr.isGeneric()) { + return scopeSnapshotHelper.scopeForEObjects("scopeWithTypeVarsOfFunctionTypeExpression", funTypeExpr, + parent, funTypeExpr.getTypeVars()); + } + return parent; + } + + /** Returns scope with locally known types and (as parent) import scope; the result is cached. */ + public IScope scopeWithLocallyDeclaredElems(Script script, Supplier parentSupplier, + boolean onlyNamespacelikes) { + return cache.get(script.eResource(), () -> { + // all types in the index: + IScope parent = parentSupplier.get(); + // but imported types are preferred (or maybe renamed with aliases): + IScope importScope = importedElementsScopingHelper.getImportedTypes(parent, script); + // finally, add locally declared types as the outer scope + IScope localTypes = scopeWithLocallyDeclaredElems(script, importScope, onlyNamespacelikes); + + return localTypes; + }, script, "locallyKnownTypes_" + String.valueOf(onlyNamespacelikes)); + } + + /** Returns scope with locally declared types (without import scope). */ + public IScope scopeWithLocallyDeclaredElems(Script script, IScope parent, boolean onlyNamespacelikes) { + return scopeWithLocallyDeclaredElems(script.getModule(), script, parent, onlyNamespacelikes); + } + + /** Returns scope with locally declared types (without import scope). */ + public IScope scopeWithLocallyDeclaredElems(N4NamespaceDeclaration namespace, IScope parent, + boolean onlyNamespacelikes) { + return cache.get(namespace.eResource(), + () -> scopeWithLocallyDeclaredElems((AbstractNamespace) namespace.getDefinedType(), namespace, parent, + onlyNamespacelikes), + namespace, "scopeWithLocallyDeclaredElems_" + String.valueOf(onlyNamespacelikes)); + } + + /** Returns scope with locally declared types (without import scope). */ + public IScope scopeWithLocallyDeclaredElems(AbstractNamespace namespace, IScope parent, + boolean onlyNamespacelikes) { + return scopeWithLocallyDeclaredElems(namespace, namespace, parent, onlyNamespacelikes); + } + + /** Returns scope with locally declared types (without import scope). */ + private IScope scopeWithLocallyDeclaredElems(AbstractNamespace ans, EObject context, IScope parent, + boolean onlyNamespacelikes) { + if (ans == null || ans.eIsProxy()) { + return parent; + } + Iterable tlElems = onlyNamespacelikes + ? Iterables.concat(ans.getNamespaces(), filter(ans.getTypes(), TEnum.class)) + : filter(ans.getTypes(), t -> !t.isPolyfill()); + Iterable eoDescrs = map(tlElems, + topLevelType -> EObjectDescription.create(topLevelType.getName(), topLevelType)); + return scopeSnapshotHelper.scopeFor("scopeWithLocallyDeclaredTypes", context, parent, eoDescrs); + } + + /** + * Returns scope with locally known types specially configured for super reference in case of polyfill definitions. + * It does not add the polyfillType itself. Instead, only its type variables are added, which are otherwise hidden + * in case of polyfills. The result is not cached as this scope is needed only one time. + */ + public IScope scopeWithLocallyKnownTypesForPolyfillSuperRef(Script script, IScope parent, Type polyfillType) { + + // imported and locally defined types are preferred (or maybe renamed with aliases): + IScope importScope = importedElementsScopingHelper.getImportedTypes(parent, script); + + // locally defined types except polyfillType itself + TModule local = script.getModule(); + Iterable eoDescrs = map(filter(local.getTypes(), t -> t != polyfillType), + t -> EObjectDescription.create(t.getName(), t)); + IScope localTypesScope = scopeSnapshotHelper.scopeFor("scopeWithLocallyKnownTypesForPolyfillSuperRef", script, + importScope, eoDescrs); + + // type variables of polyfill + if (polyfillType != null && polyfillType.isGeneric()) { + return scopeSnapshotHelper.scopeForEObjects("scopeWithLocallyKnownTypesForPolyfillSuperRef-polyfillType", + polyfillType, localTypesScope, polyfillType.getTypeVars()); + } + + // non generic: + return localTypesScope; + + } + +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.xtend deleted file mode 100644 index df9692346a..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/LocallyKnownTypesScopingHelper.xtend +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * 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: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.scoping.utils - -import com.google.common.collect.Iterables -import com.google.inject.Inject -import java.util.function.Supplier -import org.eclipse.emf.ecore.EObject -import org.eclipse.n4js.n4JS.N4NamespaceDeclaration -import org.eclipse.n4js.n4JS.Script -import org.eclipse.n4js.resource.N4JSCache -import org.eclipse.n4js.scoping.N4JSScopeProvider -import org.eclipse.n4js.scoping.imports.ImportedElementsScopingHelper -import org.eclipse.n4js.ts.typeRefs.FunctionTypeExpression -import org.eclipse.n4js.ts.types.AbstractNamespace -import org.eclipse.n4js.ts.types.TClassifier -import org.eclipse.n4js.ts.types.TEnum -import org.eclipse.n4js.ts.types.TStructMethod -import org.eclipse.n4js.ts.types.Type -import org.eclipse.xtext.resource.EObjectDescription -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.impl.SingletonScope - -/** - * Helper for {@link N4JSScopeProvider N4JSScopeProvider} using - * {@link ImportedElementsScopingHelper ImportedElementsScopingHelper} - * for providing scope for types provider. - */ -class LocallyKnownTypesScopingHelper { - - @Inject - N4JSCache cache - - @Inject - ImportedElementsScopingHelper importedElementsScopingHelper - - @Inject - ScopeSnapshotHelper scopeSnapshotHelper - - /** Returns the type itself and type variables in case the type is generic. */ - def IScope scopeWithTypeAndItsTypeVariables(IScope parent, Type type, boolean staticAccess) { - var IScope result = parent; - if (type !== null) { - - // add the type itself - if (type.name !== null && type instanceof TClassifier) { - // note that functions cannot be used as type references - result = new SingletonScope(EObjectDescription.create(type.name, type), result) - } - - // add the type variables - if (type.generic) { - if (type instanceof TClassifier && staticAccess) { - // error case: type variables of a classifier cannot be accessed from static members - // e.g. class C { static x: T; } - // --> return same scope as in success case, but wrap descriptions with a WrongStaticAccessorDescription - val wrapEODs = [new WrongStaticAccessDescription(it, staticAccess)]; - result = scopeSnapshotHelper.scopeForEObjects("scopeWithTypeAndItsTypeVariables-1", type, result, type.typeVars, wrapEODs); - } else { - // success case: simply add type variables to scope - result = scopeSnapshotHelper.scopeForEObjects("scopeWithTypeAndItsTypeVariables-2", type, result, type.typeVars); - } - } - } - - return result; - } - - /** Returns the type variables if the TStructMethod is generic. */ - def IScope scopeWithTypeVarsOfTStructMethod(IScope parent, TStructMethod m) { - val mDef = m.definedMember - if (mDef instanceof TStructMethod) { - if (mDef.generic) { - return scopeSnapshotHelper.scopeForEObjects("scopeWithTypeVarsOfTStructMethod", mDef, parent, mDef.typeVars); - } - } - return parent; - } - - /** Returns the type variables if the function type expression is generic. */ - def IScope scopeWithTypeVarsOfFunctionTypeExpression(IScope parent, FunctionTypeExpression funTypeExpr) { - if (funTypeExpr !== null && funTypeExpr.generic) { - return scopeSnapshotHelper.scopeForEObjects("scopeWithTypeVarsOfFunctionTypeExpression", funTypeExpr, parent, funTypeExpr.typeVars); - } - return parent; - } - - /** Returns scope with locally known types and (as parent) import scope; the result is cached. */ - def IScope scopeWithLocallyDeclaredElems(Script script, Supplier parentSupplier, boolean onlyNamespacelikes) { - return cache.get(script.eResource, [| - // all types in the index: - val parent = parentSupplier.get(); - // but imported types are preferred (or maybe renamed with aliases): - val IScope importScope = importedElementsScopingHelper.getImportedTypes(parent, script); - // finally, add locally declared types as the outer scope - val localTypes = scopeWithLocallyDeclaredElems(script, importScope, onlyNamespacelikes); - - return localTypes; - ], script, 'locallyKnownTypes_'+String.valueOf(onlyNamespacelikes)); - } - - /** Returns scope with locally declared types (without import scope). */ - def IScope scopeWithLocallyDeclaredElems(Script script, IScope parent, boolean onlyNamespacelikes) { - return scopeWithLocallyDeclaredElems(script.module, script, parent, onlyNamespacelikes); - } - - /** Returns scope with locally declared types (without import scope). */ - def IScope scopeWithLocallyDeclaredElems(N4NamespaceDeclaration namespace, IScope parent, boolean onlyNamespacelikes) { - return cache.get(namespace.eResource, [| - return scopeWithLocallyDeclaredElems(namespace.definedType as AbstractNamespace, namespace, parent, onlyNamespacelikes); - ], namespace, 'scopeWithLocallyDeclaredElems_'+String.valueOf(onlyNamespacelikes)); - } - - /** Returns scope with locally declared types (without import scope). */ - def IScope scopeWithLocallyDeclaredElems(AbstractNamespace namespace, IScope parent, boolean onlyNamespacelikes) { - return scopeWithLocallyDeclaredElems(namespace, namespace, parent, onlyNamespacelikes); - } - - /** Returns scope with locally declared types (without import scope). */ - def private IScope scopeWithLocallyDeclaredElems(AbstractNamespace ans, EObject context, IScope parent, boolean onlyNamespacelikes) { - if (ans === null || ans.eIsProxy) { - return parent; - } - val tlElems = if (onlyNamespacelikes) { - Iterables.concat(ans.namespaces, ans.types.filter[t | t instanceof TEnum ]) - } else { - ans.types.filter[t | !t.polyfill ]; - }; - val eoDescrs = tlElems.map[ topLevelType | - return EObjectDescription.create(topLevelType.name, topLevelType); - ]; - return scopeSnapshotHelper.scopeFor("scopeWithLocallyDeclaredTypes", context, parent, eoDescrs); - } - - /** - * Returns scope with locally known types specially configured for super reference in case of polyfill definitions. - * It is comparable to {@link #getLocallyKnownTypes(Script, EReference, IScopeProvider), but it does not - * add the polyfillType itself. Instead, only its type variables are added, which are otherwise hidden in case of polyfills. - * The result is not cached as this scope is needed only one time. - */ - def IScope scopeWithLocallyKnownTypesForPolyfillSuperRef(Script script, - IScope parent, Type polyfillType) { - - // imported and locally defined types are preferred (or maybe renamed with aliases): - val IScope importScope = importedElementsScopingHelper.getImportedTypes(parent, script) - - // locally defined types except polyfillType itself - val local = script.module - val eoDescrs = local.types.filter[it !== polyfillType].map[EObjectDescription.create(name, it)]; - val IScope localTypesScope = scopeSnapshotHelper.scopeFor("scopeWithLocallyKnownTypesForPolyfillSuperRef", script, importScope, eoDescrs); - - // type variables of polyfill - if (polyfillType !== null && polyfillType.generic) { - return scopeSnapshotHelper.scopeForEObjects("scopeWithLocallyKnownTypesForPolyfillSuperRef-polyfillType", polyfillType, localTypesScope, polyfillType.typeVars); - } - - // non generic: - return localTypesScope; - - } - -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.java new file mode 100644 index 0000000000..16cc6b8992 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * 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: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.scoping.utils; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.validation.JavaScriptVariantHelper; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IEObjectDescription; +import org.eclipse.xtext.scoping.IScope; +import org.eclipse.xtext.scoping.Scopes; +import org.eclipse.xtext.scoping.impl.MapBasedScope; +import org.eclipse.xtext.scoping.impl.MultimapBasedScope; +import org.eclipse.xtext.scoping.impl.SimpleScope; +import org.eclipse.xtext.util.SimpleAttributeResolver; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +/** + * Some utility methods, similar to xtext's {@link Scopes}. + */ +public class ScopesHelper { + + @Inject + private JavaScriptVariantHelper javaScriptVariantHelper; + + /** + * Creates a map based scope for the given iterable of descriptions. + * + * @param context + * The context of the scope + * @param descriptions + * The descriptions + */ + public IScope mapBasedScopeFor(EObject context, Iterable descriptions) { + return mapBasedScopeFor(context, IScope.NULLSCOPE, descriptions); + } + + /** + * Creates a map based scope for the given iterable of descriptions. + * + * @param context + * The context of the scope + * @param parent + * The parent scope + * @param descriptions + * The descriptions + */ + public IScope mapBasedScopeFor(EObject context, IScope parent, Iterable descriptions) { + if (javaScriptVariantHelper.isMultiQNScope(context)) { + return MultimapBasedScope.createScope(parent, descriptions, false); + } else { + return MapBasedScope.createScope(parent, descriptions); + } + } + + /** + * Convenience method for {@link #scopeFor(Iterable,Function,Function,IScope)}. + */ + public IScope scopeFor(Iterable elements, + Function wrapper) { + return scopeFor(elements, wrapper, IScope.NULLSCOPE); + } + + /** + * Convenience method for {@link #scopeFor(Iterable,Function,Function,IScope)}. + */ + public IScope scopeFor(Iterable elements, + Function wrapper, IScope outer) { + return scopeFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER), wrapper, outer); + } + + /** + * Similar to {@link Scopes#scopeFor(Iterable,Function,IScope)} but supports custom wrapping of the + * IEObjectDescriptions, for example to wrap them with error message providing subclasses such as + * {@link WrongStaticAccessDescription}. The wrapper can return the object description unchanged, create and return + * a new one or may return null to remove the corresponding object from the scope. + */ + public IScope scopeFor(Iterable elements, + Function nameComputation, + Function wrapper, IScope outer) { + return new SimpleScope(outer, + Iterables.transform(Scopes.scopedElementsFor(elements, nameComputation), wrapper)); + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.xtend deleted file mode 100644 index 3975a05c70..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/scoping/utils/ScopesHelper.xtend +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * 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: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.scoping.utils - -import com.google.common.base.Function -import com.google.common.collect.Iterables -import org.eclipse.emf.ecore.EObject -import org.eclipse.xtext.naming.QualifiedName -import org.eclipse.xtext.resource.IEObjectDescription -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.Scopes -import org.eclipse.xtext.scoping.impl.SimpleScope -import org.eclipse.xtext.util.SimpleAttributeResolver -import com.google.inject.Inject -import org.eclipse.n4js.validation.JavaScriptVariantHelper -import org.eclipse.xtext.scoping.impl.MapBasedScope -import org.eclipse.xtext.scoping.impl.MultimapBasedScope - -/** - * Some utility methods, similar to xtext's {@link Scopes}. - */ -public class ScopesHelper { - - @Inject - private JavaScriptVariantHelper javaScriptVariantHelper; - - /** - * Creates a map based scope for the given iterable of descriptions. - * - * @param context The context of the scope - * @param descriptions The descriptions - */ - def public IScope mapBasedScopeFor(EObject context, Iterable descriptions) { - return mapBasedScopeFor(context, IScope.NULLSCOPE, descriptions); - } - - /** - * Creates a map based scope for the given iterable of descriptions. - * - * @param context The context of the scope - * @param parent The parent scope - * @param descriptions The descriptions - */ - def public IScope mapBasedScopeFor(EObject context, IScope parent, Iterable descriptions) { - if (javaScriptVariantHelper.isMultiQNScope(context)) { - return MultimapBasedScope.createScope(parent, descriptions, false); - } else { - return MapBasedScope.createScope(parent, descriptions); - } - } - - /** - * Convenience method for {@link #scopeFor(Iterable,Function,Function,IScope)}. - */ - def public IScope scopeFor(Iterable elements, - Function wrapper) { - return scopeFor(elements, wrapper, IScope.NULLSCOPE); - } - - /** - * Convenience method for {@link #scopeFor(Iterable,Function,Function,IScope)}. - */ - def public IScope scopeFor(Iterable elements, - Function wrapper, IScope outer) { - return scopeFor(elements, QualifiedName.wrapper(SimpleAttributeResolver.NAME_RESOLVER), wrapper, outer); - } - - /** - * Similar to {@link Scopes#scopeFor(Iterable,Function,IScope)} but supports custom wrapping - * of the IEObjectDescriptions, for example to wrap them with error message providing subclasses - * such as {@link WrongStaticAccessDescription}. The wrapper can return the object description - * unchanged, create and return a new one or may return null to remove the corresponding object - * from the scope. - */ - def public IScope scopeFor(Iterable elements, - Function nameComputation, - Function wrapper, IScope outer) { - return new SimpleScope(outer, - Iterables.transform(Scopes.scopedElementsFor(elements, nameComputation), wrapper)); - } -}