Browse Source

Remove legacy hints module, rewrite the hints to the newer module

Toni Helenius 5 years ago
parent
commit
da19e433b5

+ 0 - 9
jme3-code-check/nbproject/project.xml

@@ -75,15 +75,6 @@
                         <implementation-version/>
                         <implementation-version/>
                     </run-dependency>
                     </run-dependency>
                 </dependency>
                 </dependency>
-                <dependency>
-                    <code-name-base>org.netbeans.modules.java.hints.legacy.spi</code-name-base>
-                    <build-prerequisite/>
-                    <compile-dependency/>
-                    <run-dependency>
-                        <release-version>1</release-version>
-                        <implementation-version/>
-                    </run-dependency>
-                </dependency>
                 <dependency>
                 <dependency>
                     <code-name-base>org.netbeans.modules.java.source</code-name-base>
                     <code-name-base>org.netbeans.modules.java.source</code-name-base>
                     <build-prerequisite/>
                     <build-prerequisite/>

+ 0 - 16
jme3-code-check/src/com/jme3/gde/codecheck/hints/Bundle.properties

@@ -1,16 +0,0 @@
-UpdateHint.display-name=Updating is not needed in jME3, check your update order if you need to call this.
-UpdateHint.id=Update States / Bound
-UpdateHint.description=Checks for calls to updateGeometricState(), updateLogicalState() and updateModelBound().
-UpdateHint.fix-text=Remove this call
-TempVarsHint.display-name=TempVars might not be released
-TempVarsHint.id=TempVars release check
-TempVarsHint.description=Checks for calls TempVars.get() and search for correspondinng release() call
-TempVarsHint.fix-text=Add a release() call at the end of the method
-ReadOnlyPrimitiveHint.display-name=This primitive is read only and should not be modified!
-ReadOnlyPrimitiveHint.id=ReadOnly Primitives
-ReadOnlyPrimitiveHint.description=Checks for modifications to readonly primitives. (getLocalTranslation().set())
-ReadOnlyPrimitiveHint.fix-text=Remove this call
-InternalMethodHint.display-name=You should not call this method, its for internal use only!
-InternalMethodHint.id=Internal Methods
-InternalMethodHint.description=Checks for calls to internal methods.
-InternalMethodHint.fix-text=Remove this call

+ 58 - 108
jme3-code-check/src/com/jme3/gde/codecheck/hints/InternalMethodHint.java

@@ -1,134 +1,84 @@
 package com.jme3.gde.codecheck.hints;
 package com.jme3.gde.codecheck.hints;
 
 
-import com.jme3.system.Annotations.Internal;
+import com.jme3.system.Annotations;
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.StatementTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePath;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.List;
-import java.util.Set;
-import javax.lang.model.element.Element;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import org.netbeans.api.editor.EditorRegistry;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.modules.java.hints.spi.AbstractHint;
-import org.netbeans.spi.editor.hints.ChangeInfo;
-import org.netbeans.spi.editor.hints.EnhancedFix;
+import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.ErrorDescription;
-import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.Fix;
-import org.openide.awt.StatusDisplayer;
+import org.netbeans.spi.editor.hints.Severity;
+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.util.NbBundle;
 import org.openide.util.NbBundle;
 
 
