This is an automated email from the ASF dual-hosted git repository.

dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 6b8e152d36 Do not mark test methods as unused.
     new 35a3f1695c Merge pull request #6277 from 
dbalek/dbalek/no-unused-test-methods
6b8e152d36 is described below

commit 6b8e152d36a9416928a5efcac23ece6ac2ec1976
Author: Dusan Balek <[email protected]>
AuthorDate: Mon Jul 31 15:26:40 2023 +0200

    Do not mark test methods as unused.
---
 java/java.editor.base/nbproject/project.xml        |  8 +++
 .../java/editor/base/semantic/UnusedDetector.java  | 43 +++++++++++++---
 .../netbeans/modules/java/hints/bugs/Unused.java   |  1 -
 java/junit.ui/nbproject/project.xml                |  8 +++
 .../junit/ui/actions/TestClassInfoTask.java        | 29 ++++++++++-
 java/spi.java.hints/apichanges.xml                 | 17 +++++++
 java/spi.java.hints/nbproject/project.properties   |  2 +-
 java/spi.java.hints/nbproject/project.xml          |  3 +-
 .../spi/java/hints/unused/UsedDetector.java        | 57 ++++++++++++++++++++++
 9 files changed, 154 insertions(+), 14 deletions(-)

diff --git a/java/java.editor.base/nbproject/project.xml 
b/java/java.editor.base/nbproject/project.xml
index d1ffc48275..8f79fbf993 100644
--- a/java/java.editor.base/nbproject/project.xml
+++ b/java/java.editor.base/nbproject/project.xml
@@ -122,6 +122,14 @@
                         <specification-version>1.87</specification-version>
                     </run-dependency>
                 </dependency>
+                <dependency>
+                    
<code-name-base>org.netbeans.spi.java.hints</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.56</specification-version>
+                    </run-dependency>
+                </dependency>
                 <dependency>
                     <code-name-base>org.openide.filesystems</code-name-base>
                     <build-prerequisite/>
diff --git 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/UnusedDetector.java
 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/UnusedDetector.java
