diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CUResolver.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CUResolver.java index 697e1ef99..395501302 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CUResolver.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CUResolver.java @@ -1,3 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; import java.lang.reflect.Constructor; @@ -28,6 +38,13 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Supplier; +/** + * Reflection based implementation of JDT package public CompilationUnitResolver. + * It is used to resolve the {@link CompilationUnitDeclaration} + * + * @author Alex Boyko + * + */ class CUResolver { private static final Logger log = LoggerFactory.getLogger(CUResolver.class); @@ -65,40 +82,7 @@ class CUResolver { return null; } }; - - private static final Supplier BITS_FIELD = () -> { - try { - Field field = ASTParser.class.getDeclaredField("bits"); - field.setAccessible(true); - return field; - } catch (SecurityException | NoSuchFieldException e) { - log.error("{}", e); - return null; - } - }; - - private static final Supplier WORKING_COPY_OWNER_FIELD = () -> { - try { - Field field = ASTParser.class.getDeclaredField("workingCopyOwner"); - field.setAccessible(true); - return field; - } catch (SecurityException | NoSuchFieldException e) { - log.error("{}", e); - return null; - } - }; - - private static final Supplier API_LEVEL_FIELD = () -> { - try { - Field field = ASTParser.class.getDeclaredField("apiLevel"); - field.setAccessible(true); - return field; - } catch (SecurityException | NoSuchFieldException e) { - log.error("{}", e); - return null; - } - }; - + private static final Supplier> COMPILATION_UNIT_RESOLVER_CLASS = () -> { try { return Class.forName("org.eclipse.jdt.core.dom.CompilationUnitResolver"); @@ -272,7 +256,7 @@ class CUResolver { }; static CompilationUnitDeclaration resolve(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, - List classpaths, Map options, int flags, INameEnvironmentWithProgress environment) + List classpaths, Map options, int flags, INameEnvironmentWithProgress environment) throws JavaModelException { try { @@ -316,7 +300,7 @@ class CUResolver { return null; } - static CompilationUnitDeclaration parse(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, Map options, int flags) { + static CompilationUnitDeclaration parse(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, Map options, int flags) { try { return (CompilationUnitDeclaration) PARSE_METHOD.get() .invoke(null, sourceUnit, null, options, flags); @@ -330,7 +314,7 @@ class CUResolver { CompilationUnitDeclaration compilationUnitDeclaration, char[] source, int apiLevel, - Map options, + Map options, boolean needToResolveBindings, WorkingCopyOwner owner, int flags) { @@ -353,47 +337,7 @@ class CUResolver { return null; } - static final Supplier BINDING_RECOVERY_FLAG = () -> { - try { - Class clazz = COMPILATION_UNIT_RESOLVER_CLASS.get(); - if (clazz != null) { - Field field = clazz.getDeclaredField("BINDING_RECOVERY"); - field.setAccessible(true); - return field.getInt(null); - } - } catch (Exception e) { - log.error("{}", e); - } - return 0; - }; - - static final Supplier IGNORE_METHOD_BODIES_FLAG = () -> { - try { - Class clazz = COMPILATION_UNIT_RESOLVER_CLASS.get(); - if (clazz != null) { - Field field = clazz.getDeclaredField("IGNORE_METHOD_BODIES"); - field.setAccessible(true); - return field.getInt(null); - } - } catch (Exception e) { - log.error("{}", e); - } - return 0; - }; - - static final Supplier STATEMENT_RECOVERY_FLAG = () -> { - try { - Class clazz = COMPILATION_UNIT_RESOLVER_CLASS.get(); - if (clazz != null) { - Field field = clazz.getDeclaredField("STATEMENT_RECOVERY"); - field.setAccessible(true); - return field.getInt(null); - } - } catch (Exception e) { - log.error("{}", e); - } - return 0; - }; + static INameEnvironmentWithProgress createLookupEnvironment(Classpath[] classpath) { try { return (INameEnvironmentWithProgress) LOOKUP_ENVIRONMENT_CONSTRUCTOR.get().newInstance(classpath, null, new NullProgressMonitor()); @@ -413,32 +357,5 @@ class CUResolver { } return null; } - - static int getBits(ASTParser parser) { - try { - return BITS_FIELD.get().getInt(parser); - } catch (IllegalAccessException | IllegalArgumentException e) { - log.error("{}", e); - } - return 0; - } - - static WorkingCopyOwner getWorkingCopyOwner(ASTParser parser) { - try { - return (WorkingCopyOwner) WORKING_COPY_OWNER_FIELD.get().get(parser); - } catch (IllegalArgumentException | IllegalAccessException e) { - log.error("{}", e); - } - return null; - } - - static int getApiLevel(ASTParser parser) { - try { - return API_LEVEL_FIELD.get().getInt(parser); - } catch (IllegalArgumentException | IllegalAccessException e) { - log.error("{}", e); - } - return 0; - } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java index e67beb61f..710c08b30 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 Pivotal, Inc. * 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 @@ -222,44 +222,44 @@ public final class CompilationUnitCache implements DocumentContentProvider { } } - public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception { - String[] classpathEntries = getClasspathEntries(project); - String docURI = document.getUri(); - String unitName = docURI.substring(docURI.lastIndexOf("/")); - char[] source = document.get(0, document.getLength()).toCharArray(); - return parse(source, docURI, unitName, classpathEntries); - } - - public CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception { - String[] classpathEntries = getClasspathEntries(project); - String unitName = uri.substring(uri.lastIndexOf("/")); - return parse(source, uri, unitName, classpathEntries); - } - - public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception { - ASTParser parser = ASTParser.newParser(AST.JLS11); - Map options = JavaCore.getOptions(); - JavaCore.setComplianceOptions(JavaCore.VERSION_11, options); - parser.setCompilerOptions(options); - parser.setKind(ASTParser.K_COMPILATION_UNIT); - parser.setStatementsRecovery(true); - parser.setBindingsRecovery(true); - parser.setResolveBindings(true); - - String[] sourceEntries = new String[] {}; - parser.setEnvironment(classpathEntries, sourceEntries, null, false); - - parser.setUnitName(unitName); - parser.setSource(source); - - CompilationUnit cu = (CompilationUnit) parser.createAST(null); - - return cu; - } +// public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception { +// String[] classpathEntries = getClasspathEntries(project); +// String docURI = document.getUri(); +// String unitName = docURI.substring(docURI.lastIndexOf("/")); +// char[] source = document.get(0, document.getLength()).toCharArray(); +// return parse(source, docURI, unitName, classpathEntries); +// } +// +// public CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception { +// String[] classpathEntries = getClasspathEntries(project); +// String unitName = uri.substring(uri.lastIndexOf("/")); +// return parse(source, uri, unitName, classpathEntries); +// } +// +// public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception { +// ASTParser parser = ASTParser.newParser(AST.JLS11); +// Map options = JavaCore.getOptions(); +// JavaCore.setComplianceOptions(JavaCore.VERSION_11, options); +// parser.setCompilerOptions(options); +// parser.setKind(ASTParser.K_COMPILATION_UNIT); +// parser.setStatementsRecovery(true); +// parser.setBindingsRecovery(true); +// parser.setResolveBindings(true); +// +// String[] sourceEntries = new String[] {}; +// parser.setEnvironment(classpathEntries, sourceEntries, null, false); +// +// parser.setUnitName(unitName); +// parser.setSource(source); +// +// CompilationUnit cu = (CompilationUnit) parser.createAST(null); +// +// return cu; +// } - public static CompilationUnit parse2(char[] source, String docURI, String unitName, String[] classpathEntries, INameEnvironmentWithProgress environment) throws Exception { - List classpaths = createClasspath(classpathEntries); - return parse2(source, docURI, unitName, classpaths, environment); + public static CompilationUnit parse2(char[] source, String docURI, String unitName, IJavaProject project) throws Exception { + List classpaths = createClasspath(getClasspathEntries(project)); + return parse2(source, docURI, unitName, classpaths, null); } private static CompilationUnit parse2(char[] source, String docURI, String unitName, List classpaths, INameEnvironmentWithProgress environment) throws Exception { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/AstParserTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/AstParserTest.java new file mode 100644 index 000000000..5431b57ad --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/AstParserTest.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.utils.test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.net.URL; + +import org.apache.commons.io.IOUtils; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.junit.Before; +import org.junit.Test; +import org.springframework.ide.vscode.boot.java.links.SourceLinks; +import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; +import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; + + +public class AstParserTest { + + private ProjectsHarness projects = ProjectsHarness.INSTANCE; + + private MavenJavaProject jp; + + @Before + public void setup() throws Exception { + jp = projects.mavenProject("empty-boot-15-web-app"); + assertTrue(jp.getIndex().findType("org.springframework.boot.SpringApplication").exists()); + } + + @Test + public void test1() throws Exception { + URL sourceUrl = SourceLinks.source(jp, "org.springframework.boot.SpringApplication").get(); + + URI uri = sourceUrl.toURI(); + + String unitName = "SpringApplication"; + + char[] content = IOUtils.toString(uri).toCharArray(); + + CompilationUnit cu = CompilationUnitCache.parse2(content, uri.toString(), unitName, jp); + + assertNotNull(cu); + + cu.accept(new ASTVisitor() { + + @Override + public boolean visit(TypeDeclaration node) { + ITypeBinding binding = node.resolveBinding(); + assertNotNull(binding); + return super.visit(node); + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + IAnnotationBinding annotationBinding = node.resolveAnnotationBinding(); + assertNotNull(annotationBinding); + ITypeBinding binding = node.resolveTypeBinding(); + assertNotNull(binding); + return super.visit(node); + } + + @Override + public boolean visit(NormalAnnotation node) { + IAnnotationBinding annotationBinding = node.resolveAnnotationBinding(); + assertNotNull(annotationBinding); + ITypeBinding binding = node.resolveTypeBinding(); + assertNotNull(binding); + return super.visit(node); + } + + @Override + public boolean visit(MarkerAnnotation node) { + IAnnotationBinding annotationBinding = node.resolveAnnotationBinding(); + assertNotNull(annotationBinding); + ITypeBinding binding = node.resolveTypeBinding(); + assertNotNull(binding); + return super.visit(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + IMethodBinding binding = node.resolveBinding(); + assertNotNull(binding); + if (node.getReturnType2() != null) { + ITypeBinding returnTypeBinding = node.getReturnType2().resolveBinding(); + assertNotNull(returnTypeBinding); + } + return super.visit(node); + } + + @Override + public boolean visit(FieldDeclaration node) { + ITypeBinding binding = node.getType().resolveBinding(); + assertNotNull(binding); + return super.visit(node); + } + + }); + + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/SomeTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/SomeTest.java deleted file mode 100644 index 9e4e80695..000000000 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/SomeTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.springframework.ide.vscode.boot.test; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.net.URI; -import java.net.URL; -import java.util.stream.Stream; - -import org.apache.commons.io.IOUtils; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.junit.Before; -import org.junit.Test; -import org.springframework.ide.vscode.boot.java.links.SourceLinks; -import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; -import org.springframework.ide.vscode.commons.java.IClasspath; -import org.springframework.ide.vscode.commons.java.IClasspathUtil; -import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; -import org.springframework.ide.vscode.project.harness.ProjectsHarness; - - -public class SomeTest { - - private ProjectsHarness projects = ProjectsHarness.INSTANCE; - - private MavenJavaProject jp; - - @Before - public void setup() throws Exception { - jp = projects.mavenProject("empty-boot-15-web-app"); - assertTrue(jp.getIndex().findType("org.springframework.boot.SpringApplication").exists()); - } - - @Test - public void test1() throws Exception { - URL sourceUrl = SourceLinks.source(jp, "org.springframework.boot.SpringApplication").get(); - - URI uri = sourceUrl.toURI(); - - String unitName = "SpringApplication"; - - char[] content = IOUtils.toString(uri).toCharArray(); - - CompilationUnit cu = CompilationUnitCache.parse2(content, uri.toString(), unitName, getClasspathEntries(jp), null); - - System.out.println(cu); - } - -// @Test -// public void test2() throws Exception { -// URL sourceUrl = SourceLinks.source(jp, "org.springframework.boot.SpringApplication").get(); -// -// URI uri = sourceUrl.toURI(); -// -// String unitName = "SpringApplication"; -// -// char[] content = IOUtils.toString(uri).toCharArray(); -// -// CompilationUnit cu = CompilationUnitCache.parse(content, uri.toString(), unitName, getClasspathEntries(jp)); -// -// System.out.println(cu); -// } - - private static String[] getClasspathEntries(IJavaProject project) throws Exception { - if (project == null) { - return new String[0]; - } else { - IClasspath classpath = project.getClasspath(); - Stream classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream(); - return classpathEntries - .filter(file -> file.exists()) - .map(file -> file.getAbsolutePath()).toArray(String[]::new); - } - } - - -}