implements SourceCodeScanner and search references

I implement  SourceCodeScanner  for search enums in project (custom lint check)

However, it is impossible to determine the logic of working with this ENUM.
I have a UClass for enum.

How can I find all the links(references) in PSI for this class in all project and analyze them?

Class "ReferencesSearch" from thit manual https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/psi_references.html not exists, and link in the manual.

And link https://upsource.jetbrains.com/idea-ce/file/idea-ce-a7b3d4e9e48efbd4ac75105e9737cea25324f11e/platform/indexing-api/com/intellij/psi/search/searches/ReferencesSearch.java from manual don't work.

13 comments
Comment actions Permalink

Could you please provide the code of your search?

0
Comment actions Permalink

private static final class EnumClassVisitor extends AbstractUastVisitor {
private final JavaContext mContext;
private boolean isBackFound = false;
UElement e;

EnumClassVisitor(JavaContext context) {
mContext = context;

}

@Override
public boolean visitClass(@NotNull UClass node) {
//NEED CHECK THEN THITS ENUM USED IN CLASS MODULE ACTIVITY AS STATUS !!!
//AND RESUTN FALSE ONLY IF ENUM USED
// return !checkAsModuleStateUsed(node)

return super.visitClass(node);
}

@Override
public boolean visitEnumConstant(@NotNull UEnumConstant field) {
String name = field.getName();
if (name != null && !name.startsWith("DIALOG_") && !name.startsWith("LAYOUT_") && !name.startsWith("PROGRESS_")) {
PsiElement e = field.getNavigationElement();
PsiEnumConstant psiMethod = field.getPsi();
mContext.report(STATUS_NAME, psiMethod, mContext.getNameLocation(psiMethod), "Bad name of module status. Need starts with DIALOG_, LAYOUT_ OR PROGRESS_";
}


return super.visitEnumConstant(field);
}
}

0
Comment actions Permalink

AbstractUastVisitor is meant to be used in "local" scopes, e.g. for inspections. You'll need to use ReferencesSearch to find usages across larger parts of the project. Please post your attempt to use it with a bit more details what doesn't work exactly.

0
Comment actions Permalink
package ru.wildberries.checks;


import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Detector.UastScanner;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.uast.UClass;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class StatusName extends Detector implements UastScanner {

public static class Registry extends IssueRegistry {
@Override
public List<Issue> getIssues() {
return Arrays.asList(STATUS_NAME,BACK_STATUS);
}
@Override public int getApi() { return com.android.tools.lint.detector.api.ApiKt.CURRENT_API; }
}

@Nullable
@Override
public List<String> applicableSuperClasses() {
return Collections.singletonList("ru.wildberries.wms.activities.ModuleActivity");
}

@Override
public void visitClass(@NotNull JavaContext context, @NotNull UClass declaration) {

PsiClassType superType = declaration.getExtendsListTypes()[0];
PsiType[] p = superType.getParameters();

if (p.length != 2) return;
if (!(p[1] instanceof PsiClassType)) return;

PsiClass enumClass = ((PsiClassType)p[1]).resolve() ;
if (enumClass == null || !enumClass.isEnum()) return;


boolean isBackFound = false;
for (PsiField field : enumClass.getFields()) {
String name = field.getName();
if (name == null) continue;
if (name.endsWith("_OR_BACK")) isBackFound = true;

if (name.startsWith("DIALOG_") || name.startsWith("LAYOUT_") || name.startsWith("PROGRESS_"))
continue;

context.report(STATUS_NAME, context.getRangeLocation(field.getNavigationElement(),0,field.getName().length()), "Status name must starts with **LAYOUT_, DIALOG_ or PROGRESS_**");
//WORK ONLY WITH getNavigationElement() BUT THEN DON'T WORK context.getNameLocation()
//context.getRangeLocation CORRECT REPORT IN LINT HTML FILE. BUT INTELLIJ SHOW WARN IN FILE WITH ENUM USIND, AND NOT SHOW WARN IN FILE WITH ENUM DECLARATION
/*shows a warning in the file using ENUM, in a place which is equal to the place in the file with ENUM declaration. If ENUM is declared and used in one file,
then the warning is correctly displayed using getNavigationElement (), however getNameLocation () does not work.*/
}

if (!isBackFound) {
context.report(BACK_STATUS, context.getNameLocation(declaration), "At least one status must end with _OR_BACK");
//NOT WORK context.report(BACK_STATUS, context.getNameLocation(enumClass), "At least one status must end with _OR_BACK");

}

}
public static final Issue STATUS_NAME = Issue.create(
"StatusName",
"Status name check",
"The status should start LAYOUT_ if setLayout is used, DIALOG_ if showDialog or PROGRESS_ is used for backgroundBuilder",
Category.CORRECTNESS,
6,
Severity.WARNING,
new Implementation(
StatusName.class,
Scope.JAVA_FILE_SCOPE));

public static final Issue BACK_STATUS = Issue.create(
"BackStatus",
"Check back status",
"If status is allowed to exit, it should end with _OR_BACK\nAt least one status must end with _OR_BACK",
Category.CORRECTNESS,
5,
Severity.ERROR,
new Implementation(
StatusName.class,
Scope.JAVA_FILE_SCOPE));

}
0
Comment actions Permalink

I brought the current decision in the "opposite direction". I am looking for using ENUM as a module state and then throwing warnings on the announcement of this ENUM if it has not passed the test.

It is correctly displayed in the LINT HTML file, but INTELLJI correctly displays warnings only if ENUM is declared in the same file as the module, otherwise it shows a warning in the file with the module on the position from the declaration file.

 

I assumed that INTELLIJ correctly displays warnings only if it is in the file pointed to by the context.UASTFile and tried to do a search in the opposite direction. From ads to use. I can find all ENUM but I need to make sure that this ENUM is used as an enumeration of the statuses of a module and only then to check its constants.

0
Comment actions Permalink

Could you please repost that in English language, please? Thank you.

0
Comment actions Permalink

I edited the message and changed my language. 
i can't use References Search because thits class NOTFOUND in current SDK.
may be need add gradle dependings? Or References Search is derpreated and have new implementstion?

0
Comment actions Permalink

Sorry for delay. Your resolved 'enumClass' can be in another file than the one currently visited/highlighted. So you cannot highlight these occurrences in the current file. In such case, you could revert to highlight class name instead.

0
Comment actions Permalink

thank.
Because selections can only be made in the currently visited file, I tried to search for all ENUM and select them if they are used in ModuleActivity.

But then you can not make a search for links to them. Looks like lint checks are not available ReferencesSearch

0
Comment actions Permalink

I don't know anything about Lint, but maybe com.android.tools.lint.detector.api.Scope.ALL_JAVA_FILES could help to run linter across multiple files.

1

Please sign in to leave a comment.