index 161855c43d..e129842e45 100644
--- 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/UnusedDetector.java
+++ 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/UnusedDetector.java
@@ -48,6 +48,8 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiFunction;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -69,8 +71,10 @@ import org.netbeans.api.project.Project;
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.api.project.SourceGroup;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.netbeans.spi.java.hints.unused.UsedDetector;
 import org.openide.filesystems.FileObject;
 import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
 
 /**
  *
@@ -114,6 +118,18 @@ public class UnusedDetector {
 
         UnusedVisitor uv = new UnusedVisitor(info);
         uv.scan(info.getCompilationUnit(), null);
+        AtomicReference<List<UsedDetector>> usedDetectors = new 
AtomicReference<>();
+        BiFunction<Element, TreePath, Boolean> markedAsUsed = (el, path) -> {
+            if (usedDetectors.get() == null) {
+                usedDetectors.set(collectUsedDetectors(info));
+            }
+            for (UsedDetector detector : usedDetectors.get()) {
+                if (detector.isUsed(el, path)) {
+                    return true;
+                }
+            }
+            return false;
+        };
         List<UnusedDescription> result = new ArrayList<>();
         for (Entry<Element, TreePath> e : uv.element2Declaration.entrySet()) {
             Element el = e.getKey();
@@ -124,11 +140,11 @@ public class UnusedDetector {
             if (isLocalVariableClosure(el)) {
                 boolean isWritten = uses.contains(UseTypes.WRITTEN);
                 boolean isRead = uses.contains(UseTypes.READ);
-                if (!isWritten && !isRead) {
+                if (!isWritten && !isRead && !markedAsUsed.apply(el, 
declaration)) {
                     result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_WRITTEN_READ));
-                } else if (!isWritten) {
+                } else if (!isWritten && !markedAsUsed.apply(el, declaration)) 
{
                     result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_WRITTEN));
-                } else if (!isRead) {
+                } else if (!isRead && !markedAsUsed.apply(el, declaration)) {
                     result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_READ));
                 }
             } else if (el.getKind().isField() && (isPrivate || isPkgPrivate)) {
@@ -136,13 +152,13 @@ public class UnusedDetector {
                     boolean isWritten = uses.contains(UseTypes.WRITTEN);
                     boolean isRead = uses.contains(UseTypes.READ);
                     if (!isWritten && !isRead) {
-                        if (isPrivate || isUnusedInPkg(info, el, cancel)) {
+                        if ((isPrivate || isUnusedInPkg(info, el, cancel)) && 
!markedAsUsed.apply(el, declaration)) {
                             result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_WRITTEN_READ));
                         }
-                    } else if (!isWritten) {
+                    } else if (!isWritten && !markedAsUsed.apply(el, 
declaration)) {
                         result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_WRITTEN));
                     } else if (!isRead) {
-                        if (isPrivate || isUnusedInPkg(info, el, cancel)) {
+                        if ((isPrivate || isUnusedInPkg(info, el, cancel)) && 
!markedAsUsed.apply(el, declaration)) {
                             result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_READ));
                         }
                     }
@@ -152,13 +168,13 @@ public class UnusedDetector {
                 if (!isSerializationMethod(info, method) && 
!uses.contains(UseTypes.USED)
                         && !info.getElementUtilities().overridesMethod(method) 
&& !lookedUpElement(el, uv.type2LookedUpMethods, uv.allStringLiterals)
                         && !SourceUtils.isMainMethod(method)) {
-                    if (isPrivate || isUnusedInPkg(info, el, cancel)) {
+                    if ((isPrivate || isUnusedInPkg(info, el, cancel)) && 
!markedAsUsed.apply(el, declaration)) {
                         result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_USED));
                     }
                 }
             } else if ((el.getKind().isClass() || el.getKind().isInterface()) 
&& (isPrivate || isPkgPrivate)) {
                 if (!uses.contains(UseTypes.USED)) {
-                    if (isPrivate || isUnusedInPkg(info, el, cancel)) {
+                    if ((isPrivate || isUnusedInPkg(info, el, cancel)) && 
!markedAsUsed.apply(el, declaration)) {
                         result.add(new UnusedDescription(el, declaration, 
isPkgPrivate, UnusedReason.NOT_USED));
                     }
                 }
@@ -401,6 +417,17 @@ public class UnusedDetector {
         return false;
     }
 
+    private static List<UsedDetector> collectUsedDetectors(CompilationInfo 
info) {
+        List<UsedDetector> detectors = new ArrayList<>();
+        for (UsedDetector.Factory factory : 
Lookup.getDefault().lookupAll(UsedDetector.Factory.class)) {
+            UsedDetector detector = factory.create(info);
+            if (detector != null) {
+                detectors.add(detector);
+            }
+        }
+        return detectors;
+    }
+
     private enum UseTypes {
         READ, WRITTEN, USED;
     }
diff --git 
a/java/java.hints/src/org/netbeans/modules/java/hints/bugs/Unused.java 
b/java/java.hints/src/org/netbeans/modules/java/hints/bugs/Unused.java
index 34744e9678..e681ed7b97 100644
--- a/java/java.hints/src/org/netbeans/modules/java/hints/bugs/Unused.java
+++ b/java/java.hints/src/org/netbeans/modules/java/hints/bugs/Unused.java
@@ -21,7 +21,6 @@ package org.netbeans.modules.java.hints.bugs;
 import com.sun.source.tree.Tree.Kind;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 import javax.lang.model.element.ElementKind;
 import org.netbeans.modules.java.editor.base.semantic.UnusedDetector;
 import 
org.netbeans.modules.java.editor.base.semantic.UnusedDetector.UnusedDescription;
diff --git a/java/junit.ui/nbproject/project.xml 
b/java/junit.ui/nbproject/project.xml
index aa582301ea..c3fc6fe537 100644
--- a/java/junit.ui/nbproject/project.xml
+++ b/java/junit.ui/nbproject/project.xml
@@ -207,6 +207,14 @@
                         <specification-version>1.78</specification-version>
                     </run-dependency>
                 </dependency>
+                <dependency>
+                    
<code-name-base>org.netbeans.spi.java.hints</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.56</specification-version>
+                    </run-dependency>
+                </dependency>
                 <dependency>
                     <code-name-base>org.openide.awt</code-name-base>
                     <build-prerequisite/>
diff --git 
a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
 
b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
index cf6ca19c42..051645ab73 100644
--- 
a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
+++ 
b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java
@@ -25,7 +25,6 @@ import com.sun.source.tree.Tree.Kind;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.Trees;
-import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -39,6 +38,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.util.Elements;
 import javax.swing.text.BadLocationException;
@@ -56,8 +56,8 @@ import 
org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController.TestMetho
 import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods;
 import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods.Factory;
 import org.netbeans.modules.parsing.spi.Parser;
+import org.netbeans.spi.java.hints.unused.UsedDetector;
 import org.netbeans.spi.project.SingleMethod;
-import org.openide.ErrorManager;
 import org.openide.filesystems.FileObject;
 import org.openide.util.Exceptions;
 import org.openide.util.lookup.ServiceProvider;
@@ -255,6 +255,31 @@ public final class TestClassInfoTask implements 
Task<CompilationController> {
         }
     }
 
+    @ServiceProvider(service=UsedDetector.Factory.class)
+    public static final class UsedDetectorImpl implements UsedDetector.Factory 
{
+
+        @Override
+        public UsedDetector create(CompilationInfo info) {
+            if (isTestSource(info.getFileObject())) {
+                List<TestMethod> testMethods = 
TestClassInfoTask.doComputeTestMethods(info, new AtomicBoolean(), -1);
+                SourcePositions sp = info.getTrees().getSourcePositions();
+                return (el, path) -> {
+                    if (el.getKind() == ElementKind.METHOD) {
+                        for (TestMethod tm : testMethods) {
+                            if 
(tm.method().getMethodName().contentEquals(el.getSimpleName())
+                                    && tm.start().getOffset() == 
sp.getStartPosition(path.getCompilationUnit(), path.getLeaf())
+                                    && tm.end().getOffset() == 
sp.getEndPosition(path.getCompilationUnit(), path.getLeaf())) {
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                };
+            }
+            return null;
+        }
+    }
+
     @MimeRegistration(mimeType="text/x-java", 
service=org.netbeans.modules.gsf.testrunner.ui.spi.ComputeTestMethods.class)
     public static final class GenericComputeTestMethodsImpl implements 
org.netbeans.modules.gsf.testrunner.ui.spi.ComputeTestMethods {
 
diff --git a/java/spi.java.hints/apichanges.xml 
b/java/spi.java.hints/apichanges.xml
index d75974e8a5..54c6cb52e2 100644
--- a/java/spi.java.hints/apichanges.xml
+++ b/java/spi.java.hints/apichanges.xml
@@ -25,6 +25,23 @@
         <apidef name="JavaHintsSPI">Java Hints SPI</apidef>
     </apidefs>
     <changes>
+        <change id="UsedDetector">
+            <api name="JavaHintsSPI"/>
+            <summary>Added UsedDetector SPI to mark an arbitrary elements as 
used</summary>
+            <version major="1" minor="56"/>
+            <date day="2" month="8" year="2023"/>
+            <compatibility addition="yes"/>
+            <description>
+                <p>
+                    The SPI to mark an arbitrary element as used was added.
+                    Allows to suppress the standard NetBeans unused element 
detection
+                    and to prevent the "unused" hint being displayed on given 
elements.
+                    Can be used by various framework libraries that sometimes 
honor
+                    annotations (i.e. injections or bindings) even on private 
methods.
+                </p>
+            </description>
+            <class package="org.netbeans.spi.java.hints.unused" 
name="UsedDetector" link="no" />
+        </change>
         <change id="openRefactoringUI">
             <api name="JavaHintsSPI"/>
             <summary>Added utility methods and SPI to open UI for 
hints</summary>
diff --git a/java/spi.java.hints/nbproject/project.properties 
b/java/spi.java.hints/nbproject/project.properties
index e8819b174c..e2e9fef7d2 100644
--- a/java/spi.java.hints/nbproject/project.properties
+++ b/java/spi.java.hints/nbproject/project.properties
@@ -17,7 +17,7 @@
 is.autoload=true
 javac.source=1.8
 javac.compilerargs=-Xlint -Xlint:-serial
-spec.version.base=1.55.0
+spec.version.base=1.56.0
 requires.nb.javac=true
 javadoc.arch=${basedir}/arch.xml
 javadoc.apichanges=${basedir}/apichanges.xml
diff --git a/java/spi.java.hints/nbproject/project.xml 
b/java/spi.java.hints/nbproject/project.xml
index d5a4f3fb8a..ac8c0a9c80 100644
--- a/java/spi.java.hints/nbproject/project.xml
+++ b/java/spi.java.hints/nbproject/project.xml
@@ -504,9 +504,8 @@
             </test-dependencies>
             <public-packages>
                 <package>org.netbeans.spi.java.hints</package>
-                <package>org.netbeans.spi.java.hints.annotations</package>
-                <package>org.netbeans.spi.java.hints.matching</package>
                 <package>org.netbeans.spi.java.hints.support</package>
+                <package>org.netbeans.spi.java.hints.unused</package>
             </public-packages>
         </data>
     </configuration>
diff --git 
a/java/spi.java.hints/src/org/netbeans/spi/java/hints/unused/UsedDetector.java 
b/java/spi.java.hints/src/org/netbeans/spi/java/hints/unused/UsedDetector.java
new file mode 100644
index 0000000000..f0d74712b6
--- /dev/null
+++ 
b/java/spi.java.hints/src/org/netbeans/spi/java/hints/unused/UsedDetector.java
@@ -0,0 +1,57 @@
+/*
+ * 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.spi.java.hints.unused;
+
+import com.sun.source.util.TreePath;
+import javax.lang.model.element.Element;
+import org.netbeans.api.java.source.CompilationInfo;
+
+/**
+ * SPI to mark an arbitrary {@link Element} as used. Allows to suppress the 
standard NetBeans
+ * unused element detection and to prevent the "unused" hint being displayed 
on given elements.
+ * Can be used by various framework libraries that sometimes honor annotations
+ * (i.e. injections or bindings) even on private methods.
+ *
+ * @since 1.56
+ */
+public interface UsedDetector {
+
+    /**
+     * Checks whether given element should be marked as "used".
+     * @param el element to check
+     * @param path path to the element to check
+     * @return true if the given element should be marked as "used"
+     * @since 1.56
+     */
+    boolean isUsed(Element el, TreePath path);
+
+    /**
+     * Factory to create {@link UsedDetector} instances.
+     * @since 1.56
+     */
+    public interface Factory {
+        /**
+         * Creates {@link UsedDetector} instance for the given {@link 
CompilationInfo}.
+         * @param info
+         * @return {@link UsedDetector} instance or null.
+         * @since 1.56
+         */
+        UsedDetector create(CompilationInfo info);
+    }
+}


---------------------------------------------------------------------
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

Reply via email to