-public class InternalMethodHint extends AbstractHint {
-
-    //This hint does not enable the IDE to fix the problem:
-    private static final List<Fix> NO_FIXES = Collections.<Fix>emptyList();
-    //This hint applies to method invocations:
-    private static final Set<Tree.Kind> TREE_KINDS =
-            EnumSet.<Tree.Kind>of(Tree.Kind.METHOD_INVOCATION);
-
-    public InternalMethodHint() {
-        super(true, true, AbstractHint.HintSeverity.WARNING);
-    }
-
-    //Specify the kind of code that the hint applies to, in this case,
-    //the hint applies to method invocations:
-    @Override
-    public Set<Kind> getTreeKinds() {
-        return TREE_KINDS;
-    }
-
-    @Override
-    public List<ErrorDescription> run(CompilationInfo info, TreePath treePath) {
-
-        Tree t = treePath.getLeaf();
-
-        Element el = info.getTrees().getElement(treePath);
-
-        if (el.getAnnotation(Internal.class) != null) {
-            //prepare selection for removing
-            JTextComponent editor = EditorRegistry.lastFocusedComponent();
-            Document doc = editor.getDocument();
-            SourcePositions sp = info.getTrees().getSourcePositions();
-            int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
-            int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
-            String bodyText = info.getText().substring(start, end);
-            //prepare fix
-            List<Fix> fixes = new ArrayList<Fix>();
-            fixes.add(new MessagesFix(doc, start, bodyText));
-
-            return Collections.<ErrorDescription>singletonList(
-                    ErrorDescriptionFactory.createErrorDescription(
-                    getSeverity().toEditorSeverity(),
-                    getDisplayName(),
-                    fixes,
-                    info.getFileObject(),
-                    (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), t),
-                    (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), t)));
-
+@Hint(id = "#InternalMethodHint.id", displayName = "#InternalMethodHint.display-name",
+        description = "#InternalMethodHint.description", severity = Severity.WARNING,
+        category = "general")
[email protected]({
+    "InternalMethodHint.display-name=You should not call this method, its for internal use only!",
+    "InternalMethodHint.id=Internal Methods",
+    "InternalMethodHint.description=Checks for calls to internal methods.",
+    "InternalMethodHint.fix-text=Remove this call"
+})
+public class InternalMethodHint {
+
+    @TriggerTreeKind(Tree.Kind.METHOD_INVOCATION)
+    public static ErrorDescription hint(HintContext ctx) {
+        CompilationInfo info = ctx.getInfo();
+        TreePath treePath = ctx.getPath();
+        if (info.getTrees().getElement(treePath).getAnnotation(Annotations.Internal.class) != null) {
+                Fix fix = new InternalMethodHint.FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
+                return ErrorDescriptionFactory.forName(
+                        ctx,
+                        ctx.getPath(),
+                        Bundle.InternalMethodHint_display_name(),
+                    fix);
         }
         }
 
 
         return null;
         return null;
-
     }
     }
 
 
-    //This is called if/when the hint processing is cancelled:
-    @Override
-    public void cancel() {
-    }
-
-    //Message that the user sees in the left sidebar:
-    @Override
-    public String getDisplayName() {
-        return NbBundle.getMessage(InternalMethodHint.class, "InternalMethodHint.display-name");
-    }
-
-    //Name of the hint in the Options window:
-    @Override
-    public String getId() {
-        return NbBundle.getMessage(InternalMethodHint.class, "InternalMethodHint.id");
-    }
-
-    //Description of the hint in the Options window:
-    @Override
-    public String getDescription() {
-        return NbBundle.getMessage(InternalMethodHint.class, "InternalMethodHint.description");
-    }
-
-    class MessagesFix implements EnhancedFix {
-
-        Document doc = null;
-        int start = 0;
-        String bodyText = null;
+    private static final class FixImpl extends JavaFix {
 
 
-        public MessagesFix(Document doc, int start, String bodyText) {
-            this.doc = doc;
-            this.start = start;
-            this.bodyText = bodyText;
-        }
-
-        @Override
-        public CharSequence getSortText() {
-            return "charsequence";
+        public FixImpl(CompilationInfo info, TreePath tp) {
+            super(info, tp);
         }
         }
 
 
         @Override
         @Override
-        public String getText() {
-            return NbBundle.getMessage(InternalMethodHint.class, "InternalMethodHint.fix-text");
+        protected String getText() {
+            return Bundle.InternalMethodHint_fix_text();
         }
         }
 
 
         @Override
         @Override
-        public ChangeInfo implement() throws Exception {
-            //Add 1 character, for the semi-colon:
-            doc.remove(start, bodyText.length() + 1);
-            //Display message to user in status bar:
-            StatusDisplayer.getDefault().setStatusText("Removed: " + bodyText);
-            return null;
+        protected void performRewrite(JavaFix.TransformationContext tc) throws Exception {
+            WorkingCopy wc = tc.getWorkingCopy();
+            TreePath statementPath = tc.getPath();
+            TreePath blockPath = tc.getPath().getParentPath();
+            while (!(blockPath.getLeaf() instanceof BlockTree)) {
+                statementPath = blockPath;
+                blockPath = blockPath.getParentPath();
+                if (blockPath == null) {
+                    return;
+                }
+            }
+            BlockTree blockTree = (BlockTree) blockPath.getLeaf();
+            List<? extends StatementTree> statements = blockTree.getStatements();
+            List<StatementTree> newStatements = new ArrayList<>();
+            for (StatementTree statement : statements) {
+                if (statement != statementPath.getLeaf()) {
+                    newStatements.add(statement);
+                }
+            }
+            BlockTree newBlockTree = wc.getTreeMaker().Block(newStatements, blockTree.isStatic());
+            wc.rewrite(blockTree, newBlockTree);
         }
         }
     }
     }
 }
 }

+ 61 - 114
jme3-code-check/src/com/jme3/gde/codecheck/hints/ReadOnlyPrimitiveHint.java

