diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.java new file mode 100644 index 0000000000..25f77550d9 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.java @@ -0,0 +1,76 @@ +/** + * 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.validation.validators; + +import static org.eclipse.n4js.utils.N4JSLanguageUtils.isContainedInStaticPolyfillModule; +import static org.eclipse.n4js.utils.N4JSLanguageUtils.isStaticPolyfill; +import static org.eclipse.n4js.validation.IssueCodes.POLY_IMPLEMENTING_INTERFACE_NOT_ALLOWED; +import static org.eclipse.n4js.validation.IssueCodes.POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.n4js.n4JS.ExportDeclaration; +import org.eclipse.n4js.n4JS.FunctionDeclaration; +import org.eclipse.n4js.n4JS.N4ClassDeclaration; +import org.eclipse.n4js.n4JS.N4EnumDeclaration; +import org.eclipse.n4js.n4JS.N4InterfaceDeclaration; +import org.eclipse.n4js.n4JS.N4JSPackage; +import org.eclipse.n4js.n4JS.Script; + +/** + * Collecting special validation logic only related to static polyfill modules. IDE-1735 + */ +public class StaticPolyfillValidatorExtension { + + /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ + public static void internalCheckNotInStaticPolyfillModule(N4InterfaceDeclaration n4InterfaceDeclaration, + N4JSInterfaceValidator host) { + if (isContainedInStaticPolyfillModule(n4InterfaceDeclaration)) { + host.addIssue(n4InterfaceDeclaration, N4JSPackage.Literals.N4_TYPE_DECLARATION__NAME, + POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); + } + } + + /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ + public static void internalCheckNotInStaticPolyfillModule(N4EnumDeclaration n4EnumDecl, N4JSEnumValidator host) { + if (isContainedInStaticPolyfillModule(n4EnumDecl)) { + host.addIssue(n4EnumDecl, N4JSPackage.Literals.N4_TYPE_DECLARATION__NAME, + POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); + } + } + + /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ + public static void internalCheckNotInStaticPolyfillModule(FunctionDeclaration functionDeclaration, + N4JSFunctionValidator host) { + // top level functionDeclarations: + EObject cont = functionDeclaration.eContainer(); + while (cont instanceof ExportDeclaration) { + cont = cont.eContainer(); + } + if (cont instanceof Script) { + if (isContainedInStaticPolyfillModule(functionDeclaration)) { + host.addIssue(functionDeclaration, N4JSPackage.Literals.FUNCTION_DECLARATION__NAME, + POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); + } + } + } + + /** §143 (Restriction on static-polyfilling): §143.4 P must not implement any interfaces */ + public static void internalCheckPolyFilledClassWithAdditionalInterface(N4ClassDeclaration classDeclaration, + N4JSClassValidator host) { + if (isStaticPolyfill(classDeclaration)) { + if (!classDeclaration.getImplementedInterfaceRefs().isEmpty()) { + host.addIssue(classDeclaration, N4JSPackage.Literals.N4_CLASS_DEFINITION__IMPLEMENTED_INTERFACE_REFS, + POLY_IMPLEMENTING_INTERFACE_NOT_ALLOWED.toIssueItem()); + } + } + } + +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.xtend deleted file mode 100644 index 3f8fddb082..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/StaticPolyfillValidatorExtension.xtend +++ /dev/null @@ -1,71 +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.validation.validators - -import org.eclipse.n4js.n4JS.ExportDeclaration -import org.eclipse.n4js.n4JS.FunctionDeclaration -import org.eclipse.n4js.n4JS.N4EnumDeclaration -import org.eclipse.n4js.n4JS.N4InterfaceDeclaration -import org.eclipse.n4js.n4JS.N4JSPackage -import org.eclipse.n4js.n4JS.Script -import org.eclipse.n4js.n4JS.N4ClassDeclaration - -import static org.eclipse.n4js.validation.IssueCodes.* -import static extension org.eclipse.n4js.utils.N4JSLanguageUtils.* - -/** - * Collecting special validation logic only related to static polyfill modules. - * IDE-1735 - */ -public class StaticPolyfillValidatorExtension { - - /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ - public static def internalCheckNotInStaticPolyfillModule(N4InterfaceDeclaration n4InterfaceDeclaration, N4JSInterfaceValidator host) { - if (n4InterfaceDeclaration.isContainedInStaticPolyfillModule) { - host.addIssue(n4InterfaceDeclaration, N4JSPackage.Literals.N4_TYPE_DECLARATION__NAME, - POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); - } - } - - - /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ - public static def internalCheckNotInStaticPolyfillModule(N4EnumDeclaration n4EnumDecl, N4JSEnumValidator host) { - if (n4EnumDecl.isContainedInStaticPolyfillModule) { - host.addIssue(n4EnumDecl, N4JSPackage.Literals.N4_TYPE_DECLARATION__NAME, - POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); - } - } - - /** §143 (Restriction on static-polyfilling): §143.1 only classes in staticPolyfillModule allowed. */ - public static def internalCheckNotInStaticPolyfillModule(FunctionDeclaration functionDeclaration, N4JSFunctionValidator host) { - // top level functionDeclarations: - var cont = functionDeclaration.eContainer; - while ( cont instanceof ExportDeclaration ) cont = cont.eContainer; - if( cont instanceof Script) - { - if ( functionDeclaration.isContainedInStaticPolyfillModule ) { - host.addIssue(functionDeclaration, N4JSPackage.Literals.FUNCTION_DECLARATION__NAME, - POLY_STATIC_POLYFILL_MODULE_ONLY_FILLING_CLASSES.toIssueItem()); - } - } - } - - /** §143 (Restriction on static-polyfilling): §143.4 P must not implement any interfaces */ - public static def internalCheckPolyFilledClassWithAdditionalInterface(N4ClassDeclaration classDeclaration, N4JSClassValidator host) { - if( classDeclaration.isStaticPolyfill ) { - if( ! classDeclaration.implementedInterfaceRefs.isEmpty ) { - host.addIssue(classDeclaration, N4JSPackage.Literals.N4_CLASS_DEFINITION__IMPLEMENTED_INTERFACE_REFS, - POLY_IMPLEMENTING_INTERFACE_NOT_ALLOWED.toIssueItem()); - } - } - } - -} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.java b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.java new file mode 100644 index 0000000000..b8e9bb0262 --- /dev/null +++ b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.java @@ -0,0 +1,203 @@ +/** + * 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.validation.validators; + +import static org.eclipse.n4js.utils.N4JSLanguageUtils.isNonStaticPolyfill; +import static org.eclipse.n4js.utils.N4JSLanguageUtils.isStaticPolyfill; +import static org.eclipse.n4js.validation.IssueCodes.UNSUPPORTED; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.n4js.n4JS.AnnotableElement; +import org.eclipse.n4js.n4JS.Argument; +import org.eclipse.n4js.n4JS.BindingPattern; +import org.eclipse.n4js.n4JS.ExportDeclaration; +import org.eclipse.n4js.n4JS.ExportableElement; +import org.eclipse.n4js.n4JS.FormalParameter; +import org.eclipse.n4js.n4JS.N4ClassDefinition; +import org.eclipse.n4js.n4JS.N4ClassExpression; +import org.eclipse.n4js.n4JS.N4JSPackage; +import org.eclipse.n4js.n4JS.N4NamespaceDeclaration; +import org.eclipse.n4js.n4JS.NamedElement; +import org.eclipse.n4js.n4JS.NamespaceElement; +import org.eclipse.n4js.n4JS.NewTarget; +import org.eclipse.n4js.n4JS.PropertySpread; +import org.eclipse.n4js.utils.ResourceType; +import org.eclipse.n4js.validation.ASTStructureValidator; +import org.eclipse.n4js.validation.AbstractN4JSDeclarativeValidator; +import org.eclipse.n4js.validation.JavaScriptVariantHelper; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.validation.Check; +import org.eclipse.xtext.validation.EValidatorRegistrar; + +import com.google.inject.Inject; + +/** + * Validations to show an error for unsupported language features, mostly ECMAScript6 features. These validations will + * be removed over time once the corresponding features are implemented. + */ +@SuppressWarnings("javadoc") +public class UnsupportedFeatureValidator extends AbstractN4JSDeclarativeValidator { + + @Inject + JavaScriptVariantHelper jsVariantHelper; + + /** + * NEEEDED + * + * when removed check methods will be called twice once by N4JSValidator, and once by + * AbstractDeclarativeN4JSValidator + */ + @Override + public void register(EValidatorRegistrar registrar) { + // nop + } + + @Check + public void checkAnonymousDefaultExport(ExportableElement decl) { + if (decl instanceof NamedElement) { + if (((NamedElement) decl).getName() == null && decl.isExportedAsDefault()) { + unsupported("anonymous default export", decl); + } + } + } + + @Check + public void checkSeparateExport(ExportDeclaration exportDecl) { + if (exportDecl.getExportedElement() == null) { + if (exportDecl.isDefaultExport() && exportDecl.getDefaultExportedExpression() != null) { + unsupported( + "exporting values (only declared classes, interfaces, enums, functions and variables can be exported)", + exportDecl); + } else { + boolean isDTS = ResourceType.getResourceType(exportDecl) == ResourceType.DTS; + if (!isDTS) { + unsupported( + "separate export statements (add keyword 'export' directly before a class, interface, enum, function or variable declaration)", + exportDecl); + } + } + } + } + + // TODO when removing this method, remove flag 'classExpressionsAreAllowed' as well! + @Check + public void checkClassExpression(N4ClassExpression classExpr) { + if (!classExpressionsAreAllowed) { + if (classExpr.getName() != null) { + unsupported("class expressions", classExpr, N4JSPackage.eINSTANCE.getN4ClassExpression_Name()); + } else { + unsupported("class expressions", classExpr, NodeModelUtils.getNode(classExpr).getOffset(), 5); // the + // first + // 5 + // characters + // are + // always + // the + // 'class' + // keyword + } + } + } + + private static boolean classExpressionsAreAllowed = false; + + @Check + public void checkNewTarget(NewTarget newTarget) { + unsupported("new.target", newTarget); + } + + @Check + public void checkExtendsExpression(N4ClassDefinition classDef) { + if (classDef.getSuperClassExpression() != null) { + unsupported("extends ", classDef, + N4JSPackage.eINSTANCE.getN4ClassDefinition_SuperClassExpression()); + } + } + + @Check + public void checkBindingPatternAsFpar(BindingPattern pattern) { + if (pattern.eContainer() instanceof FormalParameter) { + unsupported("destructuring patterns as formal parameter", pattern); + } + } + + /** + * NOTE: in addition to the errors produced by this and the following method, spread operator in array + * literals is also unsupported; but that is checked in + * {@link ASTStructureValidator#validateSpreadInArrayLiteral(org.eclipse.n4js.n4JS.ArrayElement, org.eclipse.n4js.validation.ASTStructureDiagnosticProducer)} + */ + @Check + public void checkSpreadOperatorInNewAndCallExpressions(Argument argument) { + if (argument.isSpread()) { + unsupported("spread operator in new and call expressions (only allowed in array destructuring patterns)", + argument, N4JSPackage.eINSTANCE.getArgument_Spread()); + } + } + + @Check + public void checkSpreadOperatorInObjectLiteral(PropertySpread propertySpread) { + unsupported("spread operator in object literals (only allowed in array destructuring patterns)", + propertySpread); + } + + @Check + public void checkNamespaceOutsideN4JSD(N4NamespaceDeclaration namespace) { + if (!jsVariantHelper.isExternalMode(namespace)) { + EObject markElem = (namespace.eContainer() instanceof ExportDeclaration) ? namespace.eContainer() + : namespace; + unsupported("namespaces in n4js/n4jsx files", markElem); + } + } + + @Check + public void checkPolyfillInNamespace(NamespaceElement elem) { + if (elem instanceof AnnotableElement) { + AnnotableElement anElem = (AnnotableElement) elem; + if (elem.getNamespace() != null && (isStaticPolyfill(anElem) || isNonStaticPolyfill(anElem))) { + unsupported("polyfills in namespaces", elem); + } + } + } + + // ---------------------------------------------------------------------------------------------------------------- + // UTILITY METHODS + + private void unsupported(String msg, EObject source) { + unsupported(msg, source, null); + } + + private void unsupported(String msg, EObject source, EStructuralFeature feature) { + addIssue( + source, feature, + UNSUPPORTED.toIssueItem(msg)); + } + + private void unsupported(String msg, EObject source, int offset, int length) { + addIssue( + source, + offset, length, + UNSUPPORTED.toIssueItem(msg)); + } + + /** + * Turns off unsupported feature validation for class expressions, invokes given function, and turns validation back + * on (for testing of class expressions). + */ + public static void allowClassExpressions(Runnable r) { + try { + classExpressionsAreAllowed = true; + r.run(); + } finally { + classExpressionsAreAllowed = false; + } + } +} diff --git a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.xtend b/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.xtend deleted file mode 100644 index 52c78939c8..0000000000 --- a/plugins/org.eclipse.n4js/src/org/eclipse/n4js/validation/validators/UnsupportedFeatureValidator.xtend +++ /dev/null @@ -1,193 +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.validation.validators - -import com.google.inject.Inject -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EStructuralFeature -import org.eclipse.n4js.n4JS.AnnotableElement -import org.eclipse.n4js.n4JS.Argument -import org.eclipse.n4js.n4JS.BindingPattern -import org.eclipse.n4js.n4JS.ExportDeclaration -import org.eclipse.n4js.n4JS.ExportableElement -import org.eclipse.n4js.n4JS.FormalParameter -import org.eclipse.n4js.n4JS.N4ClassDefinition -import org.eclipse.n4js.n4JS.N4ClassExpression -import org.eclipse.n4js.n4JS.N4JSPackage -import org.eclipse.n4js.n4JS.N4NamespaceDeclaration -import org.eclipse.n4js.n4JS.NamedElement -import org.eclipse.n4js.n4JS.NamespaceElement -import org.eclipse.n4js.n4JS.NewTarget -import org.eclipse.n4js.n4JS.PropertySpread -import org.eclipse.n4js.utils.ResourceType -import org.eclipse.n4js.validation.ASTStructureValidator -import org.eclipse.n4js.validation.AbstractN4JSDeclarativeValidator -import org.eclipse.n4js.validation.JavaScriptVariantHelper -import org.eclipse.xtext.nodemodel.util.NodeModelUtils -import org.eclipse.xtext.validation.Check -import org.eclipse.xtext.validation.EValidatorRegistrar - -import static org.eclipse.n4js.utils.N4JSLanguageUtils.* -import static org.eclipse.n4js.validation.IssueCodes.* - -/** - * Validations to show an error for unsupported language features, mostly ECMAScript6 features. - * These validations will be removed over time once the corresponding features are implemented. - */ -class UnsupportedFeatureValidator extends AbstractN4JSDeclarativeValidator { - - @Inject - JavaScriptVariantHelper jsVariantHelper; - - /** - * NEEEDED - * - * when removed check methods will be called twice once by N4JSValidator, and once by - * AbstractDeclarativeN4JSValidator - */ - override register(EValidatorRegistrar registrar) { - // nop - } - - - @Check - def void checkAnonymousDefaultExport(ExportableElement decl) { - if(decl instanceof NamedElement) { - if(decl.name===null && decl.exportedAsDefault) { - unsupported("anonymous default export", decl); - } - } - } - @Check - def void checkSeparateExport(ExportDeclaration exportDecl) { - if(exportDecl.exportedElement===null) { - if(exportDecl.defaultExport && exportDecl.defaultExportedExpression!==null) { - unsupported( - "exporting values (only declared classes, interfaces, enums, functions and variables can be exported)", - exportDecl); - } else { - val isDTS = ResourceType.getResourceType(exportDecl) === ResourceType.DTS; - if (!isDTS) { - unsupported( - "separate export statements (add keyword 'export' directly before a class, interface, enum, function or variable declaration)", - exportDecl); - } - } - } - } - - - // TODO when removing this method, remove flag 'classExpressionsAreAllowed' as well! - @Check - def void checkClassExpression(N4ClassExpression classExpr) { - if(!classExpressionsAreAllowed) { - if(classExpr.name!==null) { - unsupported("class expressions", classExpr, N4JSPackage.eINSTANCE.n4ClassExpression_Name); - } else { - unsupported("class expressions", classExpr, NodeModelUtils.getNode(classExpr).offset, 5); // the first 5 characters are always the 'class' keyword - } - } - } - private static boolean classExpressionsAreAllowed = false; - - - @Check - def void checkNewTarget(NewTarget newTarget) { - unsupported("new.target", newTarget); - } - - - @Check - def void checkExtendsExpression(N4ClassDefinition classDef) { - if(classDef.superClassExpression!==null) { - unsupported("extends ", classDef, N4JSPackage.eINSTANCE.n4ClassDefinition_SuperClassExpression); - } - } - - - @Check - def void checkBindingPatternAsFpar(BindingPattern pattern) { - if(pattern.eContainer instanceof FormalParameter) { - unsupported("destructuring patterns as formal parameter", pattern); - } - } - - - /** - * NOTE: in addition to the errors produced by this and the following method, spread operator - * in array literals is also unsupported; but that is checked in - * {@link ASTStructureValidator#validateSpreadInArrayLiteral(org.eclipse.n4js.n4JS.ArrayElement, - * org.eclipse.n4js.validation.ASTStructureDiagnosticProducer)} - */ - @Check - def void checkSpreadOperatorInNewAndCallExpressions(Argument argument) { - if(argument.spread) { - unsupported("spread operator in new and call expressions (only allowed in array destructuring patterns)", - argument, N4JSPackage.eINSTANCE.argument_Spread); - } - } - - @Check - def void checkSpreadOperatorInObjectLiteral(PropertySpread propertySpread) { - unsupported("spread operator in object literals (only allowed in array destructuring patterns)", propertySpread) - } - - - @Check - def void checkNamespaceOutsideN4JSD(N4NamespaceDeclaration namespace) { - if (!jsVariantHelper.isExternalMode(namespace)) { - val markElem = if (namespace.eContainer instanceof ExportDeclaration) namespace.eContainer else namespace; - unsupported("namespaces in n4js/n4jsx files", markElem) - } - } - - @Check - def void checkPolyfillInNamespace(NamespaceElement elem) { - if (elem instanceof AnnotableElement) { - if (elem.getNamespace !== null && (isStaticPolyfill(elem) || isNonStaticPolyfill(elem))) { - unsupported("polyfills in namespaces", elem) - } - } - } - - - // ---------------------------------------------------------------------------------------------------------------- - // UTILITY METHODS - - def private void unsupported(String msg, EObject source) { - unsupported(msg, source, null); - } - def private void unsupported(String msg, EObject source, EStructuralFeature feature) { - addIssue( - source, feature, - UNSUPPORTED.toIssueItem(msg)); - } - def private void unsupported(String msg, EObject source, int offset, int length) { - addIssue( - source, - offset, length, - UNSUPPORTED.toIssueItem(msg)); - } - - /** - * Turns off unsupported feature validation for class expressions, invokes given function, and turns validation - * back on (for testing of class expressions). - */ - def public static void allowClassExpressions(()=>void r) { - try { - classExpressionsAreAllowed = true; - r.apply(); - } - finally { - classExpressionsAreAllowed = false; - } - } -}