diff --git a/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java b/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java index e97b5998d..658600804 100644 --- a/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java +++ b/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java @@ -75,6 +75,8 @@ public abstract class AbstractProblemSeverityPreferencesPage extends FieldEditor private static final String[][] SEVERITY_NAMES_AND_VALUES = { {"Error", ProblemSeverity.ERROR.toString()}, {"Warning", ProblemSeverity.WARNING.toString()}, + {"Info", ProblemSeverity.INFO.toString()}, + {"Hint", ProblemSeverity.HINT.toString()}, {"Ignore", ProblemSeverity.IGNORE.toString()} }; diff --git a/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/reconcile/ProblemSeverity.java b/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/reconcile/ProblemSeverity.java index f9bf7712b..d5ae2fc4c 100644 --- a/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/reconcile/ProblemSeverity.java +++ b/eclipse-language-servers/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/reconcile/ProblemSeverity.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2016 Pivotal, Inc. + * Copyright (c) 2014, 2022 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 @@ -16,6 +16,8 @@ package org.springframework.ide.eclipse.editor.support.reconcile; public enum ProblemSeverity { IGNORE, + HINT, + INFO, WARNING, ERROR; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java index 420343506..aede53c43 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2021 Pivotal, Inc. + * Copyright (c) 2017, 2022 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 @@ -122,5 +122,42 @@ public abstract class AnnotationHierarchies { return findTransitiveSupers(candidate, new HashSet<>()) .anyMatch(sa -> isKeyAnnotationName.test(sa.getQualifiedName())); } + + public static Collection getDirectSuperAnnotationBindings(IAnnotationBinding annotationBinding) { + synchronized(lock) { + try { + if (annotationBinding.getAnnotationType() != null) { + IAnnotationBinding[] annotations = annotationBinding.getAnnotationType().getAnnotations(); + if (annotations != null && annotations.length != 0) { + ImmutableList.Builder superAnnotations = ImmutableList.builder(); + for (IAnnotationBinding ab : annotations) { + ITypeBinding sa = ab.getAnnotationType(); + if (sa != null) { + if (!ignoreAnnotation(sa.getQualifiedName())) { + superAnnotations.add(ab); + } + } + } + return superAnnotations.build(); + } + } + } + catch (AbortCompilation e) { + log.debug("compilation aborted ", e); + // ignore this, it is most likely caused by broken source code, a broken classpath, or some optional dependencies not being on the classpath + } + + return ImmutableList.of(); + } + } + + public static Stream findTransitiveSuperAnnotationBindings( + IAnnotationBinding annotationBinding) { + synchronized (lock) { + return Stream.concat(Stream.of(annotationBinding), getDirectSuperAnnotationBindings(annotationBinding) + .stream().flatMap(superBinding -> findTransitiveSuperAnnotationBindings(superBinding))); + } + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredConstructorReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredConstructorReconciler.java index 64dc0850c..6ea5a959d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredConstructorReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AutowiredConstructorReconciler.java @@ -14,11 +14,14 @@ import java.util.List; import java.util.Optional; import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.IMemberValuePairBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.SpringJavaProblemType; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.SpringProjectUtil; import org.springframework.ide.vscode.commons.java.Version; @@ -65,9 +68,9 @@ public class AutowiredConstructorReconciler implements AnnotationReconciler { if (a.getParent() instanceof MethodDeclaration) { MethodDeclaration method = (MethodDeclaration) a.getParent(); IMethodBinding methodBinding = method.resolveBinding(); - if (methodBinding != null) { + if (methodBinding != null && methodBinding.isConstructor()) { ITypeBinding declaringType = methodBinding.getDeclaringClass(); - if (declaringType != null && isOnlyOneConstructor(declaringType)) { + if (declaringType != null && !isBootTestClass(declaringType) && isOnlyOneConstructor(declaringType)) { return Optional.of(declaringType); } } @@ -90,6 +93,31 @@ public class AutowiredConstructorReconciler implements AnnotationReconciler { } return numberOfConstructors == 1; } + + private static boolean isBootTestClass(ITypeBinding typeBinding) { + for (IAnnotationBinding annotation : typeBinding.getAnnotations()) { + boolean found = AnnotationHierarchies.findTransitiveSuperAnnotationBindings(annotation).anyMatch(a -> { + if (a.getAnnotationType() != null) { + if ("org.springframework.test.context.BootstrapWith".equals(a.getAnnotationType().getQualifiedName())) { + for (IMemberValuePairBinding pair : a.getAllMemberValuePairs()) { + if (pair.getValue() instanceof ITypeBinding) { + ITypeBinding type = (ITypeBinding) pair.getValue(); + if ("value".equals(pair.getName()) + && "org.springframework.boot.test.context.SpringBootTestContextBootstrapper".equals(type.getQualifiedName())) { + return true; + } + } + } + } + } + return false; + }); + if (found) { + return true; + } + } + return false; + } }