@@ -1,144 +1,91 @@
 package com.jme3.gde.codecheck.hints;
 package com.jme3.gde.codecheck.hints;
 
 
-import com.jme3.system.Annotations.ReadOnly;
+import com.jme3.system.Annotations;
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.StatementTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePath;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.List;
-import java.util.Set;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import org.netbeans.api.editor.EditorRegistry;
+import javax.lang.model.element.Element;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.modules.java.hints.spi.AbstractHint;
-import org.netbeans.spi.editor.hints.ChangeInfo;
-import org.netbeans.spi.editor.hints.EnhancedFix;
+import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.ErrorDescription;
-import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.Fix;
-import org.openide.awt.StatusDisplayer;
+import org.netbeans.spi.editor.hints.Severity;
+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.util.NbBundle;
 import org.openide.util.NbBundle;
 
 
-public class ReadOnlyPrimitiveHint extends AbstractHint {
-
-    //This hint does not enable the IDE to fix the problem:
-    private static final List<Fix> NO_FIXES = Collections.<Fix>emptyList();
-    //This hint applies to method invocations:
-    private static final Set<Tree.Kind> TREE_KINDS =
-            EnumSet.<Tree.Kind>of(Tree.Kind.METHOD_INVOCATION);
-
-    public ReadOnlyPrimitiveHint() {
-        super(true, true, AbstractHint.HintSeverity.WARNING);
-    }
-
-    //Specify the kind of code that the hint applies to, in this case,
-    //the hint applies to method invocations:
-    @Override
-    public Set<Kind> getTreeKinds() {
-        return TREE_KINDS;
-    }
-
-    @Override
-    public List<ErrorDescription> run(CompilationInfo info, TreePath treePath) {
-
-//        MethodInvocationTree mit = (MethodInvocationTree) treePath.getLeaf();
-//        ExpressionTree select = mit.getMethodSelect();
-//        TreePath method = new TreePath(treePath, select);
-//        Element el = info.getTrees().getElement(method);
-//        TypeElement invokedClass = (TypeElement) el.getEnclosingElement();
-
-        if (info.getTrees().getElement(treePath).getAnnotation(ReadOnly.class) != null) {
+@Hint(id = "#ReadOnlyPrimitiveHint.id", displayName = "#ReadOnlyPrimitiveHint.display-name",
+        description = "#ReadOnlyPrimitiveHint.description", severity = Severity.WARNING,
+        category = "general")
[email protected]({
+    "ReadOnlyPrimitiveHint.display-name=This primitive is read only and should not be modified!",
+    "ReadOnlyPrimitiveHint.id=ReadOnly Primitives",
+    "ReadOnlyPrimitiveHint.description=Checks for modifications to readonly primitives. (getLocalTranslation().set())",
+    "ReadOnlyPrimitiveHint.fix-text=Remove this call"
+})
+public class ReadOnlyPrimitiveHint {
+
+    @TriggerTreeKind(Tree.Kind.METHOD_INVOCATION)
+    public static ErrorDescription hint(HintContext ctx) {
+        CompilationInfo info = ctx.getInfo();
+        TreePath treePath = ctx.getPath();
+        if (info.getTrees().getElement(treePath).getAnnotation(Annotations.ReadOnly.class) != null) {
             Tree t = treePath.getLeaf();
             Tree t = treePath.getLeaf();
-            //prepare selection for removing
-            JTextComponent editor = EditorRegistry.lastFocusedComponent();
-//            Document doc = editor.getDocument();
-            SourcePositions sp = info.getTrees().getSourcePositions();
-//            int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
-            int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
+            Element el = info.getTrees().getElement(info.getTrees().getPath(info.getCompilationUnit(), t));
 
 
             //TODO: add more checks
             //TODO: add more checks
-            boolean fail = false;
-            if (info.getText().length() >= end + 4) {
-                String dotText = info.getText().substring(end, end + 4);
-                if (".set".equals(dotText)) {
-                    fail = true;
-                }
-            }
-
-            if (fail) {
-                return Collections.<ErrorDescription>singletonList(
-                        ErrorDescriptionFactory.createErrorDescription(
-                        getSeverity().toEditorSeverity(),
-                        getDisplayName(),
-                        NO_FIXES,
-                        info.getFileObject(),
-                        (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), t),
-                        (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), t)));
+            if ("set".equals(el.getSimpleName().toString())) {
+                Fix fix = new ReadOnlyPrimitiveHint.FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
+                return ErrorDescriptionFactory.forName(
+                        ctx,
+                        ctx.getPath(),
+                        Bundle.ReadOnlyPrimitiveHint_display_name(),
+                        fix);
             }
             }
-            return null;
-
         }
         }
 
 
         return null;
         return null;
-
     }
     }
 
 
