You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by sr...@apache.org on 2018/09/30 15:33:33 UTC
[incubator-netbeans] branch master updated: [NETBEANS-1292] Adding
simple infrastructure to write Groovy Hints based on AST (not errors).
This is an automated email from the ASF dual-hosted git repository.
sreimers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new a9e5e74 [NETBEANS-1292] Adding simple infrastructure to write Groovy Hints based on AST (not errors).
a9e5e74 is described below
commit a9e5e745f7f83e0b930c956e54027537a229e07f
Author: Sven Reimers <sv...@users.noreply.github.com>
AuthorDate: Sun Sep 30 17:33:29 2018 +0200
[NETBEANS-1292] Adding simple infrastructure to write Groovy Hints based on AST (not errors).
---
.../groovy/editor/hints/HintsAdvancedOption.java | 63 ++++++++
.../editor/hints/RemoveUnusedImportHint.java | 178 +++++++++++++++++++++
.../editor/hints/infrastructure/Bundle.properties | 18 +++
.../editor/hints/infrastructure/GroovyAstRule.java | 38 +++++
.../hints/infrastructure/GroovyHintsProvider.java | 37 ++++-
.../modules/groovy/editor/resources/layer.xml | 19 +++
6 files changed, 351 insertions(+), 2 deletions(-)
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/HintsAdvancedOption.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/HintsAdvancedOption.java
new file mode 100644
index 0000000..5271ede
--- /dev/null
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/HintsAdvancedOption.java
@@ -0,0 +1,63 @@
+/*
+ * 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.groovy.editor.hints;
+
+import org.netbeans.modules.csl.api.HintsProvider;
+import org.netbeans.modules.groovy.editor.api.parser.GroovyLanguage;
+import org.netbeans.spi.options.AdvancedOption;
+import org.netbeans.spi.options.OptionsPanelController;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author Sven Reimers
+ */
+public class HintsAdvancedOption extends AdvancedOption {
+
+ OptionsPanelController panelController;
+
+ @Override
+ @NbBundle.Messages("CTL_Hints_DisplayName=Hints")
+ public String getDisplayName() {
+ return Bundle.CTL_Hints_DisplayName();
+ }
+
+ @Override
+ @NbBundle.Messages("CTL_Hints_ToolTip=Static code verification for Groovy")
+ public String getTooltip() {
+ return Bundle.CTL_Hints_ToolTip();
+ }
+
+ @Override
+ public synchronized OptionsPanelController create() {
+ if ( panelController == null ) {
+ HintsProvider.HintsManager manager = HintsProvider.HintsManager.getManagerForMimeType(GroovyLanguage.GROOVY_MIME_TYPE);
+ assert manager != null;
+ panelController = manager.getOptionsController();
+ }
+
+ return panelController;
+ }
+
+ //TODO: temporary solution, this should be solved on GSF level
+ public static OptionsPanelController createStatic(){
+ return new HintsAdvancedOption().create();
+ }
+}
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
new file mode 100644
index 0000000..1d16876
--- /dev/null
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
@@ -0,0 +1,178 @@
+/*
+ * 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.groovy.editor.hints;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.prefs.Preferences;
+import javax.swing.JComponent;
+import javax.swing.text.BadLocationException;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.editor.FinderFactory;
+import org.netbeans.modules.csl.api.EditList;
+import org.netbeans.modules.csl.api.Hint;
+import org.netbeans.modules.csl.api.HintFix;
+import org.netbeans.modules.csl.api.HintSeverity;
+import org.netbeans.modules.csl.api.RuleContext;
+import org.netbeans.modules.editor.NbEditorUtilities;
+import org.netbeans.modules.groovy.editor.api.ASTUtils;
+import org.netbeans.modules.groovy.editor.api.lexer.GroovyTokenId;
+import org.netbeans.modules.groovy.editor.api.lexer.LexUtilities;
+import org.netbeans.modules.groovy.editor.hints.infrastructure.GroovyAstRule;
+import org.netbeans.modules.groovy.editor.hints.infrastructure.GroovyHintsProvider;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Sven Reimers
+ */
+public class RemoveUnusedImportHint extends GroovyAstRule {
+
+ @Override
+ public void computeHints(GroovyHintsProvider.GroovyRuleContext context, List<Hint> result) {
+ final ModuleNode moduleNode = context.getGroovyParserResult().getRootElement().getModuleNode();
+ if (null == moduleNode) {
+ return;
+ }
+ List<ImportNode> importNodes = moduleNode.getImports();
+ for (ImportNode importNode : importNodes) {
+
+ String alias = importNode.getAlias();
+
+ try {
+ int find = 0;
+ final FinderFactory.StringFwdFinder stringFwdFinder = new FinderFactory.StringFwdFinder(alias, true);
+
+ while(-1 != (find = context.doc.find(stringFwdFinder, find+1, -1)) && skipUsage(find, context.doc));
+
+ if (-1 == find) {
+ result.add(new Hint(this, "Unused Import",
+ NbEditorUtilities.getFileObject(context.doc),
+ ASTUtils.getRangeFull(importNode, context.doc),
+ Collections.<HintFix>singletonList(new RemoveUnusedImportFix("Remove unused import", context.doc, importNode)), 1));
+ }
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ private boolean skipUsage(int position, BaseDocument doc) {
+ int lineNo = NbEditorUtilities.getLine(doc, position, true).getLineNumber();
+ if (0 == lineNo) {
+ return true;
+ }
+ GroovyTokenId tokenIdAtPosition = LexUtilities.getToken(doc, position).id();
+ return GroovyTokenId.LITERAL_import ==
+ LexUtilities.getToken(doc, ASTUtils.getOffset(doc, lineNo+1, 2)).id()
+ || GroovyTokenId.SH_COMMENT == tokenIdAtPosition
+ || GroovyTokenId.SL_COMMENT == tokenIdAtPosition
+ || GroovyTokenId.LINE_COMMENT == tokenIdAtPosition
+ || GroovyTokenId.BLOCK_COMMENT == tokenIdAtPosition;
+ }
+
+ @Override
+ public Set<?> getKinds() {
+ return new HashSet<>(Arrays.asList(new String[]{"Import Hints"}));
+ }
+
+ @Override
+ public String getId() {
+ return "imports.unused.hint";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Remove unused Import";
+ }
+
+ @Override
+ public boolean getDefaultEnabled() {
+ return true;
+ }
+
+ @Override
+ public JComponent getCustomizer(Preferences node) {
+ return null;
+ }
+
+ @Override
+ public boolean appliesTo(RuleContext context) {
+ return context instanceof GroovyHintsProvider.GroovyRuleContext;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "Remove unused import";
+ }
+
+ @Override
+ public boolean showInTasklist() {
+ return false;
+ }
+
+ @Override
+ public HintSeverity getDefaultSeverity() {
+ return HintSeverity.INFO;
+ }
+
+ private static class RemoveUnusedImportFix implements HintFix {
+
+ final BaseDocument baseDoc;
+ final String desc;
+ final ImportNode importNode;
+
+ public RemoveUnusedImportFix(String desc, BaseDocument baseDoc, ImportNode importNode) {
+ this.desc = desc;
+ this.baseDoc = baseDoc;
+ this.importNode = importNode;
+ }
+
+ @Override
+ public String getDescription() {
+ return desc;
+ }
+
+ @Override
+ public void implement() throws Exception {
+ EditList edits = new EditList(baseDoc);
+ int offset = ASTUtils.getOffset(baseDoc,importNode.getLineNumber(), 1);
+ int removeLen = ASTUtils.getOffset(baseDoc,importNode.getLineNumber()+1, 1)-offset;
+ edits.replace(offset, removeLen, "", true, 0);
+ edits.apply();
+ }
+
+ @Override
+ public boolean isSafe() {
+ return false;
+ }
+
+ @Override
+ public boolean isInteractive() {
+ return false;
+ }
+ }
+
+}
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/Bundle.properties b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/Bundle.properties
new file mode 100644
index 0000000..88e9918
--- /dev/null
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/Bundle.properties
@@ -0,0 +1,18 @@
+# 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.
+
+csl-hints/text/x-groovy/hints/import=Import
\ No newline at end of file
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyAstRule.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyAstRule.java
new file mode 100644
index 0000000..db2650e
--- /dev/null
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyAstRule.java
@@ -0,0 +1,38 @@
+/*
+ * 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.groovy.editor.hints.infrastructure;
+
+import java.util.List;
+import java.util.Set;
+import org.netbeans.modules.csl.api.Hint;
+import org.netbeans.modules.csl.api.Rule.AstRule;
+
+/**
+ * Represents a rule to be run on a Groovy AstNode
+ *
+ * @author Sven Reimers
+ */
+public abstract class GroovyAstRule implements AstRule {
+
+ public abstract void computeHints(GroovyHintsProvider.GroovyRuleContext context, List<Hint> result);
+
+ public abstract Set<?> getKinds();
+
+}
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyHintsProvider.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyHintsProvider.java
index 6becd1d..a576b82 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyHintsProvider.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/infrastructure/GroovyHintsProvider.java
@@ -23,6 +23,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
+import javax.swing.text.BadLocationException;
import org.codehaus.groovy.ast.ASTNode;
import org.netbeans.modules.csl.api.Error;
import org.netbeans.modules.csl.api.Hint;
@@ -43,15 +45,28 @@ import org.netbeans.modules.groovy.editor.compiler.error.GroovyError;
public class GroovyHintsProvider implements HintsProvider {
public static final Logger LOG = Logger.getLogger(GroovyHintsProvider.class.getName()); // NOI18N
- private boolean cancelled;
+ private volatile boolean cancelled;
@Override
public RuleContext createRuleContext() {
- return new RuleContext();
+ return new GroovyRuleContext();
}
@Override
public void computeHints(HintsManager manager, RuleContext context, List<Hint> hints) {
+ Map<?, List<? extends Rule.AstRule>> allHints = manager.getHints(false, context);
+ for (Map.Entry<?,List<? extends Rule.AstRule>> hintsEntry : allHints.entrySet()) {
+ for (Rule.AstRule rule : hintsEntry.getValue()) {
+ if (rule instanceof GroovyAstRule) {
+ ((GroovyAstRule)rule).computeHints((GroovyRuleContext)context, hints);
+ }
+ }
+
+ }
+ }
+
+ private void invokeHint(GroovyAstRule rule, HintsManager manager, RuleContext context, List<Hint> hints) {
+ rule.computeHints((GroovyRuleContext) context, hints);
}
@Override
@@ -139,6 +154,7 @@ public class GroovyHintsProvider implements HintsProvider {
@Override
public void cancel() {
+ cancelled = true;
}
@Override
@@ -189,4 +205,21 @@ public class GroovyHintsProvider implements HintsProvider {
return false;
}
+
+ public class GroovyRuleContext extends RuleContext {
+
+ private GroovyParserResult groovyParserResult = null;
+
+ public GroovyParserResult getGroovyParserResult() {
+ if (groovyParserResult == null) {
+ groovyParserResult = (GroovyParserResult)parserResult;
+ }
+ return groovyParserResult;
+ }
+
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ }
}
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/resources/layer.xml b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/resources/layer.xml
index 7d52fb3..613f0d5 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/resources/layer.xml
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/resources/layer.xml
@@ -33,6 +33,12 @@
<folder name="csl-hints">
<folder name="text">
<folder name="x-groovy">
+ <folder name="hints">
+ <folder name="import">
+ <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.groovy.editor.hints.infrastructure.Bundle"/>
+ <file name="org-netbeans-modules-groovy-editor-hints-RemoveUnusedImportHint.instance"/>
+ </folder>
+ </folder>
<folder name="selection">
<file name="org-netbeans-modules-groovy-editor-hints-SurroundWithHint.instance"/>
</folder>
@@ -115,6 +121,19 @@
<file name="x-groovy" url="FontsAndColorsPreview.groovy"/>
</folder>
</folder>
+ <folder name="Editor">
+ <folder name="Hints">
+ <attr name="position" intvalue="0"/>
+ <folder name="text">
+ <folder name="x-groovy">
+ <file name="GroovyHints.instance">
+ <attr name="instanceOf" stringvalue="org.netbeans.spi.options.OptionsPanelController"/>
+ <attr name="instanceCreate" methodvalue="org.netbeans.modules.groovy.editor.hints.HintsAdvancedOption.createStatic"/>
+ </file>
+ </folder>
+ </folder>
+ </folder>
+ </folder>
</folder>
<folder name="Loaders">
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists