Skip to content

Commit

Permalink
Implementation of GoTo Symbol for Groovy (apache#4091)
Browse files Browse the repository at this point in the history
* Implementation of GoTo Symbol for Groovy

* Api changes in Groovy Editor

* Fixing tests and filtering meta symbols.

* Api changes in Groovy Editor

* Simplifying writing to the index and reading from index.

* Fixing duplicated entry.

* Improving CamelCase and insensitive CamelCase.

* Synchronizing the cache.
  • Loading branch information
ppisl authored Jun 29, 2022
1 parent 1dca327 commit 77857ac
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 198 deletions.
16 changes: 15 additions & 1 deletion groovy/groovy.editor/apichanges.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ is the proper place.
<!-- ACTUAL CHANGES BEGIN HERE: -->

<changes>
<change id="GroovyElement.outer">
<api name="groovy-parsing"/>
<summary>Adding offset range for GroovyElement</summary>
<version major="1" minor="86"/>
<date day="27" month="6" year="2022"/>
<author login="ppisl"/>
<compatibility addition="yes" binary="compatible" semantic="compatible" />
<description>
<p>
GroovyElement has setOffsetRange method and it's able to remember it.
</p>
</description>
<class package="org.netbeans.modules.groovy.editor.api.elements" name="GroovyElement"/>
</change>
<change id="LexUtilities.LineDocument.methods">
<api name="groovy-parsing"/>
<summary>Variants of the exisitng methods taking LineDocument as argument added.</summary>
Expand All @@ -97,7 +111,7 @@ is the proper place.
</p>
</description>
<class package="org.netbeans.modules.groovy.editor.api.lexer" name="LexUtilities"/>
</change>
</change>
<change id="ASTPath.outer">
<api name="groovy-parsing"/>
<summary>Alternative construction for path more suitable for expressions, API to resolve types</summary>
Expand Down
2 changes: 1 addition & 1 deletion groovy/groovy.editor/manifest.mf
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ AutoUpdate-Show-In-Client: false
OpenIDE-Module: org.netbeans.modules.groovy.editor/3
OpenIDE-Module-Layer: org/netbeans/modules/groovy/editor/resources/layer.xml
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/groovy/editor/Bundle.properties
OpenIDE-Module-Specification-Version: 1.85
OpenIDE-Module-Specification-Version: 1.86

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.util.logging.Level;
import org.codehaus.groovy.ast.FieldNode;
import org.netbeans.modules.csl.api.Modifier;
import org.netbeans.modules.csl.api.OffsetRange;
import org.netbeans.modules.groovy.editor.api.lexer.LexUtilities;
import org.netbeans.modules.groovy.editor.api.elements.ast.ASTField;
import org.netbeans.modules.groovy.editor.api.elements.ast.ASTMethod;
Expand All @@ -68,6 +69,7 @@ public class GroovyIndexer extends EmbeddingIndexer {
static final String CASE_INSENSITIVE_CLASS_NAME = "class-ig"; //NOI18N
// not indexed
static final String IN = "in"; //NOI18N
static final String CLASS_OFFSET = "class-range"; //NOI18N
/** Attributes: hh;nnnn where hh is a hex representing flags in IndexedClass, and nnnn is the documentation length */
static final String CLASS_ATTRS = "attrs"; //NOI18N

Expand Down Expand Up @@ -160,7 +162,7 @@ public FileObject getPreindexedDb() {
public static final class Factory extends EmbeddingIndexerFactory {

public static final String NAME = "groovy"; // NOI18N
public static final int VERSION = 8;
public static final int VERSION = 9;

@Override
public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot snapshot) {
Expand Down Expand Up @@ -321,6 +323,9 @@ private void indexClass(ASTClass element, IndexDocument document) {
document.addPair(FQN_NAME, element.getFqn(), true, true);
document.addPair(CLASS_NAME, name, true, true);
document.addPair(CASE_INSENSITIVE_CLASS_NAME, name.toLowerCase(), true, true);
StringBuilder sb = new StringBuilder();
appendOffsetRange(sb, element.getNode(), doc);
document.addPair(CLASS_OFFSET, sb.toString(), false, true);
}

private void indexField(ASTField child, IndexDocument document) {
Expand All @@ -333,17 +338,20 @@ private void indexField(ASTField child, IndexDocument document) {

// maintain index compatibility; althogh
int flags = getFieldModifiersFlag(child.isProperty(), child.getModifiers());
sb.append(';');
if (flags != 0 || child.isProperty()) {
sb.append(';');
sb.append(IndexedElement.flagToFirstChar(flags));
sb.append(IndexedElement.flagToSecondChar(flags));
}

sb.append(';');
if (child.isProperty()) {
sb.append(';');
sb.append(child.isProperty());
}

sb.append(';');
appendOffsetRange(sb, node, doc);

// TODO - gather documentation on fields? naeh
document.addPair(FIELD_NAME, sb.toString(), true, true);
}
Expand All @@ -363,16 +371,19 @@ private void indexConstructor(ASTMethod constructor, IndexDocument document) {
// Removing last ","
sb.deleteCharAt(sb.length() - 1);
}

Set<Modifier> modifiers = constructor.getModifiers();

int flags = getMethodModifiersFlag(modifiers);
sb.append(';');
if (flags != 0) {
sb.append(';');
sb.append(IndexedElement.flagToFirstChar(flags));
sb.append(IndexedElement.flagToSecondChar(flags));
}


sb.append(';');
appendOffsetRange(sb, constructor.getNode(), doc);

document.addPair(CONSTRUCTOR, sb.toString(), true, true);
}

Expand All @@ -387,15 +398,23 @@ private void indexMethod(ASTMethod child, IndexDocument document) {
Set<Modifier> modifiers = child.getModifiers();

int flags = getMethodModifiersFlag(modifiers);


sb.append(';');
if (flags != 0) {
sb.append(';');
sb.append(IndexedElement.flagToFirstChar(flags));
sb.append(IndexedElement.flagToSecondChar(flags));
}

sb.append(';');
appendOffsetRange(sb, childNode, doc);

document.addPair(METHOD_NAME, sb.toString(), true, true);
}

private static void appendOffsetRange(StringBuilder sb, ASTNode node, BaseDocument document) {
OffsetRange range = ASTUtils.getRange(node, document);
sb.append('[').append(range.getStart()).append(',').append(range.getEnd()).append(']');
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public abstract class GroovyElement implements ElementHandle {
/** Signature of the element*/
protected String signature;

/** Offset range of the element */
protected OffsetRange offsetRange;

public GroovyElement() {
}
Expand Down Expand Up @@ -124,6 +126,11 @@ public Set<Modifier> getModifiers() {

@Override
public OffsetRange getOffsetRange(ParserResult result) {
return OffsetRange.NONE;
return this.offsetRange == null ? OffsetRange.NONE : offsetRange;
}

public void setOffsetRange(OffsetRange offsetRange) {
this.offsetRange = offsetRange;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@
import org.netbeans.modules.csl.api.IndexSearcher;
import org.netbeans.modules.csl.api.IndexSearcher.Descriptor;
import org.netbeans.modules.csl.api.IndexSearcher.Helper;
import org.netbeans.modules.csl.api.OffsetRange;
import org.netbeans.modules.csl.spi.GsfUtilities;
import org.netbeans.modules.groovy.editor.api.GroovyIndex;
import org.netbeans.modules.groovy.editor.api.elements.index.IndexedClass;
import org.netbeans.modules.groovy.editor.api.elements.index.IndexedElement;
import org.netbeans.modules.groovy.editor.api.elements.index.IndexedField;
import org.netbeans.modules.groovy.editor.api.elements.index.IndexedMethod;
import org.netbeans.modules.groovy.support.api.GroovySources;
import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport;
import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport.Kind;
Expand All @@ -59,10 +62,38 @@ public class GroovyTypeSearcher implements IndexSearcher {

@Override
public Set<? extends Descriptor> getSymbols(Project project, String textForQuery, Kind kind, Helper helper) {
// TODO - search for methods too!!
GroovyIndex index = GroovyIndex.get(QuerySupport.findRoots(project, Collections.singleton(ClassPath.SOURCE), Collections.<String>emptySet(), Collections.<String>emptySet()));

// For now, just at a minimum do the types
return getTypes(project, textForQuery, kind, helper);
kind = adjustKind(kind, textForQuery);

if (kind == QuerySupport.Kind.CASE_INSENSITIVE_PREFIX) {
textForQuery = textForQuery.toLowerCase(Locale.ENGLISH);
}

Set<GroovyTypeDescriptor> result = new HashSet<GroovyTypeDescriptor>();


if (textForQuery.length() > 0) {
Set<IndexedClass> classes = null;
classes = index.getClasses(textForQuery, kind);
for (IndexedClass cls : classes) {
result.add(new GroovyTypeDescriptor(cls, helper));
}

Set<IndexedField> fields = index.getFields(textForQuery, null, kind);
for (IndexedField field : fields) {
result.add(new GroovyTypeDescriptor(field, helper));
}

Set<IndexedMethod> methods = index.getMethods(textForQuery, null, kind);
for (IndexedMethod method : methods) {
if (method.getOffsetRange(null) != OffsetRange.NONE) {
result.add(new GroovyTypeDescriptor(method, helper));
}
}
}

return result;
}

@Override
Expand Down Expand Up @@ -208,11 +239,8 @@ public void open() {
// out by getFileObject (to avoid checking file existence multiple times; use a boolean
// flag for that instead)
} else {

// TODO: Would be good to change offset to the start of the class decalaration instead
// of zero. Unfortunatelly we don't have such an information in the index so far and
// parsing whole AST for that is too expensive (see issue 183727 for background)
GsfUtilities.open(fileObject, 0, element.getName());
GsfUtilities.open(fileObject, getOffset(), element.getName());
}
}

Expand Down Expand Up @@ -251,7 +279,8 @@ public ElementHandle getElement() {

@Override
public int getOffset() {
throw new UnsupportedOperationException("Not supported yet.");
OffsetRange range = element.getOffsetRange(null);
return range != null ? range.getStart() : -1;
}

@Override
Expand All @@ -264,6 +293,41 @@ public String getOuterName() {
return null;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
GroovyTypeDescriptor other = (GroovyTypeDescriptor) obj;
if (this.element != null) {
if (!this.element.equals(other.element)) {
return false;
}
} else if (other.element != null) {
return false;
}
if (this.helper != null) {
if (!this.helper.equals(other.helper)) {
return false;
}
} else if (other.helper != null) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 11;
hash = 23 * hash + (this.element != null ? this.element.hashCode() : 0);
hash = 23 * hash + (this.helper != null ? this.helper.hashCode() : 0);
return hash;
}


}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,51 @@ Document 0
Searchable Keys:
class : BookmarkController
class-ig : bookmarkcontroller
field : create;java.lang.Object;00;true
field : delete;java.lang.Object;00;true
field : deliciousService;DeliciousService;00;true
field : edit;java.lang.Object;00;true
field : list;java.lang.Object;00;true
field : params;java.util.Map;00;true
field : preview;java.lang.Object;00;true
field : save;java.lang.Object;00;true
field : scaffold;java.lang.Object;00;true
field : search;java.lang.Object;00;true
field : suggestTag;java.lang.Object;00;true
field : update;java.lang.Object;00;true
field : updateNotes;java.lang.Object;00;true
field : create;java.lang.Object;00;true;[233,239]
field : delete;java.lang.Object;00;true;[894,900]
field : deliciousService;DeliciousService;00;true;[137,153]
field : edit;java.lang.Object;00;true;[635,639]
field : list;java.lang.Object;00;true;[2586,2590]
field : params;java.util.Map;00;true;[164,170]
field : preview;java.lang.Object;00;true;[442,449]
field : save;java.lang.Object;00;true;[1583,1587]
field : scaffold;java.lang.Object;00;true;[93,101]
field : search;java.lang.Object;00;true;[3125,3131]
field : suggestTag;java.lang.Object;00;true;[4226,4236]
field : update;java.lang.Object;00;true;[1166,1172]
field : updateNotes;java.lang.Object;00;true;[4039,4050]
fqn : BookmarkController
method : addTags(Bookmark);java.lang.Object;02
method : getCreate;java.lang.Object;01
method : getDelete;java.lang.Object;01
method : getDeliciousService;DeliciousService;01
method : getEdit;java.lang.Object;01
method : getList;java.lang.Object;01
method : getMetaClass;groovy.lang.MetaClass;01
method : getParams;java.util.Map;01
method : getPreview;java.lang.Object;01
method : getSave;java.lang.Object;01
method : getScaffold;java.lang.Object;01
method : getSearch;java.lang.Object;01
method : getSuggestTag;java.lang.Object;01
method : getSuggestions(java.lang.Object,java.lang.Object);java.lang.Object;02
method : getUpdate;java.lang.Object;01
method : getUpdateNotes;java.lang.Object;01
method : printParams(java.lang.Object,java.lang.Object);java.lang.Object;02
method : setCreate(java.lang.Object);void;01
method : setDelete(java.lang.Object);void;01
method : setDeliciousService(DeliciousService);void;01
method : setEdit(java.lang.Object);void;01
method : setList(java.lang.Object);void;01
method : setMetaClass(groovy.lang.MetaClass);void;01
method : setParams(java.util.Map);void;01
method : setPreview(java.lang.Object);void;01
method : setSave(java.lang.Object);void;01
method : setScaffold(java.lang.Object);void;01
method : setSearch(java.lang.Object);void;01
method : setSuggestTag(java.lang.Object);void;01
method : setUpdate(java.lang.Object);void;01
method : setUpdateNotes(java.lang.Object);void;01
method : addTags(Bookmark);java.lang.Object;02;[1974,1981]
method : getCreate;java.lang.Object;01;[0,0]
method : getDelete;java.lang.Object;01;[0,0]
method : getDeliciousService;DeliciousService;01;[0,0]
method : getEdit;java.lang.Object;01;[0,0]
method : getList;java.lang.Object;01;[0,0]
method : getMetaClass;groovy.lang.MetaClass;01;[0,0]
method : getParams;java.util.Map;01;[0,0]
method : getPreview;java.lang.Object;01;[0,0]
method : getSave;java.lang.Object;01;[0,0]
method : getScaffold;java.lang.Object;01;[0,0]
method : getSearch;java.lang.Object;01;[0,0]
method : getSuggestTag;java.lang.Object;01;[0,0]
method : getSuggestions(java.lang.Object,java.lang.Object);java.lang.Object;02;[5074,5088]
method : getUpdate;java.lang.Object;01;[0,0]
method : getUpdateNotes;java.lang.Object;01;[0,0]
method : printParams(java.lang.Object,java.lang.Object);java.lang.Object;02;[4961,4972]
method : setCreate(java.lang.Object);void;01;[0,0]
method : setDelete(java.lang.Object);void;01;[0,0]
method : setDeliciousService(DeliciousService);void;01;[0,0]
method : setEdit(java.lang.Object);void;01;[0,0]
method : setList(java.lang.Object);void;01;[0,0]
method : setMetaClass(groovy.lang.MetaClass);void;01;[0,0]
method : setParams(java.util.Map);void;01;[0,0]
method : setPreview(java.lang.Object);void;01;[0,0]
method : setSave(java.lang.Object);void;01;[0,0]
method : setScaffold(java.lang.Object);void;01;[0,0]
method : setSearch(java.lang.Object);void;01;[0,0]
method : setSuggestTag(java.lang.Object);void;01;[0,0]
method : setUpdate(java.lang.Object);void;01;[0,0]
method : setUpdateNotes(java.lang.Object);void;01;[0,0]

Not Searchable Keys:
class-range : [37:55]
Loading

0 comments on commit 77857ac

Please sign in to comment.