This is an automated email from the ASF dual-hosted git repository.
geertjan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 41da26b [NETBEANS-253] Fixing watches with lambdas. (#358)
41da26b is described below
commit 41da26b7de7506c86dee891b88b50f3c6f37b5bb
Author: Jan Lahoda <[email protected]>
AuthorDate: Wed Jan 31 18:49:31 2018 +0100
[NETBEANS-253] Fixing watches with lambdas. (#358)
-passing an URI to the created (memory) FileObject when compiling a class
using JavaSourceUtilImpl to prevent exceptions
-improving type detection for watches (don't using
Trees.getElement(...).getReturnType() and alike, but rather
Trees.getTypeMirror(...), as the latter has generics instantiated, etc.)
---
debugger.jpda.projects/nbproject/project.xml | 31 +++++
.../debugger/jpda/projects/ScanLocalVars.java | 33 +----
.../jpda/projects/CodeSnippetCompilerTest.java | 107 +++++++++++++++
.../modules/java/source/JavaSourceUtilImpl.java | 2 +
.../modules/java/source/indexing/APTUtils.java | 4 +-
.../java/source/JavaSourceUtilImplTest.java | 147 ++++++++++++++++++++-
6 files changed, 295 insertions(+), 29 deletions(-)
diff --git a/debugger.jpda.projects/nbproject/project.xml
b/debugger.jpda.projects/nbproject/project.xml
index e223d09..c1c6ce7 100644
--- a/debugger.jpda.projects/nbproject/project.xml
+++ b/debugger.jpda.projects/nbproject/project.xml
@@ -178,10 +178,41 @@
<compile-dependency/>
</test-dependency>
<test-dependency>
+
<code-name-base>org.netbeans.modules.classfile</code-name-base>
+ <compile-dependency/>
+ </test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
+ <compile-dependency/>
+ <test/>
+ </test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.java.source</code-name-base>
+ <compile-dependency/>
+ </test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.java.source.base</code-name-base>
+ <compile-dependency/>
+ <test/>
+ </test-dependency>
+ <test-dependency>
<code-name-base>org.netbeans.modules.nbjunit</code-name-base>
<recursive/>
<compile-dependency/>
</test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.parsing.indexing</code-name-base>
+ <compile-dependency/>
+ <test/>
+ </test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.parsing.nb</code-name-base>
+ <compile-dependency/>
+ </test-dependency>
+ <test-dependency>
+
<code-name-base>org.netbeans.modules.projectapi.nb</code-name-base>
+ <compile-dependency/>
+ </test-dependency>
</test-type>
</test-dependencies>
<friend-packages>
diff --git
a/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/ScanLocalVars.java
b/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/ScanLocalVars.java
index b14bc6a..2151563 100644
---
a/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/ScanLocalVars.java
+++
b/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/ScanLocalVars.java
@@ -133,9 +133,9 @@ final class ScanLocalVars extends
ErrorAwareTreePathScanner<Void, Void> {
public Void visitReturn(ReturnTree node, Void p) {
if (isMethodCode() /*&& phase == PHASE_INSIDE_SELECTION*/) {
hasReturns = true;
- Element retExpElem = info.getTrees().getElement(new
TreePath(getCurrentPath(), node.getExpression())); //.asType().toString();
- if (retExpElem != null) {
- returnTypes.add(getElementType(retExpElem));
+ TypeMirror type = info.getTrees().getTypeMirror(new
TreePath(getCurrentPath(), node.getExpression())); //.asType().toString();
+ if (type != null && type.getKind() != TypeKind.ERROR) {
+ returnTypes.add(type);
} else {
// Unresolved element
TypeElement object =
info.getElements().getTypeElement("java.lang.Object");
@@ -152,36 +152,15 @@ final class ScanLocalVars extends
ErrorAwareTreePathScanner<Void, Void> {
if (node == lastStatement) {
if (!hasReturns) {
ExpressionTree expression = node.getExpression();
- Element retExpElem = info.getTrees().getElement(new
TreePath(getCurrentPath(), expression));
- if (retExpElem == null) {
- TreePath elementPath = null;
- if (Tree.Kind.ASSIGNMENT.equals(expression.getKind())) {
- elementPath = new TreePath(getCurrentPath(),
((AssignmentTree) expression).getVariable());
- } else if
(Tree.Kind.VARIABLE.equals(expression.getKind())) {
- elementPath = new TreePath(getCurrentPath(),
((VariableTree) expression));
- }
- if (elementPath != null) {
- retExpElem = info.getTrees().getElement(elementPath);
- }
- }
- if (retExpElem != null &&
!TypeKind.ERROR.equals(retExpElem.asType().getKind())) {
- returnTypes.add(getElementType(retExpElem));
+ TypeMirror type = info.getTrees().getTypeMirror(new
TreePath(getCurrentPath(), expression));
+ if (type != null && !TypeKind.ERROR.equals(type.getKind())) {
+ returnTypes.add(type);
}
}
}
return super.visitExpressionStatement(node, p);
}
- private TypeMirror getElementType(Element element) {
- switch (element.getKind()) {
- case METHOD:
- case CONSTRUCTOR:
- return ((ExecutableElement) element).getReturnType();
- default:
- return element.asType();
- }
- }
-
Set<VariableElement> getReferencedVariables() {
return referencedVariables;
}
diff --git
a/debugger.jpda.projects/test/unit/src/org/netbeans/modules/debugger/jpda/projects/CodeSnippetCompilerTest.java
b/debugger.jpda.projects/test/unit/src/org/netbeans/modules/debugger/jpda/projects/CodeSnippetCompilerTest.java
new file mode 100644
index 0000000..8dd3a8f
--- /dev/null
+++
b/debugger.jpda.projects/test/unit/src/org/netbeans/modules/debugger/jpda/projects/CodeSnippetCompilerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.projects;
+
+import com.sun.source.tree.StatementTree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+import java.io.ByteArrayInputStream;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.SourceUtilsTestUtil;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.spi.java.classpath.ClassPathProvider;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+/**
+ *
+ * @author lahvac
+ */
+public class CodeSnippetCompilerTest extends NbTestCase {
+
+ public CodeSnippetCompilerTest(String name) {
+ super(name);
+ }
+
+ private FileObject wd;
+ private FileObject root;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearWorkDir();
+ SourceUtilsTestUtil.prepareTest(new String[0], new Object[] {
+ new ClassPathProvider() {
+ @Override
+ public ClassPath findClassPath(FileObject file, String type) {
+ if (type == ClassPath.SOURCE) {
+ return ClassPathSupport.createClassPath(root);
+ }
+ return null;
+ }
+ }
+ });
+ wd = FileUtil.toFileObject(FileUtil.normalizeFile(getWorkDir()));
+ root = FileUtil.createFolder(wd, "src"); //NOI18N
+ }
+
+ private static FileObject createFile(
+ final FileObject root,
+ final String path,
+ final String content) throws Exception {
+ FileObject file = FileUtil.createData(root, path);
+ TestUtilities.copyStringToFile(file, content);
+ return file;
+ }
+
+ public void testInferResultType() throws Exception {
+ String code = "package test;\n class A { public void
test(java.util.List<String> l) { } }";
+ String watch = "l.stream().map(s ->
s.length()).collect(java.util.stream.Collectors.toList());";
+ int pos = code.indexOf("{", code.indexOf("{") + 1);
+ FileObject java = createFile(root, "test/A.java", code); //NOI18N
+
JavaSource.forFileObject(java).runUserActionTask((CompilationController cc) -> {
+ cc.toPhase(Phase.RESOLVED);
+ TreePath posPath = cc.getTreeUtilities().pathFor(pos);
+ StatementTree tree = cc.getTreeUtilities().parseStatement(
+ watch,
+ new SourcePositions[1]
+ );
+ cc.getTreeUtilities().attributeTree(tree,
cc.getTrees().getScope(posPath));
+ TreePath tp = new TreePath(posPath, tree);
+ ClassToInvoke cti = CodeSnippetCompiler.compileToClass(cc, watch,
0, cc.getJavaSource(), java, -1, tp, tree, false);
+
+ ClassFile cf = ClassFile.read(new
ByteArrayInputStream(cti.bytecode));
+
+ for (Method m : cf.methods) {
+ if
(cf.constant_pool.getUTF8Value(m.name_index).equals("invoke")) {
+ assertEquals("(Ljava/util/List;)Ljava/util/List;",
cf.constant_pool.getUTF8Value(m.descriptor.index));
+ }
+ }
+ }, true);
+
+ }
+
+}
diff --git
a/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java
b/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java
index 6c6b060..5d0f203 100644
---
a/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java
+++
b/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java
@@ -143,6 +143,8 @@ public final class JavaSourceUtilImpl extends
org.netbeans.modules.java.preproce
final JavaFileObject toCompile = FileObjects.memoryFileObject(
ncs[0],
ncs[1]+'.'+file.getExt(),
+ file.toURI(),
+ System.currentTimeMillis(),
content);
boolean success = false;
final TransactionContext ctx = TransactionContext.beginTrans()
diff --git
a/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java
b/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java
index 3f26bcc..68e4a4b 100644
---
a/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java
+++
b/java.source.base/src/org/netbeans/modules/java/source/indexing/APTUtils.java
@@ -269,9 +269,11 @@ public class APTUtils implements ChangeListener,
PropertyChangeListener {
if (pp == null) {
pp = ClassPath.EMPTY;
}
+ ClassLoader contextCL = Context.class.getClassLoader();
cl = CachingArchiveClassLoader.forClassPath(
pp,
- new
BypassOpenIDEUtilClassLoader(Context.class.getClassLoader()),
+ contextCL != null ? new
BypassOpenIDEUtilClassLoader(contextCL)
+ :
ClassLoader.getSystemClassLoader().getParent(),
usedRoots);
classLoaderCache = !DISABLE_CLASSLOADER_CACHE ? new
ClassLoaderRef(cl, root, isModule) : null;
} else {
diff --git
a/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java
b/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java
index 4db230e..90e55f9 100644
---
a/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java
+++
b/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java
@@ -21,20 +21,35 @@ package org.netbeans.modules.java.source;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.net.URL;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.swing.event.ChangeListener;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
import org.junit.Before;
import org.junit.Test;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.JavaClassPathConstants;
+import org.netbeans.api.java.queries.AnnotationProcessingQuery;
import org.netbeans.api.java.source.TestUtilities;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.classfile.ClassFile;
import org.netbeans.modules.java.source.parsing.FileObjects;
+import org.netbeans.spi.java.classpath.ClassPathProvider;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
+import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
+import org.openide.util.test.MockLookup;
/**
*
@@ -45,6 +60,9 @@ public class JavaSourceUtilImplTest extends NbTestCase {
private FileObject wd;
private FileObject root;
private FileObject java;
+ private FileObject cache;
+ private FileObject cacheSrc;
+ private FileObject ap;
public JavaSourceUtilImplTest(String name) {
super(name);
@@ -58,13 +76,136 @@ public class JavaSourceUtilImplTest extends NbTestCase {
wd = FileUtil.toFileObject(FileUtil.normalizeFile(getWorkDir()));
root = FileUtil.createFolder(wd, "src"); //NOI18N
java = createFile(root, "org/nb/A.java","package nb;\n class A {}");
//NOI18N
+ cache = FileUtil.createFolder(wd, "cache"); //NOI18N
+ cacheSrc = FileUtil.createFolder(wd, "cacheSrc"); //NOI18N
+ ap = createFile(cacheSrc, "test/AP.java",""); //NOI18N
}
@Test
public void testGenerate() throws Exception {
+ MockLookup.setInstances(new SourceLevelQueryImplementation() {
+ @Override
+ public String getSourceLevel(FileObject javaFile) {
+ return "1.8";
+ }
+ });
+ assertNotNull(root);
+ assertNotNull(java);
+ DiagnosticListener<JavaFileObject> noErrors = d -> {
+ fail(d.getMessage(null));
+ };
+ final Map<String, byte[]> res = new
JavaSourceUtilImpl().generate(root, java, "package nb;\n class A { void
foo(){}}", noErrors); //NOI18N
+ assertNotNull(res);
+ assertEquals(1, res.size());
+ Map.Entry<String,byte[]> e = res.entrySet().iterator().next();
+ assertEquals("nb.A", e.getKey()); //NOI18N
+ final ClassFile cf = new ClassFile(new
ByteArrayInputStream(e.getValue()));
+ assertEquals(2, cf.getMethodCount());
+ final Set<String> methods = cf.getMethods().stream()
+ .map((m) -> m.getName())
+ .collect(Collectors.toSet());
+ assertEquals(
+ new HashSet<>(Arrays.asList(new String[]{
+ "<init>", //NOI18N
+ "foo" //NOI18N
+ })),
+ methods);
+ }
+
+ @Test
+ public void testGenerateWithAP() throws Exception {
+ MockLookup.setInstances(new AnnotationProcessingQueryImplementation() {
+ @Override
+ public AnnotationProcessingQuery.Result
getAnnotationProcessingOptions(FileObject file) {
+ if (file != java && file != root) return null;
+ return new AnnotationProcessingQuery.Result() {
+ @Override
+ public Set<? extends AnnotationProcessingQuery.Trigger>
annotationProcessingEnabled() {
+ return
EnumSet.allOf(AnnotationProcessingQuery.Trigger.class);
+ }
+
+ @Override
+ public Iterable<? extends String>
annotationProcessorsToRun() {
+ return Arrays.asList("test.AP");
+ }
+
+ @Override
+ public URL sourceOutputDirectory() {
+ return cache.toURL();
+ }
+
+ @Override
+ public Map<? extends String, ? extends String>
processorOptions() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void addChangeListener(ChangeListener l) {
+ }
+
+ @Override
+ public void removeChangeListener(ChangeListener l) {
+ }
+ };
+ }
+ }, new ClassPathProvider() {
+ @Override
+ public ClassPath findClassPath(FileObject file, String type) {
+ if (file != java && file != root) return null;
+ if (type == JavaClassPathConstants.PROCESSOR_PATH) {
+ return ClassPathSupport.createClassPath(cache);
+ } else if (type == ClassPath.SOURCE) {
+ return ClassPathSupport.createClassPath(root);
+ }
+ return null;
+ }
+ }, new SourceLevelQueryImplementation() {
+ @Override
+ public String getSourceLevel(FileObject javaFile) {
+ return "1.8";
+ }
+ });
+
+ String apCode = "package test;\n" +
+ "\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.Writer;\n" +
+ "import java.util.Set;\n" +
+ "import
javax.annotation.processing.AbstractProcessor;\n" +
+ "import
javax.annotation.processing.RoundEnvironment;\n" +
+ "import
javax.annotation.processing.SupportedAnnotationTypes;\n" +
+ "import
javax.annotation.processing.SupportedSourceVersion;\n" +
+ "import javax.lang.model.element.TypeElement;\n" +
+ "import javax.lang.model.SourceVersion;\n" +
+ "\n" +
+ "@SupportedAnnotationTypes(\"*\")
@SupportedSourceVersion(SourceVersion.RELEASE_8)\n" +
+ "public class AP extends AbstractProcessor {\n" +
+ " int round;\n" +
+ " @Override\n" +
+ " public boolean process(Set<? extends TypeElement>
arg0, RoundEnvironment arg1) {\n" +
+ " if (round++ == 0) {\n" +
+ " try (Writer w =
processingEnv.getFiler().createSourceFile(\"nb.Dep\").openWriter()) {\n" +
+ " w.write(\"package nb; class Dep {
}\");\n" +
+ " } catch (IOException ex) {\n" +
+ " ex.printStackTrace();\n" +
+ " throw new
IllegalStateException(ex);\n" +
+ " }\n" +
+ " }\n" +
+ " return false;\n" +
+ " }\n" +
+ " \n" +
+ "}\n";
+ DiagnosticListener<JavaFileObject> noErrors = d -> {
+ fail(d.getMessage(null));
+ };
+ for (Entry<String, byte[]> e : new
JavaSourceUtilImpl().generate(cacheSrc, ap, apCode, noErrors).entrySet()) {
+ try (OutputStream out = FileUtil.createData(cache,
e.getKey().replace(".", "/") + ".class").getOutputStream()) {
+ out.write(e.getValue());
+ }
+ }
assertNotNull(root);
assertNotNull(java);
- final Map<String, byte[]> res = new
JavaSourceUtilImpl().generate(root, java, "package nb;\n class A { void
foo(){}}", null); //NOI18N
+ final Map<String, byte[]> res = new
JavaSourceUtilImpl().generate(root, java, "package nb;\n class A { Dep dep;
void foo(){}}", noErrors); //NOI18N
assertNotNull(res);
assertEquals(1, res.size());
Map.Entry<String,byte[]> e = res.entrySet().iterator().next();
@@ -108,4 +249,8 @@ public class JavaSourceUtilImplTest extends NbTestCase {
}
System.out.printf("Dumped into: %s%n",
FileUtil.getFileDisplayName(wd));
}
+
+ static {
+ System.setProperty("SourcePath.no.source.filter", "true");
+ }
}
--
To stop receiving notification emails like this one, please contact
[email protected].
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists