diff --git a/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/NashornTests.java b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/NashornTests.java index 53e61490b2a..f9a95f9b810 100644 --- a/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/NashornTests.java +++ b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/NashornTests.java @@ -1,34 +1,45 @@ package org.eclipse.cdt.qt.core.tests; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.cdt.qt.core.QMLTernCompletion; +import org.eclipse.cdt.qt.core.qmljs.IJSBinaryExpression; +import org.eclipse.cdt.qt.core.qmljs.IJSBinaryExpression.BinaryOperator; +import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode; +import org.eclipse.cdt.qt.core.qmljs.IQmlHeaderItem; +import org.eclipse.cdt.qt.core.qmljs.IQmlImport; +import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember; +import org.eclipse.cdt.qt.core.qmljs.IQmlProgram; +import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding; +import org.eclipse.cdt.qt.core.qmljs.IQmlRootObject; +import org.eclipse.cdt.qt.core.qmljs.IQmlScriptBinding; import org.junit.BeforeClass; import org.junit.Test; @SuppressWarnings("nls") public class NashornTests { - protected static QMLAnalyzer analyzer; + protected static IQMLAnalyzer analyzer; @BeforeClass public static void loadAnalyzer() { - analyzer = Activator.getService(QMLAnalyzer.class); + analyzer = Activator.getService(IQMLAnalyzer.class); } protected void getCompletions(String code, QMLTernCompletion... expected) throws Throwable { int pos = code.indexOf('|'); code = code.substring(0, pos) + code.substring(pos + 1); - Collection QMLTernCompletions = analyzer.getCompletions("test1.qml", code, pos); + Collection QMLTernCompletions = analyzer.getCompletions("test1.qml", code, pos, false); Map set = new HashMap<>(); Set unexpected = new HashSet<>(); @@ -55,7 +66,108 @@ public class NashornTests { } @Test - public void test1() throws Throwable { + public void testParseFile1() throws Throwable { + IQmlASTNode node = analyzer.parseFile("main.qml", ""); + assertEquals("Unexpected program node type", "QMLProgram", node.getType()); + } + + @Test + public void testParseFile2() throws Throwable { + IQmlASTNode node = analyzer.parseFile("main.qml", "import QtQuick 2.2"); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + List headerItems = program.getHeaderItemList().getItems(); + assertEquals("Unexpected number of header items", 1, headerItems.size()); + assertThat(headerItems.get(0), instanceOf(IQmlImport.class)); + IQmlImport imp = (IQmlImport) headerItems.get(0); + assertEquals("Unexpected module identifier", "QtQuick", imp.getModule().getIdentifier().getName()); + assertEquals("Unexpected module raw version", "2.2", imp.getModule().getVersion().getRaw()); + assertEquals("Unexpected module version", 2.2, imp.getModule().getVersion().getValue(), 0.0001d); + } + + @Test + public void testParseString1() throws Throwable { + IQmlASTNode node = analyzer.parseString("", "qml", true, true); + assertEquals("Unexpected program node type", "QMLProgram", node.getType()); + } + + @Test + public void testParseString2() throws Throwable { + IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + List headerItems = program.getHeaderItemList().getItems(); + assertEquals("Unexpected number of header items", 1, headerItems.size()); + assertThat(headerItems.get(0), instanceOf(IQmlImport.class)); + IQmlImport imp = (IQmlImport) headerItems.get(0); + assertEquals("Unexpected module identifier", "QtQuick", imp.getModule().getIdentifier().getName()); + assertEquals("Unexpected module raw version", "2.2", imp.getModule().getVersion().getRaw()); + assertEquals("Unexpected module version", 2.2, imp.getModule().getVersion().getValue(), 0.0001d); + } + + @Test + public void testParseString3() throws Throwable { + IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + List headerItems = program.getHeaderItemList().getItems(); + assertEquals("Unexpected number of header items", 1, headerItems.size()); + assertThat(headerItems.get(0), instanceOf(IQmlImport.class)); + IQmlImport imp = (IQmlImport) headerItems.get(0); + assertEquals("Unexpected start range", 0, imp.getRange()[0]); + assertEquals("Unexpected end range", 18, imp.getRange()[1]); + } + + @Test + public void testParseString4() throws Throwable { + IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + List headerItems = program.getHeaderItemList().getItems(); + assertEquals("Unexpected number of header items", 1, headerItems.size()); + assertThat(headerItems.get(0), instanceOf(IQmlImport.class)); + IQmlImport imp = (IQmlImport) headerItems.get(0); + assertEquals("Unexpected start line", 1, imp.getLocation().getStart().getLine()); + assertEquals("Unexpected start column", 0, imp.getLocation().getStart().getColumn()); + assertEquals("Unexpected start line", 1, imp.getLocation().getEnd().getLine()); + assertEquals("Unexpected start column", 18, imp.getLocation().getEnd().getColumn()); + } + + @Test + public void testParseString5() throws Throwable { + IQmlASTNode node = analyzer.parseString("QtObject {}", "qml", true, true); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + List headerItems = program.getHeaderItemList().getItems(); + assertEquals("Unexpected number of header items", 0, headerItems.size()); + assertNotNull("Root object was null", program.getRootObject()); + IQmlRootObject root = program.getRootObject(); + assertEquals("Unexpected root object type", "QMLObjectDefinition", root.getType()); + assertEquals("Unexpected root object identifier", "QtObject", root.getIdentifier().getName()); + } + + @Test + public void testParseString6() throws Throwable { + IQmlASTNode node = analyzer.parseString("QtObject {s: 3 + 3}", "qml", true, true); + assertThat(node, instanceOf(IQmlProgram.class)); + IQmlProgram program = (IQmlProgram) node; + assertNotNull("Root object was null", program.getRootObject()); + IQmlRootObject root = program.getRootObject(); + List members = root.getBody().getMembers(); + assertEquals("Unexpected number of root object members", 1, members.size()); + assertThat(members.get(0), instanceOf(IQmlPropertyBinding.class)); + IQmlPropertyBinding bind = (IQmlPropertyBinding) members.get(0); + assertThat(bind.getBinding(), instanceOf(IQmlScriptBinding.class)); + IQmlScriptBinding scriptBinding = (IQmlScriptBinding) bind.getBinding(); + assertFalse("Script binding was not a JavaScript expression", scriptBinding.isBlock()); + assertThat(scriptBinding.getScript(), instanceOf(IJSBinaryExpression.class)); + assertEquals("Unexpected expression type", "BinaryExpression", scriptBinding.getScript().getType()); + IJSBinaryExpression expr = (IJSBinaryExpression) scriptBinding.getScript(); + assertEquals("Unexpected binary operator", BinaryOperator.Add, expr.getOperator()); + } + + @Test + public void testCompletions1() throws Throwable { if (analyzer == null) { return; } @@ -64,7 +176,7 @@ public class NashornTests { } @Test - public void test2() throws Throwable { + public void testCompletions2() throws Throwable { if (analyzer == null) { return; } @@ -75,7 +187,7 @@ public class NashornTests { } @Test - public void test3() throws Throwable { + public void testCompletions3() throws Throwable { if (analyzer == null) { return; } @@ -83,7 +195,7 @@ public class NashornTests { } @Test - public void test4() throws Throwable { + public void testCompletions4() throws Throwable { if (analyzer == null) { return; } @@ -118,7 +230,7 @@ public class NashornTests { } @Test - public void test5() throws Throwable { + public void testCompletions5() throws Throwable { if (analyzer == null) { return; } @@ -153,7 +265,7 @@ public class NashornTests { } @Test - public void test6() throws Throwable { + public void testCompletions6() throws Throwable { if (analyzer == null) { return; } @@ -188,7 +300,7 @@ public class NashornTests { } @Test - public void test7() throws Throwable { + public void testCompletions7() throws Throwable { if (analyzer == null) { return; } diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 9660440da67..ac5d70d56a1 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -31,4 +31,5 @@ Export-Package: org.eclipse.cdt.internal.qt.core;x-friends:="org.eclipse.cdt.qt. org.eclipse.cdt.internal.qt.core.qmldir;x-friends:="org.eclipse.cdt.qt.core.tests", org.eclipse.cdt.qt.core, org.eclipse.cdt.qt.core.location, - org.eclipse.cdt.qt.core.qmldir + org.eclipse.cdt.qt.core.qmldir, + org.eclipse.cdt.qt.core.qmljs diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js index 1533e619851..b16dba70421 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/inject.js @@ -623,6 +623,7 @@ // replacing JavaScripts top-level. Here we are parsing such things // as the root object literal and header statements of QML. Eventually, // these rules will delegate down to JavaScript expressions. + node.mode = this.options.mode; node.headerItemList = this.qml_parseHeaderItemList(); node.rootObject = null; if (this.type !== tt.eof) { diff --git a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js index ee3eff58b7f..0c2e0425834 100644 --- a/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js +++ b/qt/org.eclipse.cdt.qt.core/acorn-qml/loose/inject.js @@ -656,6 +656,7 @@ var injectQMLLoose; // as the root object literal and header statements of QML. Eventually, // these rules will delegate down to JavaScript expressions. var node = this.startNode(); + node.mode = this.options.mode; node.headerItemList = this.qml_parseHeaderItemList(); node.rootObject = null; if (this.tok.type !== tt.eof) { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/Activator.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/Activator.java index df0e1a592a0..2c3f989c5bc 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/Activator.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/Activator.java @@ -13,8 +13,8 @@ import javax.script.ScriptException; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.internal.qt.core.build.QtBuildConfigurationFactory; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.cdt.qt.core.IQtInstallManager; -import org.eclipse.cdt.qt.core.QMLAnalyzer; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -64,8 +64,8 @@ public class Activator extends Plugin { context.registerService(IQtInstallManager.class, new QtInstallManager(), null); QMLAnalyzer qmlAnalyzer = new QMLAnalyzer(); - context.registerService(QMLAnalyzer.class, qmlAnalyzer, null); - new Job("Load QML Analyzer") { + context.registerService(IQMLAnalyzer.class, qmlAnalyzer, null); + new Job("Load QML Analyzer") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { try { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QMLAnalyzer.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QMLAnalyzer.java similarity index 64% rename from qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QMLAnalyzer.java rename to qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QMLAnalyzer.java index 3aca52cfa9a..cb30a069c25 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QMLAnalyzer.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QMLAnalyzer.java @@ -5,7 +5,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ -package org.eclipse.cdt.qt.core; +package org.eclipse.cdt.internal.qt.core; import java.io.BufferedReader; import java.io.File; @@ -27,10 +27,12 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; -import org.eclipse.cdt.internal.qt.core.Activator; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; +import org.eclipse.cdt.qt.core.QMLTernCompletion; +import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode; @SuppressWarnings("nls") -public class QMLAnalyzer { +public class QMLAnalyzer implements IQMLAnalyzer { private ScriptEngine engine; private Invocable invoke; @@ -72,6 +74,9 @@ public class QMLAnalyzer { ResolveDirectory resolveDirectory = (file, pathString) -> { String filename = (String) file.get("name"); String fileDirectory = new File(filename).getParent(); + if (fileDirectory == null) { + fileDirectory = ""; + } if (pathString == null) { return fixPathString(fileDirectory); } @@ -130,43 +135,134 @@ public class QMLAnalyzer { return fileName; } + @Override public void addFile(String fileName, String code) throws NoSuchMethodException, ScriptException { waitUntilLoaded(); invoke.invokeMethod(tern, "addFile", fixPathString(fileName), code); } + @Override public void deleteFile(String fileName) throws NoSuchMethodException, ScriptException { waitUntilLoaded(); invoke.invokeMethod(tern, "delFile", fixPathString(fileName)); } + private static class ASTCallback implements RequestCallback { + private IQmlASTNode ast; + + @Override + public void callback(Object err, Object data) { + if (err != null) { + throw new RuntimeException(err.toString()); + } else { + try { + ast = QmlASTNodeHandler.createQmlASTProxy((Bindings) ((Bindings) data).get("ast")); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + + public IQmlASTNode getAST() { + return ast; + } + } + + @Override + public IQmlASTNode parseFile(String fileName, String text) throws NoSuchMethodException, ScriptException { + waitUntilLoaded(); + fileName = fixPathString(fileName); + + Bindings query = engine.createBindings(); + query.put("type", "parseFile"); + query.put("file", fileName); + Bindings request = engine.createBindings(); + request.put("query", query); + + if (text != null) { + Bindings file = engine.createBindings(); + file.put("type", "full"); + file.put("name", fileName); + file.put("text", text); + Bindings files = (Bindings) engine.eval("new Array()"); + invoke.invokeMethod(files, "push", file); + request.put("files", files); + } + + ASTCallback callback = new ASTCallback(); + invoke.invokeMethod(tern, "request", request, invoke.invokeFunction("requestCallback", callback)); + return callback.getAST(); + } + + @Override + public IQmlASTNode parseString(String text) throws NoSuchMethodException, ScriptException { + return parseString(text, "qml", false, false); + } + + @Override + public IQmlASTNode parseString(String text, String mode, boolean locations, boolean ranges) + throws NoSuchMethodException, ScriptException { + waitUntilLoaded(); + Bindings query = engine.createBindings(); + query.put("type", "parseString"); + query.put("text", text); + Bindings options = engine.createBindings(); + options.put("mode", mode); + options.put("locations", locations); + options.put("ranges", ranges); + query.put("options", options); + Bindings request = engine.createBindings(); + request.put("query", query); + + ASTCallback callback = new ASTCallback(); + invoke.invokeMethod(tern, "request", request, invoke.invokeFunction("requestCallback", callback)); + return callback.getAST(); + } + + protected T[] toJavaArray(Bindings binding, Class clazz) throws NoSuchMethodException, ScriptException { + return clazz.cast(invoke.invokeMethod(engine.get("Java"), "to", binding, + clazz.getCanonicalName() + (clazz.isArray() ? "" : "[]"))); + } + + @Override public Collection getCompletions(String fileName, String text, int pos) throws NoSuchMethodException, ScriptException { + return getCompletions(fileName, text, pos, true); + } + + @Override + public Collection getCompletions(String fileName, String text, int pos, boolean includeKeywords) + throws NoSuchMethodException, ScriptException { waitUntilLoaded(); fileName = fixPathString(fileName); - Bindings file = engine.createBindings(); - file.put("type", "full"); - file.put("name", fileName); - file.put("text", text); - Bindings files = (Bindings) engine.eval("new Array()"); - invoke.invokeMethod(files, "push", file); Bindings query = engine.createBindings(); query.put("type", "completions"); + query.put("lineCharPositions", true); query.put("file", fileName); query.put("end", pos); query.put("types", true); query.put("docs", false); query.put("urls", false); query.put("origins", true); + query.put("filter", true); query.put("caseInsensitive", true); - query.put("lineCharPositions", true); - query.put("expandWordForward", false); - query.put("includeKeywords", true); query.put("guess", false); + query.put("sort", true); + query.put("expandWordForward", false); + query.put("includeKeywords", includeKeywords); + Bindings request = engine.createBindings(); - request.put("files", files); request.put("query", query); + if (text != null) { + Bindings file = engine.createBindings(); + file.put("type", "full"); + file.put("name", fileName); + file.put("text", text); + Bindings files = (Bindings) engine.eval("new Array()"); + invoke.invokeMethod(files, "push", file); + request.put("files", files); + } List completions = new ArrayList<>(); @@ -176,8 +272,7 @@ public class QMLAnalyzer { } else { try { Bindings comps = (Bindings) ((Bindings) data).get("completions"); - for (Bindings completion : (Bindings[]) invoke.invokeMethod(engine.get("Java"), "to", comps, - "javax.script.Bindings[]")) { + for (Bindings completion : toJavaArray(comps, Bindings[].class)) { completions.add(new QMLTernCompletion((String) completion.get("name"), (String) completion.get("type"), (String) completion.get("origin"))); } @@ -192,16 +287,11 @@ public class QMLAnalyzer { return completions; } + @Override public List getDefinition(String identifier, String fileName, String text, int pos) throws NoSuchMethodException, ScriptException { waitUntilLoaded(); fileName = fixPathString(fileName); - Bindings file = engine.createBindings(); - file.put("type", "full"); - file.put("name", fileName); - file.put("text", text); - Bindings files = (Bindings) engine.eval("new Array()"); - invoke.invokeMethod(files, "push", file); Bindings query = engine.createBindings(); query.put("type", "definition"); @@ -217,8 +307,16 @@ public class QMLAnalyzer { query.put("includeKeywords", true); query.put("guess", false); Bindings request = engine.createBindings(); - request.put("files", files); request.put("query", query); + if (text != null) { + Bindings file = engine.createBindings(); + file.put("type", "full"); + file.put("name", fileName); + file.put("text", text); + Bindings files = (Bindings) engine.eval("new Array()"); + invoke.invokeMethod(files, "push", file); + request.put("files", files); + } List definitions = new ArrayList<>(); diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QmlASTNodeHandler.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QmlASTNodeHandler.java new file mode 100644 index 00000000000..c59163b8385 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QmlASTNodeHandler.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * 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: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.qt.core; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.script.Bindings; + +import org.eclipse.cdt.internal.qt.core.location.Position; +import org.eclipse.cdt.internal.qt.core.location.SourceLocation; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; +import org.eclipse.cdt.qt.core.location.ISourceLocation; +import org.eclipse.cdt.qt.core.qmljs.IJSLiteral; +import org.eclipse.cdt.qt.core.qmljs.IJSRegExpLiteral; +import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode; +import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition; +import org.eclipse.cdt.qt.core.qmljs.IQmlRootObject; + +/** + * Translates a JavaScript {@link Bindings} object into a QML AST. This class employs {@link java.lang.reflect.Proxy} in order to + * dynamically create the AST at runtime. + *

+ * To begin translation simply call the static method createQmlASTProxy. The AST is translated only when it needs to be + * (i.e. when one of its 'get' methods are called). + */ +public class QmlASTNodeHandler implements InvocationHandler { + private static final String NODE_QML_PREFIX = "QML"; //$NON-NLS-1$ + private static final String NODE_TYPE_PROPERTY = "type"; //$NON-NLS-1$ + private static final String NODE_REGEX_PROPERTY = "regex"; //$NON-NLS-1$ + private static final String CREATE_ENUM_METHOD = "fromObject"; //$NON-NLS-1$ + private static final String AST_PACKAGE = "org.eclipse.cdt.qt.core.qmljs."; //$NON-NLS-1$ + private static final String AST_QML_PREFIX = "IQml"; //$NON-NLS-1$ + private static final String AST_JS_PREFIX = "IJS"; //$NON-NLS-1$ + + private static String getPropertyName(String method) { + String name = ""; //$NON-NLS-1$ + if (method.startsWith("is")) { //$NON-NLS-1$ + name = method.substring(2, 3).toLowerCase() + method.substring(3); + } else if (method.startsWith("get")) { //$NON-NLS-1$ + name = method.substring(3, 4).toLowerCase() + method.substring(4); + } + if (name.equalsIgnoreCase("identifier")) { //$NON-NLS-1$ + return "id"; //$NON-NLS-1$ + } else if (name.equalsIgnoreCase("location")) { //$NON-NLS-1$ + return "loc"; //$NON-NLS-1$ + } + return name; + } + + /** + * Constructs a new {@link IQmlASTNode} from the given {@link Bindings}. This is a helper method equivalent to + * createQmlASTProxy(node, null) + * + * @param node + * the AST node as retrieved from Nashorn + * @return a Proxy representing the given node + * @throws ClassNotFoundException + * if the node does not represent a valid QML AST Node + * @see {@link QmlASTNodeHandler#createQmlASTProxy(Bindings, Class)} + */ + public static IQmlASTNode createQmlASTProxy(Bindings node) throws ClassNotFoundException { + return createQmlASTProxy(node, null); + } + + /** + * Constructs a new {@link IQmlASTNode} from the given {@link Bindings}. If a return type is specified, it will take precedence + * over the type retrieved from the binding. This is useful for nodes that extend, but do not add functionality to, an acorn AST + * element. A good example of this is {@link IQmlRootObject} which extends {@link IQmlObjectDefinition}. We can easily determine + * the location in the AST at which we want an IQmlRootObject over an IQmlObjectDefinition and set the returnType accordingly. + * + * @param node + * the node as retrieved from acorn + * @param returnType + * the expected node to return or null + * @return a Proxy representing the given node + * @throws ClassNotFoundException + * if the node does not represent a valid QML AST Node + */ + public static IQmlASTNode createQmlASTProxy(Bindings node, Class returnType) throws ClassNotFoundException { + String type = (String) node.getOrDefault(NODE_TYPE_PROPERTY, ""); //$NON-NLS-1$ + if (type.startsWith(NODE_QML_PREFIX)) { + type = AST_QML_PREFIX + type.substring(3); + } else { + type = AST_JS_PREFIX + type; + } + Class astClass = Class.forName(AST_PACKAGE + type); + if (astClass.equals(IJSLiteral.class)) { + // If this is a Literal, we have to distinguish it between a RegExp Literal using the 'regex' property + if (node.get(NODE_REGEX_PROPERTY) != null) { + astClass = IJSRegExpLiteral.class; + } + } + if (returnType != null) { + if (!IQmlASTNode.class.isAssignableFrom(astClass)) { + throw new ClassCastException(astClass + " cannot be cast to " + IQmlASTNode.class); //$NON-NLS-1$ + } + if (astClass.isAssignableFrom(returnType)) { + astClass = returnType; + } + } + return (IQmlASTNode) Proxy.newProxyInstance(QmlASTNodeHandler.class.getClassLoader(), + new Class[] { astClass }, + new QmlASTNodeHandler(node)); + } + + private final QMLAnalyzer analyzer; + private final Bindings node; + private final Map methodResults; + + private QmlASTNodeHandler(Bindings node) { + this.analyzer = (QMLAnalyzer) Activator.getService(IQMLAnalyzer.class); + this.node = node; + this.methodResults = new HashMap<>(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String mName = method.getName(); + if (!methodResults.containsKey(method.getName())) { + // Invoke the default implementation of the method if possible + if (method.isDefault()) { + final Class declaringClass = method.getDeclaringClass(); + Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, + int.class); + constructor.setAccessible(true); + methodResults.put(mName, constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) + .unreflectSpecial(method, declaringClass) + .bindTo(proxy) + .invokeWithArguments(args)); + } else { + // Use the return type of the method as well as its contents of the node to get the Object to return + String pName = getPropertyName(mName); + methodResults.put(mName, handleObject(node.get(pName), method.getReturnType())); + } + } + return methodResults.get(method.getName()); + } + + private Object handleObject(Object value, Class expectedType) throws Throwable { + if (expectedType.isAssignableFrom(ISourceLocation.class)) { + // ISourceLocation doesn't correspond to an AST Node and needs to be created manually from + // the given Bindings. + if (value instanceof Bindings) { + Bindings bind = (Bindings) value; + SourceLocation loc = new SourceLocation(); + loc.setSource((String) bind.get("source")); //$NON-NLS-1$ + Bindings start = (Bindings) bind.get("start"); //$NON-NLS-1$ + loc.setStart(new Position(((Number) start.get("line")).intValue(), //$NON-NLS-1$ + ((Number) start.get("column")).intValue())); //$NON-NLS-1$ + Bindings end = (Bindings) bind.get("end"); //$NON-NLS-1$ + loc.setEnd(new Position(((Number) end.get("line")).intValue(), //$NON-NLS-1$ + ((Number) end.get("column")).intValue())); //$NON-NLS-1$ + return loc; + } + return new SourceLocation(); + } else if (expectedType.isArray()) { + Object arr = Array.newInstance(expectedType.getComponentType(), ((Bindings) value).size()); + int ctr = 0; + for (Object obj : ((Bindings) value).values()) { + Array.set(arr, ctr++, handleObject(obj, expectedType.getComponentType())); + } + return arr; + } else if (expectedType.isAssignableFrom(List.class)) { + if (value instanceof Bindings) { + List list = new ArrayList<>(); + for (Bindings object : analyzer.toJavaArray((Bindings) value, Bindings[].class)) { + list.add(QmlASTNodeHandler.createQmlASTProxy(object)); + } + return list; + } + return null; + } else if (expectedType.isPrimitive()) { + return handlePrimitive(value, expectedType); + } else if (expectedType.isAssignableFrom(Number.class)) { + if (value instanceof Number) { + return value; + } + return new Integer(0); + } else if (expectedType.isEnum()) { + return expectedType.getMethod(CREATE_ENUM_METHOD, Object.class).invoke(null, value); + } else if (value instanceof Bindings) { + return QmlASTNodeHandler.createQmlASTProxy((Bindings) value, expectedType); + } + return value; + } + + private Object handlePrimitive(Object value, Class expectedType) throws Throwable { + if (expectedType.isPrimitive()) { + if (expectedType.equals(Boolean.TYPE)) { + if (value instanceof Boolean) { + return value; + } + return false; + } else if (expectedType.equals(Character.TYPE)) { + if (value instanceof Character) { + return value; + } + return '\0'; + } else if (expectedType.equals(Byte.TYPE)) { + if (value instanceof Number) { + return ((Number) value).byteValue(); + } + return (byte) 0; + } else if (expectedType.equals(Short.TYPE)) { + if (value instanceof Number) { + return ((Number) value).shortValue(); + } + return (short) 0; + } else if (expectedType.equals(Integer.TYPE)) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return 0; + } else if (expectedType.equals(Long.TYPE)) { + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return 0l; + } else if (expectedType.equals(Float.TYPE)) { + if (value instanceof Number) { + return ((Number) value).floatValue(); + } + return 0.0f; + } else if (expectedType.equals(Double.TYPE)) { + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return 0.0d; + } + } + throw new IllegalArgumentException("expectedType was not a primitive type"); //$NON-NLS-1$ + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQMLAnalyzer.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQMLAnalyzer.java new file mode 100644 index 00000000000..6c8343f110f --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/IQMLAnalyzer.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2015 QNX Software Systems and others. + * 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: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.qt.core; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import javax.script.Bindings; +import javax.script.ScriptException; + +import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode; + +public interface IQMLAnalyzer { + + void addFile(String fileName, String code) throws NoSuchMethodException, ScriptException; + + void deleteFile(String fileName) throws NoSuchMethodException, ScriptException; + + IQmlASTNode parseFile(String fileName, String text) throws NoSuchMethodException, ScriptException; + + IQmlASTNode parseString(String text) throws NoSuchMethodException, ScriptException; + + IQmlASTNode parseString(String text, String mode, boolean locations, boolean ranges) + throws NoSuchMethodException, ScriptException; + + Collection getCompletions(String fileName, String text, int pos) + throws NoSuchMethodException, ScriptException; + + Collection getCompletions(String fileName, String text, int pos, boolean includeKeywords) + throws NoSuchMethodException, ScriptException; + + List getDefinition(String identifier, String fileName, String text, int pos) + throws NoSuchMethodException, ScriptException; + + void load() throws ScriptException, IOException, NoSuchMethodException; + +} \ No newline at end of file diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSAssignmentExpression.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSAssignmentExpression.java index d07c0ef80d2..0bd47ba92be 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSAssignmentExpression.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSAssignmentExpression.java @@ -32,6 +32,17 @@ public interface IJSAssignmentExpression extends IJSExpression { AssignExclusiveOr("^"), //$NON-NLS-1$ AssignAnd("&="); //$NON-NLS-1$ + public static AssignmentOperator fromObject(Object obj) { + if (obj instanceof String) { + for (AssignmentOperator op : AssignmentOperator.values()) { + if (obj.equals(op.toString())) { + return op; + } + } + } + return null; + } + private final String op; private AssignmentOperator(String op) { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSBinaryExpression.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSBinaryExpression.java index 43790d77d59..37958a8ce76 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSBinaryExpression.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSBinaryExpression.java @@ -40,6 +40,17 @@ public interface IJSBinaryExpression extends IJSExpression { In("in"), //$NON-NLS-1$ Instanceof("instanceof"); //$NON-NLS-1$ + public static BinaryOperator fromObject(Object obj) { + if (obj instanceof String) { + for (BinaryOperator op : BinaryOperator.values()) { + if (obj.equals(op.toString())) { + return op; + } + } + } + return null; + } + private final String op; private BinaryOperator(String op) { @@ -54,7 +65,7 @@ public interface IJSBinaryExpression extends IJSExpression { @Override default String getType() { - return "UnaryExpression"; //$NON-NLS-1$ + return "BinaryExpression"; //$NON-NLS-1$ } public BinaryOperator getOperator(); diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSLogicalExpression.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSLogicalExpression.java index de224729607..b79c83caddf 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSLogicalExpression.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSLogicalExpression.java @@ -22,6 +22,17 @@ public interface IJSLogicalExpression extends IJSExpression { Or("||"), //$NON-NLS-1$ And("&&"); //$NON-NLS-1$ + public static LogicalOperator fromObject(Object obj) { + if (obj instanceof String) { + for (LogicalOperator op : LogicalOperator.values()) { + if (obj.equals(op.toString())) { + return op; + } + } + } + return null; + } + private final String op; private LogicalOperator(String op) { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUnaryExpression.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUnaryExpression.java index 6fe2c021b12..389a2a7f8bc 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUnaryExpression.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUnaryExpression.java @@ -27,6 +27,17 @@ public interface IJSUnaryExpression extends IJSExpression { Void("void"), //$NON-NLS-1$ Delete("delete"); //$NON-NLS-1$ + public static UnaryOperator fromObject(Object obj) { + if (obj instanceof String) { + for (UnaryOperator op : UnaryOperator.values()) { + if (obj.equals(op.toString())) { + return op; + } + } + } + return null; + } + private final String op; private UnaryOperator(String op) { diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUpdateExpression.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUpdateExpression.java index cddb8461a3e..3a771f7fdc7 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUpdateExpression.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmljs/IJSUpdateExpression.java @@ -22,6 +22,17 @@ public interface IJSUpdateExpression extends IQmlASTNode { Decrement("--"), //$NON-NLS-1$ Increment("++"); //$NON-NLS-1$ + public static UpdateOperator fromObject(Object obj) { + if (obj instanceof String) { + for (UpdateOperator op : UpdateOperator.values()) { + if (obj.equals(op.toString())) { + return op; + } + } + } + return null; + } + private final String op; private UpdateOperator(String op) { diff --git a/qt/org.eclipse.cdt.qt.core/tern-qml/qml.js b/qt/org.eclipse.cdt.qt.core/tern-qml/qml.js index 63bfd5d1b9d..fec8f8538c6 100644 --- a/qt/org.eclipse.cdt.qt.core/tern-qml/qml.js +++ b/qt/org.eclipse.cdt.qt.core/tern-qml/qml.js @@ -969,20 +969,20 @@ if (query.file) { // Get the file's AST. It should have been parsed already by the server. ast = file.ast; - } else if (query.text) { + } else { // Parse the file manually and get the AST. - var text = query.text; - var options = query.options || { + var options = { + directSourceFile: file, allowReturnOutsideFunction: true, allowImportExportEverywhere: true, ecmaVersion: srv.options.ecmaVersion }; - srv.signalReturnFirst("preParse", text, options); - try { - ast = acorn.parse(text, options); - } catch (e) { - ast = acorn.parse_dammit(text, options); + for (var opt in query.options) { + options[opt] = query.options[opt]; } + query.text = query.text || ""; + var text = srv.signalReturnFirst("preParse", query.text, options) || query.text; + ast = infer.parse(text, options); srv.signal("postParse", ast, text); } return { diff --git a/qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js b/qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js index c4585d8e365..ae6ecd9367d 100644 --- a/qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js +++ b/qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js @@ -29,7 +29,7 @@ test("{Parse existing file}", function (server, callback, name) { if (err) { throw err; } - if (!resp.ast && resp.ast.type === "QMLProgram") { + if (!resp.ast || resp.ast.type !== "QMLProgram") { return callback("fail", name, "AST could not be found in response"); } return callback("ok", name); @@ -53,14 +53,33 @@ test("{Parse given file}", function (server, callback, name) { if (err) { throw err; } - if (!resp.ast && resp.ast.type === "QMLProgram") { + if (!resp.ast || resp.ast.type !== "QMLProgram") { return callback("fail", name, "AST could not be found in response"); } return callback("ok", name); }); }); -test("{Parse text}", function (server, callback, name) { +test("{Parse empty text}", function (server, callback, name) { + server.request({ + query: { + type: "parseString", + text: "" + } + }, function (err, resp) { + if (err) { + throw err; + } + if (!resp.ast) { + return callback("fail", name, "AST could not be found in response"); + } else if (resp.ast.type !== "QMLProgram" || resp.ast.mode !== "qml") { + return callback("fail", name, "AST was not a QMLProgram with mode 'qml'"); + } + return callback("ok", name); + }); +}); + +test("{Parse text no mode}", function (server, callback, name) { server.request({ query: { type: "parseString", @@ -70,8 +89,57 @@ test("{Parse text}", function (server, callback, name) { if (err) { throw err; } - if (!resp.ast && resp.ast.type === "QMLProgram") { + if (!resp.ast) { return callback("fail", name, "AST could not be found in response"); + } else if (resp.ast.type !== "QMLProgram" || resp.ast.mode !== "qml") { + return callback("fail", name, "AST was not a QMLProgram with mode 'qml'"); + } + return callback("ok", name); + }); +}); + +test("{Parse text (mode: qmltypes)}", function (server, callback, name) { + server.request({ + query: { + type: "parseString", + text: "QtObject {\n\tobj: {\n\t\tprop1: 1,\n\t\tprop2: 2\n\t}\n}", + options: { + mode: "qmltypes" + } + } + }, function (err, resp) { + if (err) { + throw err; + } + if (!resp.ast) { + return callback("fail", name, "AST could not be found in response"); + } else if (resp.ast.type !== "QMLProgram" || resp.ast.mode !== "qmltypes") { + return callback("fail", name, "AST was not a QMLProgram with mode 'qmltypes'"); + } + return callback("ok", name); + }); +}); + +test("{Parse text with locations}", function (server, callback, name) { + server.request({ + query: { + type: "parseString", + text: "var w = 3", + options: { + mode: "js", + locations: true + } + } + }, function (err, resp) { + if (err) { + throw err; + } + if (!resp.ast) { + return callback("fail", name, "AST could not be found in response"); + } else if (resp.ast.type !== "Program") { + return callback("fail", name, "AST was not a JavaScript Program"); + } else if (!resp.ast.loc) { + return callback("fail", name, "AST had no loc object"); } return callback("ok", name); }); diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLContentAssistProcessor.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLContentAssistProcessor.java index a7de25a2720..6e1e79794a2 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLContentAssistProcessor.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLContentAssistProcessor.java @@ -13,7 +13,7 @@ import java.util.Collection; import javax.script.ScriptException; import org.eclipse.cdt.internal.qt.ui.Activator; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.cdt.qt.core.QMLTernCompletion; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -29,7 +29,7 @@ public class QMLContentAssistProcessor implements IContentAssistProcessor { private static final IContextInformation[] NO_CONTEXTS = {}; private static final ICompletionProposal[] NO_COMPLETIONS = {}; - private final QMLAnalyzer analyzer = Activator.getService(QMLAnalyzer.class); + private final IQMLAnalyzer analyzer = Activator.getService(IQMLAnalyzer.class); private final QMLEditor editor; public QMLContentAssistProcessor(QMLEditor editor) { diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLEditor.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLEditor.java index 7339ca15618..1be6776a615 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLEditor.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLEditor.java @@ -16,7 +16,7 @@ import javax.script.ScriptException; import org.eclipse.cdt.internal.qt.ui.Activator; import org.eclipse.cdt.internal.qt.ui.actions.OpenDeclarationsAction; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.preference.IPreferenceStore; @@ -41,7 +41,7 @@ public class QMLEditor extends TextEditor { private static final String BRACKET_MATCHING_PREFERENCE = "org.eclipse.cdt.qt.ui.qmlMatchingBrackets"; //$NON-NLS-1$ private static final char[] BRACKETS = { '{', '}', '(', ')', '[', ']' }; - private final QMLAnalyzer analyzer = Activator.getService(QMLAnalyzer.class); + private final IQMLAnalyzer analyzer = Activator.getService(IQMLAnalyzer.class); @Override protected void initializeEditor() { diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLHyperlink.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLHyperlink.java index d81873aac0e..c74b170f9d3 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLHyperlink.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/editor/QMLHyperlink.java @@ -14,7 +14,7 @@ import javax.script.Bindings; import javax.script.ScriptException; import org.eclipse.cdt.internal.qt.core.Activator; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.jface.text.BadLocationException; @@ -57,7 +57,7 @@ public class QMLHyperlink implements IHyperlink { @Override public void open() { - QMLAnalyzer analyzer = Activator.getService(QMLAnalyzer.class); + IQMLAnalyzer analyzer = Activator.getService(IQMLAnalyzer.class); try { IDocument document = viewer.getDocument(); String selected = document.get(region.getOffset(), region.getLength()); diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/resources/QMLTernFileUpdateJob.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/resources/QMLTernFileUpdateJob.java index ad9644c9f2d..8c97f80dcc8 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/resources/QMLTernFileUpdateJob.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/resources/QMLTernFileUpdateJob.java @@ -17,7 +17,7 @@ import java.util.List; import javax.script.ScriptException; import org.eclipse.cdt.internal.qt.ui.Activator; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; @@ -30,7 +30,7 @@ import org.eclipse.core.runtime.jobs.Job; public class QMLTernFileUpdateJob extends Job { private List deltaList; - private final QMLAnalyzer analyzer = Activator.getService(QMLAnalyzer.class); + private final IQMLAnalyzer analyzer = Activator.getService(IQMLAnalyzer.class); public QMLTernFileUpdateJob(List deltas) { super("Add/Remove Files in Tern"); //$NON-NLS-1$ diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/handlers/ReloadAnalyzerHandler.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/handlers/ReloadAnalyzerHandler.java index 78b4d8c036f..5e394a782bb 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/handlers/ReloadAnalyzerHandler.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/handlers/ReloadAnalyzerHandler.java @@ -12,7 +12,7 @@ import java.io.IOException; import javax.script.ScriptException; import org.eclipse.cdt.internal.qt.core.Activator; -import org.eclipse.cdt.qt.core.QMLAnalyzer; +import org.eclipse.cdt.qt.core.IQMLAnalyzer; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; @@ -23,7 +23,7 @@ import org.eclipse.core.runtime.jobs.Job; /** * Our sample handler extends AbstractHandler, an IHandler base class. - * + * * @see org.eclipse.core.commands.IHandler * @see org.eclipse.core.commands.AbstractHandler */ @@ -35,7 +35,7 @@ public class ReloadAnalyzerHandler extends AbstractHandler { @Override protected IStatus run(IProgressMonitor monitor) { try { - Activator.getService(QMLAnalyzer.class).load(); + Activator.getService(IQMLAnalyzer.class).load(); } catch (NoSuchMethodException | ScriptException | IOException e) { return Activator.error("Reloading QML Analyzer", e); }