Problem searching for Java methods by bean property name

I'm trying to allow my plugin to have references in Clojure code to Java methods, referring to them by their bean property name like this:

[Customer (= true VIP)]

Here Customer refers to a Java class, and VIP refers to its isVIP() method. The symbol resolution is working in the editor, but find usages from the declaration of the method doesn't find this usage. After poking around in the source code I found CustomPropertyScopeProvider and I implemented that as follows:

public class ClojureCustomPropertyScopeProvider implements CustomPropertyScopeProvider {
public SearchScope getScope(Project project) {
return GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project),
ClojureFileType.getInstance(),
CljcFileType.getInstance());
}
}

However the find usages still doesn't work. Is there anything else I need to do to ensure this works?

 

5 comments

One other thing - the usages highlighting within the editor works fine, so all the basic stuff like word scanning etc is working. It seems to be a problem with scopes. I don't really understand how the low levels of the index code work, but I can only see scopes relating to Java being used at the lower levels, so I guess my contributed scope is getting intersected out somehow. My scope contributor is being called correctly.

0

I managed to resolve this by implementing a custom MethodReferenceSearcher.

0

I'm struggling with exactly the same problem. Does anyone know what can be the reason? I'd like to understand why it's not working and avoid implementing custom searcher to solve the issue.

Elements are resolved and highlighted correctly, but if I run Find Usages action, nothing is found. The "isReferenceTo()" method is not even invoked during finding usages, so I guess tokens are not found or somehow ignored/excluded. For "getName()" method my element's text can be ".name" or ".getName" (notice dot before property name). If I use ".getName", then usages are found. If I mix ".name" and ".getName" in a file, only ".getName" usages are found.

I spent a few hours on debugging, but the code and flow are too hard to understand for me. My CustomPropertyScopeProvider is implemented as follows:

class HtlPropertyScopeProvider : CustomPropertyScopeProvider {

override fun getScope(project: Project) =
GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), HtlFileType)

}

It is called during Find Usages action. My property access element implements PsiNamedElement and PsiReference. The "getRangeInElement()" correctly skips dot.

Help!

0

I found the reason. I defined FindUsagesProvider:

class HtlVariablesFindUsagesProvider : FindUsagesProvider {

...

override fun getWordsScanner() = DefaultWordsScanner(
HtlLexerAdapter(),
TokenSet.create(IDENTIFIER),
TokenSet.create(COMMENT_START, COMMENT_CONTENT, COMMENT_END),
TokenSet.create(STRING, INTEGER_NUMBER, FLOAT_NUMBER, BOOLEAN_LITERAL)
)

...

}

DefaultWordsScanner has a line handling my identifiers tokens:

if (!stripWords(processor, fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE, occurrence, false)) ...

What's important it passes WordOccurrence.Kind.CODE to the processor. It is processed in IdTableBuilding class:

consumer.addOccurrence(t.getBaseText(), t.getStart(), t.getEnd(), convertToMask(t.getKind()));

and "kind" is converted to mask:

private int convertToMask(final WordOccurrence.Kind kind) {
if (kind == null) {
return UsageSearchContext.ANY;
}
if (kind == WordOccurrence.Kind.CODE) return UsageSearchContext.IN_CODE;
if (kind == WordOccurrence.Kind.COMMENTS) return UsageSearchContext.IN_COMMENTS;
if (kind == WordOccurrence.Kind.LITERALS) return UsageSearchContext.IN_STRINGS;
if (kind == WordOccurrence.Kind.FOREIGN_LANGUAGE) return UsageSearchContext.IN_FOREIGN_LANGUAGES;
return 0;
}

So it is converted to UsageSearchContext.IN_CODE.

The problem is that MethodUsagesSearcher (which uses the CustomPropertyScopeProvider) invokes:

SimpleAccessorReferenceSearcher.addPropertyAccessUsages(method, restrictedByAccessScope, collector);

Let's check how it looks inside:

collector.searchWord(propertyName, propScope, UsageSearchContext.IN_FOREIGN_LANGUAGES, true, method);

So it searches property occurrences in IN_FOREIGN_LANGUAGES context. The property occurrence was indexed as UsageSearchContext.IN_CODE.

Later in PsiSearchHelperImpl we have such statement:

myDumbService.runReadActionInSmartMode(
() -> FileBasedIndex.getInstance().processValues(IdIndex.NAME, indexEntry, file, (file1, value) -> {
int mask = value.intValue();
for (RequestWithProcessor single : processors) {
ProgressManager.checkCanceled();
final PsiSearchRequest request = single.request;
if ((mask & request.searchContext) != 0 && request.searchScope.contains(file1)) {
MultiMap<VirtualFile, RequestWithProcessor> result1 =
intersectionWithContainerNameFiles == null || !intersectionWithContainerNameFiles.contains(file1) ? restResult : intersectionResult;
result1.putValue(file1, single);
}
}
return true;
}, commonScope))

Important is:

if ((mask & request.searchContext) != 0 ...) {
...
}

mask of the indexed word is IN_CODE (1) and property search context is IN_FOREIGN_LANGUAGES (8). IN_CODE & IN_FOREIGN_LANGUAGES == 0, so if condition is evaluated to false.

I'm thinking how to fix it now. Any ideas?

0

OK, I ended up with implementing `methodReferencesSearch` extension, like Colin.

0

Please sign in to leave a comment.