-    //This is called if/when the hint processing is cancelled:
-    @Override
-    public void cancel() {
-    }
+    private static final class FixImpl extends JavaFix {
 
 
-    //Message that the user sees in the left sidebar:
-    @Override
-    public String getDisplayName() {
-        return NbBundle.getMessage(ReadOnlyPrimitiveHint.class, "ReadOnlyPrimitiveHint.display-name");
-    }
-
-    //Name of the hint in the Options window:
-    @Override
-    public String getId() {
-        return NbBundle.getMessage(ReadOnlyPrimitiveHint.class, "ReadOnlyPrimitiveHint.id");
-    }
-
-    //Description of the hint in the Options window:
-    @Override
-    public String getDescription() {
-        return NbBundle.getMessage(ReadOnlyPrimitiveHint.class, "ReadOnlyPrimitiveHint.description");
-    }
-
-    class MessagesFix implements EnhancedFix {
-
-        Document doc = null;
-        int start = 0;
-        String bodyText = null;
-
-        public MessagesFix(Document doc, int start, String bodyText) {
-            this.doc = doc;
-            this.start = start;
-            this.bodyText = bodyText;
+        public FixImpl(CompilationInfo info, TreePath tp) {
+            super(info, tp);
         }
         }
 
 
         @Override
         @Override
-        public CharSequence getSortText() {
-            return "charsequence";
+        protected String getText() {
+            return Bundle.ReadOnlyPrimitiveHint_fix_text();
         }
         }
 
 
         @Override
         @Override
-        public String getText() {
-            return NbBundle.getMessage(ReadOnlyPrimitiveHint.class, "ReadOnlyPrimitiveHint.fix-text");
-        }
-
-        @Override
-        public ChangeInfo implement() throws Exception {
-            //Add 1 character, for the semi-colon:
-            doc.remove(start, bodyText.length() + 1);
-            //Display message to user in status bar:
-            StatusDisplayer.getDefault().setStatusText("Removed: " + bodyText);
-            return null;
+        protected void performRewrite(JavaFix.TransformationContext tc) throws Exception {
+            WorkingCopy wc = tc.getWorkingCopy();
+            TreePath statementPath = tc.getPath();
+            TreePath blockPath = tc.getPath().getParentPath();
+            while (!(blockPath.getLeaf() instanceof BlockTree)) {
+                statementPath = blockPath;
+                blockPath = blockPath.getParentPath();
+                if (blockPath == null) {
+                    return;
+                }
+            }
+            BlockTree blockTree = (BlockTree) blockPath.getLeaf();
+            List<? extends StatementTree> statements = blockTree.getStatements();
+            List<StatementTree> newStatements = new ArrayList<>();
+            for (StatementTree statement : statements) {
+                if (statement != statementPath.getLeaf()) {
+                    newStatements.add(statement);
+                }
+            }
+            BlockTree newBlockTree = wc.getTreeMaker().Block(newStatements, blockTree.isStatic());
+            wc.rewrite(blockTree, newBlockTree);
         }
         }
     }
     }
 }
 }

+ 119 - 138
jme3-code-check/src/com/jme3/gde/codecheck/hints/TempVarsHint.java

@@ -1,198 +1,179 @@
 package com.jme3.gde.codecheck.hints;
 package com.jme3.gde.codecheck.hints;
 
 
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.ExpressionStatementTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.StatementTree;
 import com.sun.source.tree.StatementTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePath;
 import java.util.ArrayList;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
-import java.util.Set;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.Element;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import org.netbeans.api.editor.EditorRegistry;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.modules.java.hints.spi.AbstractHint;
-import org.netbeans.spi.editor.hints.ChangeInfo;
-import org.netbeans.spi.editor.hints.EnhancedFix;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.ErrorDescription;
-import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.Fix;
-import org.openide.awt.StatusDisplayer;
+import org.netbeans.spi.editor.hints.Severity;
+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.util.NbBundle;
 import org.openide.util.NbBundle;
 
 
-public class TempVarsHint extends AbstractHint {
-
-    //This hint does not enable the IDE to fix the problem:
-    private static final List<Fix> NO_FIXES = Collections.<Fix>emptyList();
-    //This hint applies to method invocations:
-    private static final Set<Tree.Kind> TREE_KINDS =
-            EnumSet.<Tree.Kind>of(Tree.Kind.METHOD);
-    private List<varsPosition> vars = new ArrayList<varsPosition>();
+@Hint(id = "#TempVarsHint.id", displayName = "#TempVarsHint.display-name",
+        description = "#TempVarsHint.description", severity = Severity.WARNING,
+        category = "general")
[email protected]({
+    "TempVarsHint.display-name=TempVars might not be released",
+    "TempVarsHint.id=TempVars release check",
+    "TempVarsHint.description=Checks for calls TempVars.get() and search for correspondinng release() call",
+    "TempVarsHint.fix-text=Add a release() call at the end of the method",})
+public class TempVarsHint {
+
+    @TriggerTreeKind(Tree.Kind.METHOD)
+    public static List<ErrorDescription> hint(HintContext ctx) {
+        MethodTree mt = (MethodTree) ctx.getPath().getLeaf();
+        CompilationInfo info = ctx.getInfo();
+
+        // Get the list of unreleased temp variables inside the method body
+        Collection<VarsPosition> vars = getUnreleasedTempVars(mt, info);
+        if (!vars.isEmpty()) {
+            List<ErrorDescription> list = new ArrayList<>(vars.size());
+
+            for (VarsPosition curVar : vars) {
+                Fix fix = new TempVarsHint.FixImpl(ctx.getInfo(), ctx.getPath(), curVar).toEditorFix();
+                list.add(ErrorDescriptionFactory.forSpan(
+                        ctx,
+                        curVar.start, curVar.end,
+                        Bundle.TempVarsHint_display_name(),
+                        fix));
+            }
 
 
-    public TempVarsHint() {
-        super(true, true, AbstractHint.HintSeverity.WARNING);
-    }
+            return list;
+        }
 
 
-    //Specify the kind of code that the hint applies to, in this case,
-    //the hint applies to method invocations:
-    @Override
-    public Set<Kind> getTreeKinds() {
-        return TREE_KINDS;
+        return null;
     }
     }
 
 
-    @Override
-    public List<ErrorDescription> run(CompilationInfo info, TreePath treePath) {
-
-        MethodTree mt = (MethodTree) treePath.getLeaf();
-        vars.clear();
+    private static List<VarsPosition> getUnreleasedTempVars(MethodTree mt, CompilationInfo info) {
         if (mt.getBody() != null) {
         if (mt.getBody() != null) {
+            List<VarsPosition> vars = null;
             for (StatementTree t : mt.getBody().getStatements()) {
             for (StatementTree t : mt.getBody().getStatements()) {
 
 
-
                 if (t.getKind().equals(Tree.Kind.VARIABLE)) {
                 if (t.getKind().equals(Tree.Kind.VARIABLE)) {
                     Element el = info.getTrees().getElement(info.getTrees().getPath(info.getCompilationUnit(), t));
                     Element el = info.getTrees().getElement(info.getTrees().getPath(info.getCompilationUnit(), t));
-                    String name = t.toString();
+                    String realTypeName = el.asType().toString();
 
 
-                    //This is where it all happens: if the method invocation is 'showMessageDialog',
-                    //then the hint infrastructure kicks into action:
-                    if (name.indexOf("TempVars.get()") >= 0) {
+                    // Check that the variable type is TempVars
+                    if ("com.jme3.util.TempVars".equals(realTypeName)) {
 
 
                         SourcePositions sp = info.getTrees().getSourcePositions();
                         SourcePositions sp = info.getTrees().getSourcePositions();
                         int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
                         int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
                         int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
                         int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
-                        vars.add(new varsPosition(el.getSimpleName().toString(), start, end));
+                        String variableName = el.getSimpleName().toString();
+                        if (vars == null) {
+                            vars = new ArrayList<>();
+                        }
+                        vars.add(new VarsPosition(variableName, start, end));
                         // System.err.println("TempVars.get() at " + start + " " + end+" for variable "+el.getSimpleName().toString());
                         // System.err.println("TempVars.get() at " + start + " " + end+" for variable "+el.getSimpleName().toString());
                     }
                     }
 
 
                 }
                 }
-                if (t.getKind().equals(Tree.Kind.EXPRESSION_STATEMENT) && !vars.isEmpty()) {
-                    Element el = info.getTrees().getElement(treePath);
-                    String name = t.toString();
-
-
-                    if (name.indexOf(".release()") >= 0) {
-
-                        for (Iterator<varsPosition> it = vars.iterator(); it.hasNext();) {
-                            varsPosition curVar = it.next();
-                            //This is where it all happens: if the method invocation is 'showMessageDialog',
-                            //then the hint infrastructure kicks into action:
-                            if (name.indexOf(curVar.varName + ".release()") >= 0) {
-                                //prepare selection for removing                       
-                                it.remove();
-
-//                            SourcePositions sp = info.getTrees().getSourcePositions();
-//                            int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
-//                            int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
-//                            System.err.println(curVar.varName + ".release() at " + start + " " + end);
-
+                if (vars != null && !vars.isEmpty() && t.getKind().equals(Tree.Kind.EXPRESSION_STATEMENT)) {
+                    ExpressionStatementTree expressionStatementTree = (ExpressionStatementTree) t;
+                    if (expressionStatementTree.getExpression().getKind().equals(Tree.Kind.METHOD_INVOCATION)) {
+                        MethodInvocationTree methodInvocationTree = (MethodInvocationTree) expressionStatementTree.getExpression();
+
+                        // See that the method is called on a member
+                        if (methodInvocationTree.getMethodSelect().getKind().equals(Tree.Kind.MEMBER_SELECT)) {
+                            MemberSelectTree memberSelectTree = (MemberSelectTree) methodInvocationTree.getMethodSelect();
+                            Element el = info.getTrees().getElement(info.getTrees().getPath(info.getCompilationUnit(), methodInvocationTree));
+
+                            // Check that the method being called is "release"
+                            if ("release".equals(el.getSimpleName().toString())) {
+                                String variableName = memberSelectTree.getExpression().toString();
+                                for (Iterator<VarsPosition> it = vars.iterator(); it.hasNext();) {
+                                    VarsPosition curVar = it.next();
+                                    if (variableName.equals(curVar.varName)) {
+                                        //prepare selection for removing
+                                        it.remove();
+
+                                        //SourcePositions sp = info.getTrees().getSourcePositions();
+                                        //int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
+                                        //int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
+                                        //System.err.println(curVar.varName + ".release() at " + start + " " + end);
+                                        break;
+                                    }
+                                }
                             }
                             }
                         }
                         }
                     }
                     }
-
                 }
                 }
-
-
             }
             }
-        }
-        if (!vars.isEmpty()) {
-            List<ErrorDescription> list = new ArrayList<ErrorDescription>();
-
-            JTextComponent editor = EditorRegistry.lastFocusedComponent();
-            Document doc = editor.getDocument();
-            List<Fix> fixes = new ArrayList<Fix>();
-            SourcePositions sp = info.getTrees().getSourcePositions();
-            int methodEnd = (int) (sp.getEndPosition(info.getCompilationUnit(), mt) - 1);
-
-            for (varsPosition curVar : vars) {
-                String bodyText = "    "+curVar.varName + ".release();\n    ";
-                fixes.clear();
-                fixes.add(new MessagesFix(doc, methodEnd, bodyText));
-
-                list.add(ErrorDescriptionFactory.createErrorDescription(
-                        getSeverity().toEditorSeverity(),
-                        getDisplayName(),
-                        fixes,
-                        info.getFileObject(),
-                        curVar.start, curVar.end));
-            }
-            return list;
-        }
-
-        return null;
-
-    }
-
-    //This is called if/when the hint processing is cancelled:
-    @Override
-    public void cancel() {
-    }
-
-    //Message that the user sees in the left sidebar:
-    @Override
-    public String getDisplayName() {
-        return NbBundle.getMessage(TempVarsHint.class, "TempVarsHint.display-name");
-    }
 
 
-    //Name of the hint in the Options window:
-    @Override
-    public String getId() {
-        return NbBundle.getMessage(TempVarsHint.class, "TempVarsHint.id");
-    }
+            return (vars == null ? Collections.emptyList() : vars);
+        }
 
 
-    //Description of the hint in the Options window:
-    @Override
-    public String getDescription() {
-        return NbBundle.getMessage(TempVarsHint.class, "TempVarsHint.description");
+        return Collections.emptyList();
     }
     }
 
 
-    class MessagesFix implements EnhancedFix {
+    private static final class VarsPosition {
 
 
-        Document doc = null;
-        int start = 0;
-        String bodyText = null;
+        final String varName;
+        final int start;
+        final int end;
 
 
-        public MessagesFix(Document doc, int start, String bodyText) {
-            this.doc = doc;
+        public VarsPosition(String varName, int start, int end) {
+            this.varName = varName;
+            this.end = end;
             this.start = start;
             this.start = start;
-            this.bodyText = bodyText;
         }
         }
 
 
         @Override
         @Override
-        public CharSequence getSortText() {
-            return "charsequence";
+        public String toString() {
+            return varName;
         }
         }
 
 
-        @Override
-        public String getText() {
-            return NbBundle.getMessage(TempVarsHint.class, "TempVarsHint.fix-text");
+    }
+
+    private static final class FixImpl extends JavaFix {
+
+        private final VarsPosition variable;
+
+        public FixImpl(CompilationInfo info, TreePath tp, VarsPosition variable) {
+            super(info, tp);
+            this.variable = variable;
         }
         }
 
 
         @Override
         @Override
-        public ChangeInfo implement() throws Exception {
-            //Adding the release call
-            doc.insertString(start, bodyText, null);            
-            //Display message to user in status bar:
-            StatusDisplayer.getDefault().setStatusText("Added: " + bodyText);
-            return null;
+        protected String getText() {
+            return Bundle.TempVarsHint_fix_text();
         }
         }
-    }
-
-    class varsPosition {
 
 
-        String varName;
-        int start;
-        int end;
-
-        public varsPosition(String varName, int start, int end) {
-            this.varName = varName;
-            this.end = end;
-            this.start = start;
+        @Override
+        protected void performRewrite(JavaFix.TransformationContext tc) throws Exception {
+            WorkingCopy wc = tc.getWorkingCopy();
+            TreePath tp = tc.getPath();
+            final BlockTree oldBody = ((MethodTree) tp.getLeaf()).getBody();
+            if (oldBody == null) {
+                return;
+            }
+            TreeMaker make = wc.getTreeMaker();
+            List<? extends StatementTree> statements = oldBody.getStatements();
+            List<StatementTree> newStatements = new ArrayList<>(statements.size() + 1);
+            newStatements.addAll(statements);
+            newStatements.add(make.ExpressionStatement(make.MethodInvocation(Collections.emptyList(), make.MemberSelect(make.Identifier(variable.varName), "release"), Collections.emptyList())));
+
+            BlockTree newBlockTree = wc.getTreeMaker().Block(newStatements, oldBody.isStatic());
+            wc.rewrite(oldBody, newBlockTree);
         }
         }
     }
     }
 }
 }

+ 67 - 118
jme3-code-check/src/com/jme3/gde/codecheck/hints/UpdateHint.java

@@ -1,136 +1,85 @@
 package com.jme3.gde.codecheck.hints;
 package com.jme3.gde.codecheck.hints;
 
 
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-import com.sun.source.util.SourcePositions;
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.StatementTree;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePath;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
 import java.util.List;
 import java.util.List;
-import java.util.Set;
-import javax.lang.model.element.Element;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import org.netbeans.api.editor.EditorRegistry;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.modules.java.hints.spi.AbstractHint;
-import org.netbeans.spi.editor.hints.ChangeInfo;
-import org.netbeans.spi.editor.hints.EnhancedFix;
+import org.netbeans.api.java.source.WorkingCopy;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.ErrorDescription;
-import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.Fix;
-import org.openide.awt.StatusDisplayer;
+import org.netbeans.spi.editor.hints.Severity;
+import org.netbeans.spi.java.hints.ConstraintVariableType;
+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.TriggerPattern;
+import org.netbeans.spi.java.hints.TriggerPatterns;
 import org.openide.util.NbBundle;
 import org.openide.util.NbBundle;
 
 
-public class UpdateHint extends AbstractHint {
-
-    //This hint does not enable the IDE to fix the problem:
-    private static final List<Fix> NO_FIXES = Collections.<Fix>emptyList();
-    //This hint applies to method invocations:
-    private static final Set<Tree.Kind> TREE_KINDS =
-            EnumSet.<Tree.Kind>of(Tree.Kind.METHOD_INVOCATION);
-
-    public UpdateHint() {
-        super(true, true, AbstractHint.HintSeverity.WARNING);
-    }
-
-    //Specify the kind of code that the hint applies to, in this case,
-    //the hint applies to method invocations:
-    @Override
-    public Set<Kind> getTreeKinds() {
-        return TREE_KINDS;
-    }
-
-    @Override
-    public List<ErrorDescription> run(CompilationInfo info, TreePath treePath) {
-
-        Tree t = treePath.getLeaf();
-
-        Element el = info.getTrees().getElement(treePath);
-        String name = el.getSimpleName().toString();
-
-        //This is where it all happens: if the method invocation is 'showMessageDialog',
-        //then the hint infrastructure kicks into action:
-        if (name.equals("updateGeometricState") || name.equals("updateLogicalState") || name.equals("updateModelBound")) {
-            //prepare selection for removing
-            JTextComponent editor = EditorRegistry.lastFocusedComponent();
-            Document doc = editor.getDocument();
-            SourcePositions sp = info.getTrees().getSourcePositions();
-            int start = (int) sp.getStartPosition(info.getCompilationUnit(), t);
-            int end = (int) sp.getEndPosition(info.getCompilationUnit(), t);
-            String bodyText = info.getText().substring(start, end);
-            //prepare fix
-            List<Fix> fixes = new ArrayList<Fix>();
-            fixes.add(new MessagesFix(doc, start, bodyText));
-
-            return Collections.<ErrorDescription>singletonList(
-                    ErrorDescriptionFactory.createErrorDescription(
-                    getSeverity().toEditorSeverity(),
-                    getDisplayName(),
-                    fixes,
-                    info.getFileObject(),
-                    (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), t),
-                    (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), t)));
-
-        }
-
-        return null;
-
-    }
-
-    //This is called if/when the hint processing is cancelled:
-    @Override
-    public void cancel() {
-    }
-
-    //Message that the user sees in the left sidebar:
-    @Override
-    public String getDisplayName() {
-        return NbBundle.getMessage(UpdateHint.class, "UpdateHint.display-name");
-    }
-
-    //Name of the hint in the Options window:
-    @Override
-    public String getId() {
-        return NbBundle.getMessage(UpdateHint.class, "UpdateHint.id");
-    }
-
-    //Description of the hint in the Options window:
-    @Override
-    public String getDescription() {
-        return NbBundle.getMessage(UpdateHint.class, "UpdateHint.description");
-    }
-
-    class MessagesFix implements EnhancedFix {
-
-        Document doc = null;
-        int start = 0;
-        String bodyText = null;
-
-        public MessagesFix(Document doc, int start, String bodyText) {
-            this.doc = doc;
-            this.start = start;
-            this.bodyText = bodyText;
-        }
-
-        @Override
-        public CharSequence getSortText() {
-            return "charsequence";
+@Hint(id = "#UpdateHint.id", displayName = "#UpdateHint.display-name",
+        description = "#UpdateHint.description", severity = Severity.WARNING,
+        category = "general")
[email protected]({
+    "UpdateHint.id=Update States / Bound",
+    "UpdateHint.display-name=Updating is not needed in jME3, check your update order if you need to call this.",
+    "UpdateHint.description=Checks for calls to updateGeometricState(), updateLogicalState() and updateModelBound().",
+    "UpdateHint.fix-text=Remove this call"
+})
+public class UpdateHint {
+
+     @TriggerPatterns({
+         @TriggerPattern(value = "$type.updateGeometricState",
+                 constraints=@ConstraintVariableType(variable="$type", type="com.jme3.scene.Spatial")),
+         @TriggerPattern(value = "$type.updateLogicalState",
+                 constraints=@ConstraintVariableType(variable="$type", type="com.jme3.scene.Spatial")),
+         @TriggerPattern(value = "$type.updateModelBound",
+                 constraints=@ConstraintVariableType(variable="$type", type="com.jme3.scene.Spatial"))
+     })
+     public static ErrorDescription hint(HintContext ctx) {
+         Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
+         return ErrorDescriptionFactory.forName(
+                 ctx,
+                 ctx.getPath(),
+                 Bundle.UpdateHint_display_name(),
+                 fix);
+     }
+
+    private static final class FixImpl extends JavaFix {
+
+        public FixImpl(CompilationInfo info, TreePath tp) {
+            super(info, tp);
         }
         }
 
 
         @Override
         @Override
-        public String getText() {
-            return NbBundle.getMessage(UpdateHint.class, "UpdateHint.fix-text");
+        protected String getText() {
+            return Bundle.UpdateHint_fix_text();
         }
         }
 
 
         @Override
         @Override
-        public ChangeInfo implement() throws Exception {
-            //Add 1 character, for the semi-colon:
-            doc.remove(start, bodyText.length() + 1);
-            //Display message to user in status bar:
-            StatusDisplayer.getDefault().setStatusText("Removed: " + bodyText);
-            return null;
+        protected void performRewrite(TransformationContext tc) throws Exception {
+            WorkingCopy wc = tc.getWorkingCopy();
+            TreePath statementPath = tc.getPath();
+            TreePath blockPath = tc.getPath().getParentPath();
+            while (!(blockPath.getLeaf() instanceof BlockTree)) {
+                statementPath = blockPath;
+                blockPath = blockPath.getParentPath();
+                if (blockPath == null) {
+                    return;
+                }
+            }
+            BlockTree blockTree = (BlockTree) blockPath.getLeaf();
+            List<? extends StatementTree> statements = blockTree.getStatements();
+            List<StatementTree> newStatements = new ArrayList<>();
+            for (StatementTree statement : statements) {
+                if (statement != statementPath.getLeaf()) {
+                    newStatements.add(statement);
+                }
+            }
+            BlockTree newBlockTree = wc.getTreeMaker().Block(newStatements, blockTree.isStatic());
+            wc.rewrite(blockTree, newBlockTree);
         }
         }
     }
     }
-}
+}