You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@netbeans.apache.org by GitBox <gi...@apache.org> on 2020/10/25 15:10:30 UTC

[GitHub] [netbeans] Akshay-Gupta-Oracle opened a new pull request #2488: [NETBEANS-3990] Sealed hints

Akshay-Gupta-Oracle opened a new pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488


   Adding hints for putting sealed and permits clause on classes.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] ebarboni commented on pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
ebarboni commented on pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#issuecomment-884160317


   comment still need to be adressed postponed to 12.6 for now


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] geertjanw commented on pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
geertjanw commented on pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#issuecomment-821062451


   Changing milestone to 12.5.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] arvindaprameya commented on pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
arvindaprameya commented on pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#issuecomment-755141415


   Approved


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] neilcsmith-net commented on pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
neilcsmith-net commented on pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#issuecomment-1014634577


   @Akshay-Gupta-Oracle unresolved conversations and merge conflicts, so removing from all milestones and marking stale. Please address or close as appropriate.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] lahodaj commented on a change in pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
lahodaj commented on a change in pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#discussion_r555677949



##########
File path: java/java.hints/src/org/netbeans/modules/java/hints/jdk/AddSealedForClass.java
##########
@@ -0,0 +1,217 @@
+/*
+ * 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.java.hints.jdk;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.lang.instrument.IllegalClassFormatException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.CompilerOptionsQuery;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.modules.java.editor.overridden.ComputeOverriders;
+import org.netbeans.modules.java.editor.overridden.ElementDescription;
+import org.netbeans.modules.java.hints.TreeShims;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.TriggerTreeKind;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle.Messages;
+
+@Hint(displayName = "#DN_AddSealedForClass", description = "#DESC_AddSealedForClass", category = "general", minSourceVersion = "15")

Review comment:
       Make a suggestion, instead of a hint, and possibly not enabled by default? Not sure, see the main comment.

##########
File path: java/java.hints/src/org/netbeans/modules/java/hints/jdk/AddSealedForClass.java
##########
@@ -0,0 +1,217 @@
+/*
+ * 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.java.hints.jdk;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.lang.instrument.IllegalClassFormatException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.CompilerOptionsQuery;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.modules.java.editor.overridden.ComputeOverriders;
+import org.netbeans.modules.java.editor.overridden.ElementDescription;
+import org.netbeans.modules.java.hints.TreeShims;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.TriggerTreeKind;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle.Messages;
+
+@Hint(displayName = "#DN_AddSealedForClass", description = "#DESC_AddSealedForClass", category = "general", minSourceVersion = "15")
+@Messages({
+    "DN_AddSealedForClass=Can Be Sealed Type",
+    "DESC_AddSealedForClass=This class can be set to sealed type with permiting only current sub classes."
+})
+public class AddSealedForClass {
+
+    @TriggerTreeKind({Tree.Kind.CLASS, Tree.Kind.INTERFACE})
+    @Messages("ERR_AddSealedForClass=Can use sealed")
+    public static ErrorDescription computeWarning(HintContext context) {
+        TreePath tp = context.getPath();
+        ClassTree cls = (ClassTree) tp.getLeaf();
+        if (!CompilerOptionsQuery.getOptions(context.getInfo().getFileObject()).getArguments().contains("--enable-preview"))
+            return null;
+        CompilationInfo info = context.getInfo();
+        TypeElement typeElement = (TypeElement) info.getTrees().getElement(tp);
+
+        if (typeElement == null || typeElement.getModifiers().contains(Modifier.FINAL) || typeElement.getModifiers().contains(TreeShims.getSealed())) {
+            return null;
+        }
+        
+        AtomicBoolean cancel = new AtomicBoolean();
+        cancel.set(false);
+        Map<ElementHandle<? extends Element>, List<ElementDescription>> subClasses = new ComputeOverriders(cancel).process(info, null, null, false);

Review comment:
       I guess it would be good to see here whether we can minimize the work. Like:
   
   - only compute the info for the class we are interested in
   - stop the computation immediately if we know we can't make the class sealed, like as soon as any subtype is found in a different package (for unnamed module) or a different (named) module
   - caching everything we can
   - making the computation actually cancelable (otherwise it will not only delay hints, but also the code completion, etc.)
   - do all check that can be done before the subtype computation run before it.

##########
File path: java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
##########
@@ -231,7 +236,124 @@ public static Tree getBindingPatternType(Tree node) {
             throw TreeShims.<RuntimeException>throwAny(ex);
         }
     }
+    public static Modifier getSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static Modifier getNonSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("NON_SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static long getFlagExtendedStandardFlags() {
+        Class flagsClass = null;
+        long flagExtendedStandardFlags = Flags.ExtendedStandardFlags;
+        try {
+            flagsClass = Class.forName("com.sun.tools.javac.code.Flags");
+            flagExtendedStandardFlags = flagsClass.getDeclaredField("ExtendedStandardFlags").getLong(null);
+        } catch (ClassNotFoundException | NoSuchFieldException ex) {
+            return flagExtendedStandardFlags;
+        } catch (IllegalArgumentException | IllegalAccessException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+        return flagExtendedStandardFlags;
+    }
+
+    public static long getSealedFlag() {
+        Class flagsClass = null;
+        long sealedFlag = 0;
+        try {
+            flagsClass = Class.forName("com.sun.tools.javac.code.Flags");
+            sealedFlag = flagsClass.getDeclaredField("SEALED").getLong(null);
+        } catch (ClassNotFoundException | NoSuchFieldException ex) {
+            return 0;
+        } catch (IllegalArgumentException | IllegalAccessException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+        return sealedFlag;
+    }
 
+    public static ClassTree getClassTree(TreeMaker make, Names names, ModifiersTree modifiers, CharSequence simpleName, ListBuffer<JCTree.JCTypeParameter> typarams, Tree extendsClause, ListBuffer<JCExpression> impls, ListBuffer<JCExpression> permits, ListBuffer<JCTree> defs) {

Review comment:
       Can be moved to TreeFactory?

##########
File path: java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
##########
@@ -319,6 +347,29 @@ public ClassTree Interface(ModifiersTree modifiers,
              List<? extends Tree> memberDecls) {
         return delegate.Interface(modifiers, simpleName, typeParameters, extendsClauses, memberDecls);
     }
+    /**
+     * Creates a new ClassTree representing interface.
+     * 
+     * @param modifiers the modifiers declaration
+     * @param simpleName        the name of the class without its package, such
+     *                          as "String" for the class "java.lang.String".
+     * @param typeParameters    the list of type parameters, or an empty list.
+     * @param extendsClauses    the list of the interfaces this class
+     *                          extends, or an empty list.
+     * @param permsClauses      the list of the classes this class allows
+     * @param memberDecls       the list of fields defined by this class, or an
+     *                          empty list.
+     * @return 
+     * @see com.sun.source.tree.ClassTree
+     */
+    public ClassTree InterfaceWithPerms(ModifiersTree modifiers, 

Review comment:
       The same comment about  a name as for `ClassWithPerms`.

##########
File path: java/java.hints/src/org/netbeans/modules/java/hints/jdk/AddSealedForClass.java
##########
@@ -0,0 +1,217 @@
+/*
+ * 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.java.hints.jdk;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.lang.instrument.IllegalClassFormatException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.CompilerOptionsQuery;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.modules.java.editor.overridden.ComputeOverriders;
+import org.netbeans.modules.java.editor.overridden.ElementDescription;
+import org.netbeans.modules.java.hints.TreeShims;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.TriggerTreeKind;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle.Messages;
+
+@Hint(displayName = "#DN_AddSealedForClass", description = "#DESC_AddSealedForClass", category = "general", minSourceVersion = "15")
+@Messages({
+    "DN_AddSealedForClass=Can Be Sealed Type",
+    "DESC_AddSealedForClass=This class can be set to sealed type with permiting only current sub classes."
+})
+public class AddSealedForClass {
+
+    @TriggerTreeKind({Tree.Kind.CLASS, Tree.Kind.INTERFACE})
+    @Messages("ERR_AddSealedForClass=Can use sealed")
+    public static ErrorDescription computeWarning(HintContext context) {
+        TreePath tp = context.getPath();
+        ClassTree cls = (ClassTree) tp.getLeaf();
+        if (!CompilerOptionsQuery.getOptions(context.getInfo().getFileObject()).getArguments().contains("--enable-preview"))
+            return null;
+        CompilationInfo info = context.getInfo();
+        TypeElement typeElement = (TypeElement) info.getTrees().getElement(tp);
+
+        if (typeElement == null || typeElement.getModifiers().contains(Modifier.FINAL) || typeElement.getModifiers().contains(TreeShims.getSealed())) {
+            return null;
+        }
+        
+        AtomicBoolean cancel = new AtomicBoolean();
+        cancel.set(false);
+        Map<ElementHandle<? extends Element>, List<ElementDescription>> subClasses = new ComputeOverriders(cancel).process(info, null, null, false);
+        Iterator<ElementHandle<? extends Element>> iterator = subClasses.keySet().iterator();
+        List<ElementDescription> currentSubClasses = new ArrayList<>();
+        while (iterator.hasNext()) {
+            ElementHandle eh = iterator.next();
+            if (eh.getBinaryName().substring(eh.getQualifiedName().lastIndexOf(".") + 1).equals(cls.getSimpleName().toString())) {
+                currentSubClasses = subClasses.get(eh);
+                break;
+            }
+        }
+       
+        Set<ElementDescription> subClassesToRemove = new HashSet<>();
+        for (int i = 0; i < currentSubClasses.size(); i++) {
+            subClassesToRemove.addAll(subClasses.getOrDefault(currentSubClasses.get(i).getHandle(), new ArrayList<>()));
+        }
+        PackageElement currentPackageElement = (PackageElement) info.getElementUtilities().outermostTypeElement(typeElement).getEnclosingElement();
+        boolean isModule=false;
+        Element parentElement=currentPackageElement;
+        while(parentElement!=null){

Review comment:
       See `Elements.getModuleOf` and `ModuleElements.isUnnamed()`.

##########
File path: java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
##########
@@ -299,6 +299,34 @@ public ClassTree Class(ModifiersTree modifiers,
               List<? extends Tree> memberDecls) {
         return delegate.Class(modifiers, simpleName, typeParameters, extendsClause, implementsClauses, memberDecls);
     }
+    
+    /** 
+     * Creates a new ClassTree.With additional permits clause
+     *
+     * @param modifiers the modifiers declaration
+     * @param simpleName        the name of the class without its package, such
+     *                          as "String" for the class "java.lang.String".
+     * @param typeParameters    the list of type parameters, or an empty list.
+     * @param extendsClause     the name of the class this class extends, or null.
+     * @param implementsClauses the list of the interfaces this class
+     *                          implements, or an empty list.
+     * @param permsClauses      the list of the classes this class allows
+     *                          as sub class, or an empty list.
+     * @param memberDecls       the list of fields defined by this class, or an
+     *                          empty list.
+     * @return 
+     * @see com.sun.source.tree.ClassTree
+     */
+    public ClassTree ClassWithPerms(ModifiersTree modifiers, 

Review comment:
       Not sure if we need a different name here (`ClassWithPerms`) - shouldn't `Class` work? The it has a different number of parameters compared to the existing overloads, right?

##########
File path: java/java.lexer/src/org/netbeans/api/java/lexer/JavaTokenId.java
##########
@@ -86,6 +86,7 @@
     /**@since 1.35*/
     OPENS("opens", "keyword"),
     PACKAGE("package", "keyword"),
+    PERMITS("permits", "keyword"),

Review comment:
       Not sure what is the reason for this, but `permits` is not a keyword.

##########
File path: java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
##########
@@ -176,7 +181,7 @@ public static Name getBinding(Tree node) {
         return perms;
     }
 
-    public static List<? extends Tree> getPermits(JCClassDecl newT) {
+    public static List<? extends JCTree> getPermits(JCClassDecl newT) {

Review comment:
       TreeShims are intended to serve as a mirror for things that should be (or are) an API, but can't be (yet) or are not (yet) available. If java.source.base needs access to internal javac structures, it should do it outside of TreeShims, which are copied to other modules as well. The API in TreeShims should only refer to API types.

##########
File path: java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
##########
@@ -231,7 +236,124 @@ public static Tree getBindingPatternType(Tree node) {
             throw TreeShims.<RuntimeException>throwAny(ex);
         }
     }
+    public static Modifier getSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static Modifier getNonSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("NON_SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static long getFlagExtendedStandardFlags() {
+        Class flagsClass = null;
+        long flagExtendedStandardFlags = Flags.ExtendedStandardFlags;
+        try {
+            flagsClass = Class.forName("com.sun.tools.javac.code.Flags");
+            flagExtendedStandardFlags = flagsClass.getDeclaredField("ExtendedStandardFlags").getLong(null);
+        } catch (ClassNotFoundException | NoSuchFieldException ex) {
+            return flagExtendedStandardFlags;
+        } catch (IllegalArgumentException | IllegalAccessException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+        return flagExtendedStandardFlags;
+    }
+
+    public static long getSealedFlag() {
+        Class flagsClass = null;
+        long sealedFlag = 0;
+        try {
+            flagsClass = Class.forName("com.sun.tools.javac.code.Flags");
+            sealedFlag = flagsClass.getDeclaredField("SEALED").getLong(null);
+        } catch (ClassNotFoundException | NoSuchFieldException ex) {
+            return 0;
+        } catch (IllegalArgumentException | IllegalAccessException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+        return sealedFlag;
+    }
 
+    public static ClassTree getClassTree(TreeMaker make, Names names, ModifiersTree modifiers, CharSequence simpleName, ListBuffer<JCTree.JCTypeParameter> typarams, Tree extendsClause, ListBuffer<JCExpression> impls, ListBuffer<JCExpression> permits, ListBuffer<JCTree> defs) {
+        try {
+            Class treeMaker = Class.forName("com.sun.tools.javac.tree.TreeMaker");
+            Method allMethods[] = treeMaker.getDeclaredMethods();
+            Method classDefs = null;
+            for (int i = 0; i < allMethods.length; i++) {
+                Method oneMethod = allMethods[i];
+                if (oneMethod.getName().equals("ClassDef") && oneMethod.getParameterCount() == 7) {
+                    classDefs = oneMethod;
+                    break;
+                }
+            }
+            if (classDefs == null) {
+                return null;
+            }
+            ClassTree name = (ClassTree) classDefs.invoke(make, (JCTree.JCModifiers) modifiers,
+                    names.fromString(simpleName.toString()),
+                    typarams.toList(),
+                    (JCTree.JCExpression) extendsClause,
+                    impls.toList(),
+                    permits.toList(),
+                    defs.toList());
+            return name;
+        } catch (ClassNotFoundException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
+    public static ClassTree getClassTree(TreeMaker make, Names names, long modifiers,

Review comment:
       Can be moved to TreeFactory?

##########
File path: java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
##########
@@ -231,7 +236,124 @@ public static Tree getBindingPatternType(Tree node) {
             throw TreeShims.<RuntimeException>throwAny(ex);
         }
     }
+    public static Modifier getSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static Modifier getNonSealed() {
+        try {
+            Class modifierEnum = Class.forName("javax.lang.model.element.Modifier");
+            Modifier[] enumConstants = (Modifier[]) modifierEnum.getEnumConstants();
+            for (int i = 0; i < enumConstants.length; i++) {
+                if (enumConstants[i].name().equals("NON_SEALED")) {
+                    return enumConstants[i];
+                }
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+        return null;
+    }
+
+    public static long getFlagExtendedStandardFlags() {

Review comment:
       The flag bitmask is not a public API. This can be moved to VeryPretty/CausalDiff, or elsewhere where it is needed, or internally to java.source.base.

##########
File path: java/java.hints/src/org/netbeans/modules/java/hints/jdk/AddSealedForClass.java
##########
@@ -0,0 +1,217 @@
+/*
+ * 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.java.hints.jdk;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.lang.instrument.IllegalClassFormatException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.queries.CompilerOptionsQuery;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.modules.java.editor.overridden.ComputeOverriders;
+import org.netbeans.modules.java.editor.overridden.ElementDescription;
+import org.netbeans.modules.java.hints.TreeShims;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.TriggerTreeKind;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle.Messages;
+
+@Hint(displayName = "#DN_AddSealedForClass", description = "#DESC_AddSealedForClass", category = "general", minSourceVersion = "15")
+@Messages({
+    "DN_AddSealedForClass=Can Be Sealed Type",
+    "DESC_AddSealedForClass=This class can be set to sealed type with permiting only current sub classes."
+})
+public class AddSealedForClass {
+
+    @TriggerTreeKind({Tree.Kind.CLASS, Tree.Kind.INTERFACE})
+    @Messages("ERR_AddSealedForClass=Can use sealed")
+    public static ErrorDescription computeWarning(HintContext context) {
+        TreePath tp = context.getPath();
+        ClassTree cls = (ClassTree) tp.getLeaf();
+        if (!CompilerOptionsQuery.getOptions(context.getInfo().getFileObject()).getArguments().contains("--enable-preview"))
+            return null;
+        CompilationInfo info = context.getInfo();
+        TypeElement typeElement = (TypeElement) info.getTrees().getElement(tp);
+
+        if (typeElement == null || typeElement.getModifiers().contains(Modifier.FINAL) || typeElement.getModifiers().contains(TreeShims.getSealed())) {
+            return null;
+        }
+        
+        AtomicBoolean cancel = new AtomicBoolean();
+        cancel.set(false);
+        Map<ElementHandle<? extends Element>, List<ElementDescription>> subClasses = new ComputeOverriders(cancel).process(info, null, null, false);
+        Iterator<ElementHandle<? extends Element>> iterator = subClasses.keySet().iterator();
+        List<ElementDescription> currentSubClasses = new ArrayList<>();
+        while (iterator.hasNext()) {
+            ElementHandle eh = iterator.next();
+            if (eh.getBinaryName().substring(eh.getQualifiedName().lastIndexOf(".") + 1).equals(cls.getSimpleName().toString())) {
+                currentSubClasses = subClasses.get(eh);
+                break;
+            }
+        }
+       
+        Set<ElementDescription> subClassesToRemove = new HashSet<>();
+        for (int i = 0; i < currentSubClasses.size(); i++) {
+            subClassesToRemove.addAll(subClasses.getOrDefault(currentSubClasses.get(i).getHandle(), new ArrayList<>()));
+        }
+        PackageElement currentPackageElement = (PackageElement) info.getElementUtilities().outermostTypeElement(typeElement).getEnclosingElement();
+        boolean isModule=false;
+        Element parentElement=currentPackageElement;
+        while(parentElement!=null){
+            if(parentElement.getKind().equals(ElementKind.MODULE) && !parentElement.getSimpleName().toString().equals("")){
+                isModule=true;
+                break;
+            }
+            parentElement=parentElement.getEnclosingElement();
+        }
+        if(!isModule){
+            for (int i = 0; i < currentSubClasses.size(); i++) {
+                String currentSubClass = currentSubClasses.get(i).getHandle().getQualifiedName();
+                if(!currentSubClass.substring(0,currentSubClass.lastIndexOf(".")).equals(currentPackageElement.getQualifiedName().toString())){
+                    return null;
+                }
+            }
+        }
+        for (int i = 0; i < currentSubClasses.size(); i++) {
+            for (ElementDescription elementDescription : subClassesToRemove) {
+                if (currentSubClasses.get(i).getHandle().getQualifiedName().equals(elementDescription.getHandle().getQualifiedName())) {
+                    currentSubClasses.remove(i);
+                    i--;
+                    break;
+                }
+            }
+        }
+//        for (int i = 0; i < currentSubClasses.size(); i++) {

Review comment:
       Nit - possibly delete?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


[GitHub] [netbeans] mbien commented on pull request #2488: [NETBEANS-3990] Sealed hints

Posted by GitBox <gi...@apache.org>.
mbien commented on pull request #2488:
URL: https://github.com/apache/netbeans/pull/2488#issuecomment-1005142127


   needs a rebase, but the diff doesn't look too bad


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@netbeans.apache.org
For additional commands, e-mail: notifications-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists