new find usages implementation

GitOrigin-RevId: e397953aef0bc2a5dafe0fc41bb85fb6866eff66
This commit is contained in:
adelf
2019-07-29 17:42:36 +03:00
committed by intellij-monorepo-bot
parent 20dd4b9155
commit 6f75e7b34d
22 changed files with 134 additions and 232 deletions

View File

@@ -21,7 +21,7 @@ sourceSets {
}
test {
java.srcDirs 'src/test/java'
//resources.srcDirs 'src/test/resources'
resources.srcDirs 'src/test/resources'
}
}
@@ -49,6 +49,7 @@ intellij {
patchPluginXml {
sinceBuild '191'
untilBuild '192.*'
}
group 'ru.adelf'

View File

@@ -6,11 +6,12 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.util.Processor;
import com.intellij.util.indexing.FileBasedIndex;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.indexing.DotEnvKeyValuesIndex;
import ru.adelf.idea.dotenv.indexing.DotEnvKeysIndex;
import ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex;
import ru.adelf.idea.dotenv.models.EnvironmentKeyValue;
import ru.adelf.idea.dotenv.util.EnvironmentVariablesProviderUtil;
import ru.adelf.idea.dotenv.util.EnvironmentVariablesUtil;
@@ -101,20 +102,18 @@ public class EnvironmentVariablesApi {
public static PsiElement[] getKeyUsages(Project project, String key) {
List<PsiElement> targets = new ArrayList<>();
FileBasedIndex.getInstance().getFilesWithKey(DotEnvUsagesIndex.KEY, new HashSet<>(Collections.singletonList(key)), virtualFile -> {
PsiFile psiFileTarget = PsiManager.getInstance(project).findFile(virtualFile);
if(psiFileTarget == null) {
return true;
}
PsiSearchHelper searchHelper = PsiSearchHelper.getInstance(project);
for(EnvironmentVariablesUsagesProvider provider : EnvironmentVariablesProviderUtil.USAGES_PROVIDERS) {
if(provider.acceptFile(virtualFile)) {
targets.addAll(EnvironmentVariablesUtil.getUsagesElementsByKey(key, provider.getUsages(psiFileTarget)));
}
Processor<PsiFile> psiFileProcessor = psiFile -> {
for (EnvironmentVariablesUsagesProvider provider : EnvironmentVariablesProviderUtil.USAGES_PROVIDERS) {
targets.addAll(EnvironmentVariablesUtil.getUsagesElementsByKey(key, provider.getUsages(psiFile)));
}
return true;
}, GlobalSearchScope.allScope(project));
};
searchHelper.processAllFilesWithWord(key, GlobalSearchScope.allScope(project), psiFileProcessor, true);
searchHelper.processAllFilesWithWordInLiterals(key, GlobalSearchScope.allScope(project), psiFileProcessor);
return targets.toArray(PsiElement.EMPTY_ARRAY);
}

View File

@@ -18,7 +18,6 @@ public class DockerComposeKeyGotoHandler implements GotoDeclarationHandler {
@Nullable
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement psiElement, int i, Editor editor) {
if(psiElement == null) {
return PsiElement.EMPTY_ARRAY;
}

View File

@@ -14,7 +14,6 @@ public class DotEnvKeyGotoHandler implements GotoDeclarationHandler {
@Nullable
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement psiElement, int i, Editor editor) {
if(psiElement == null || psiElement.getParent() == null) {
return PsiElement.EMPTY_ARRAY;
}

View File

@@ -0,0 +1,37 @@
package ru.adelf.idea.dotenv.go;
import com.goide.psi.GoCallExpr;
import com.goide.psi.GoStringLiteral;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
import java.util.Collection;
import java.util.HashSet;
class GoEnvironmentCallsVisitor extends PsiRecursiveElementWalkingVisitor {
final private Collection<KeyUsagePsiElement> collectedItems = new HashSet<>();
@Override
public void visitElement(PsiElement element) {
if(element instanceof GoCallExpr) {
this.visitCall((GoCallExpr) element);
}
super.visitElement(element);
}
private void visitCall(GoCallExpr expression) {
GoStringLiteral stringLiteral = GoPsiHelper.getEnvironmentGoLiteral(expression);
if(stringLiteral != null) {
collectedItems.add(new KeyUsagePsiElement(stringLiteral.getDecodedText(), stringLiteral));
}
}
@NotNull
Collection<KeyUsagePsiElement> getCollectedItems() {
return collectedItems;
}
}

View File

@@ -0,0 +1,32 @@
package ru.adelf.idea.dotenv.go;
import com.goide.GoFileType;
import com.goide.psi.GoFile;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.api.EnvironmentVariablesUsagesProvider;
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
import java.util.Collection;
import java.util.Collections;
public class GoEnvironmentVariablesUsagesProvider implements EnvironmentVariablesUsagesProvider {
@Override
public boolean acceptFile(VirtualFile file) {
return file.getFileType().equals(GoFileType.INSTANCE);
}
@NotNull
@Override
public Collection<KeyUsagePsiElement> getUsages(PsiFile psiFile) {
if(psiFile instanceof GoFile) {
GoEnvironmentCallsVisitor visitor = new GoEnvironmentCallsVisitor();
psiFile.acceptChildren(visitor);
return visitor.getCollectedItems();
}
return Collections.emptyList();
}
}

View File

@@ -1,76 +0,0 @@
package ru.adelf.idea.dotenv.indexing;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.VoidDataExternalizer;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.api.EnvironmentVariablesUsagesProvider;
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
import ru.adelf.idea.dotenv.util.EnvironmentVariablesProviderUtil;
import java.util.HashMap;
import java.util.Map;
public class DotEnvUsagesIndex extends FileBasedIndexExtension<String, Void> {
public static final ID<String, Void> KEY = ID.create("ru.adelf.idea.php.dotenv.usages");
private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor();
@NotNull
@Override
public ID<String, Void> getName() {
return KEY;
}
@NotNull
@Override
public DataIndexer<String, Void, FileContent> getIndexer() {
return fileContent -> {
final Map<String, Void> map = new HashMap<>();
for(EnvironmentVariablesUsagesProvider provider : EnvironmentVariablesProviderUtil.USAGES_PROVIDERS) {
for(KeyUsagePsiElement keyUsagePsiElement : provider.getUsages(fileContent.getPsiFile())) {
map.put(keyUsagePsiElement.getKey(), null);
}
}
return map;
};
}
@NotNull
@Override
public KeyDescriptor<String> getKeyDescriptor() {
return this.myKeyDescriptor;
}
@NotNull
@Override
public DataExternalizer<Void> getValueExternalizer() {
return VoidDataExternalizer.INSTANCE;
}
@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return file -> {
for(EnvironmentVariablesUsagesProvider provider : EnvironmentVariablesProviderUtil.USAGES_PROVIDERS) {
if(provider.acceptFile(file)) return true;
}
return false;
};
}
@Override
public boolean dependsOnFileContent() {
return true;
}
@Override
public int getVersion() {
return 2;
}
}

View File

@@ -1,32 +0,0 @@
package ru.adelf.idea.dotenv.js;
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.extension.DotEnvReference;
public class JsEnvReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(JSReferenceExpression.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext context) {
JSReferenceExpression reference = (JSReferenceExpression) element;
if (!reference.getCanonicalText().startsWith("process.env.")) {
return PsiReference.EMPTY_ARRAY;
}
String value = reference.getCanonicalText();
return new PsiReference[]{new DotEnvReference(element, new TextRange(0, value.length()), value.substring(12))};
}
});
}
}

View File

@@ -1,32 +0,0 @@
package ru.adelf.idea.dotenv.php;
import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.PlatformPatterns;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.extension.DotEnvReference;
public class PhpEnvReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(StringLiteralExpression.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext context) {
StringLiteralExpression literal = (StringLiteralExpression) element;
if (!PhpPsiHelper.isEnvFunctionParameter(literal)) {
return PsiReference.EMPTY_ARRAY;
}
String value = literal.getContents();
return new PsiReference[]{new DotEnvReference(element, new TextRange(1, value.length() + 1))};
}
});
}
}

View File

@@ -1,54 +0,0 @@
package ru.adelf.idea.dotenv.ruby;
import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.ruby.ruby.lang.psi.basicTypes.stringLiterals.RStringLiteral;
import org.jetbrains.plugins.ruby.ruby.lang.psi.expressions.RArrayIndexing;
import org.jetbrains.plugins.ruby.ruby.lang.psi.variables.RConstant;
import ru.adelf.idea.dotenv.extension.DotEnvReference;
import java.util.Objects;
public class RubyEnvReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(RStringLiteral.class),
new PsiReferenceProvider() {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull ProcessingContext context) {
RStringLiteral literal = (RStringLiteral) element;
if (literal.getParent() == null) {
return PsiReference.EMPTY_ARRAY;
}
PsiElement array = literal.getParent().getParent();
if (!(array instanceof RArrayIndexing)) {
return PsiReference.EMPTY_ARRAY;
}
PsiElement receiver = ((RArrayIndexing) array).getReceiver();
if (!(receiver instanceof RConstant)) {
return PsiReference.EMPTY_ARRAY;
}
if (receiver.getFirstChild() == null) {
return PsiReference.EMPTY_ARRAY;
}
if (!Objects.equals(receiver.getFirstChild().getText(), "ENV")) {
return PsiReference.EMPTY_ARRAY;
}
return new PsiReference[]{new DotEnvReference(literal, new TextRange(1, literal.getTextLength() + 1))};
}
});
}
}

View File

@@ -3,4 +3,8 @@
<completion.contributor language="go" implementationClass="ru.adelf.idea.dotenv.go.GoEnvCompletionProvider"/>
<gotoDeclarationHandler implementation="ru.adelf.idea.dotenv.go.GoEnvCompletionProvider"/>
</extensions>
<extensions defaultExtensionNs="ru.adelf.idea.dotenv">
<environmentVariablesUsagesProvider implementation="ru.adelf.idea.dotenv.go.GoEnvironmentVariablesUsagesProvider"/>
</extensions>
</idea-plugin>

View File

@@ -2,7 +2,6 @@
<extensions defaultExtensionNs="com.intellij">
<completion.contributor language="JavaScript" implementationClass="ru.adelf.idea.dotenv.js.JsEnvCompletionProvider"/>
<gotoDeclarationHandler implementation="ru.adelf.idea.dotenv.js.JsEnvCompletionProvider"/>
<psi.referenceContributor implementation="ru.adelf.idea.dotenv.js.JsEnvReferenceContributor"/>
</extensions>
<extensions defaultExtensionNs="ru.adelf.idea.dotenv">

View File

@@ -2,11 +2,9 @@
<extensions defaultExtensionNs="com.intellij">
<completion.contributor language="PHP" implementationClass="ru.adelf.idea.dotenv.php.PhpEnvCompletionContributor"/>
<gotoDeclarationHandler implementation="ru.adelf.idea.dotenv.php.PhpEnvCompletionContributor"/>
<psi.referenceContributor implementation="ru.adelf.idea.dotenv.php.PhpEnvReferenceContributor"/>
</extensions>
<extensions defaultExtensionNs="ru.adelf.idea.dotenv">
<environmentVariablesUsagesProvider
implementation="ru.adelf.idea.dotenv.php.PhpEnvironmentVariablesUsagesProvider"/>
<environmentVariablesUsagesProvider implementation="ru.adelf.idea.dotenv.php.PhpEnvironmentVariablesUsagesProvider"/>
</extensions>
</idea-plugin>

View File

@@ -12,21 +12,19 @@
<li>Environment variables completion for PHP, JavaScript, Python, Go and Ruby languages</li>
<li>Dockerfile and docker-compose.yml files support.</li>
<li>Go to declaration(in .env file) and usages(in code), by Ctrl(Cmd)+click or hot key(Ctrl(Cmd)-B, etc.)</li>
<li>.env file commenter</li>
<li>.env file syntax highlighter</li>
</ul>
]]></description>
<change-notes><![CDATA[
0.7
0.8
<ul>
<li>.env syntax highlighting</li>
<li>Go support</li>
<li>.env.* files support</li>
<li>Javascript indexing optimization(remove /node_modules from index)</li>
<li>Improved performance by removing additional indexing</li>
<li>.env syntax fix</li>
</ul>
]]></change-notes>
<idea-version since-build="191"/>
<idea-version since-build="191" until-build="192.*"/>
<extensionPoints>
<extensionPoint qualifiedName="ru.adelf.idea.dotenv.environmentVariablesProvider" interface="ru.adelf.idea.dotenv.api.EnvironmentVariablesProvider"/>
@@ -49,14 +47,10 @@
<fileBasedIndex implementation="ru.adelf.idea.dotenv.indexing.DotEnvKeysIndex"/>
<fileBasedIndex implementation="ru.adelf.idea.dotenv.indexing.DotEnvKeyValuesIndex"/>
<fileBasedIndex implementation="ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex"/>
<fileTypeFactory implementation="ru.adelf.idea.dotenv.DotEnvFileTypeFactory"/>
<lang.parserDefinition language="DotEnv" implementationClass="ru.adelf.idea.dotenv.DotEnvParserDefinition"/>
<lang.commenter language="DotEnv" implementationClass="ru.adelf.idea.dotenv.extension.DotEnvCommenter"/>
<!--<lang.refactoringSupport language="DotEnv" implementationClass="ru.adelf.idea.dotenv.extension.DotEnvRefactoringSupportProvider"/>
<lang.findUsagesProvider language="DotEnv" implementationClass="ru.adelf.idea.dotenv.extension.DotEnvFindUsagesProvider"/>
<referencesSearch implementation="ru.adelf.idea.dotenv.extension.DotEnvReferencesSearcher"/>-->
<localInspection language="DotEnv"
groupName="DotEnv"

View File

@@ -2,7 +2,6 @@
<extensions defaultExtensionNs="com.intellij">
<completion.contributor language="ruby" implementationClass="ru.adelf.idea.dotenv.ruby.RubyEnvCompletionProvider"/>
<gotoDeclarationHandler implementation="ru.adelf.idea.dotenv.ruby.RubyEnvCompletionProvider"/>
<psi.referenceContributor implementation="ru.adelf.idea.dotenv.ruby.RubyEnvReferenceContributor"/>
</extensions>
<extensions defaultExtensionNs="ru.adelf.idea.dotenv">

View File

@@ -1,11 +1,13 @@
package ru.adelf.idea.dotenv.tests;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.indexing.ID;
import org.jetbrains.annotations.NotNull;
import ru.adelf.idea.dotenv.api.EnvironmentVariablesApi;
import java.util.ArrayList;
import java.util.Collection;
@@ -43,4 +45,13 @@ public abstract class DotEnvLightCodeInsightFixtureTestCase extends LightCodeIns
}
}
}
protected void assertUsagesContains(@NotNull String... keys) {
for (String key : keys) {
PsiElement[] usages = EnvironmentVariablesApi.getKeyUsages(this.myFixture.getProject(), key);
if(usages.length == 0) {
fail(String.format("Fail that usages contains '%s'", key));
}
}
}
}

View File

@@ -0,0 +1,20 @@
package ru.adelf.idea.dotenv.tests.usages;
import ru.adelf.idea.dotenv.tests.DotEnvLightCodeInsightFixtureTestCase;
public class GoUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("usages.go"));
}
protected String getTestDataPath() {
return basePath + "usages/fixtures";
}
public void testUsages() {
assertUsagesContains("GO_TEST", "GO_TEST2");
}
}

View File

@@ -1,6 +1,5 @@
package ru.adelf.idea.dotenv.tests.usages;
import ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex;
import ru.adelf.idea.dotenv.tests.DotEnvLightCodeInsightFixtureTestCase;
public class JsUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
@@ -16,6 +15,6 @@ public class JsUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
}
public void testUsages() {
assertIndexContains(DotEnvUsagesIndex.KEY,"JS_TEST");
assertUsagesContains("JS_TEST");
}
}

View File

@@ -1,6 +1,5 @@
package ru.adelf.idea.dotenv.tests.usages;
import ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex;
import ru.adelf.idea.dotenv.tests.DotEnvLightCodeInsightFixtureTestCase;
public class PhpUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
@@ -16,6 +15,6 @@ public class PhpUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
}
public void testUsages() {
assertIndexContains(DotEnvUsagesIndex.KEY,"PHP_TEST", "PHP_TEST2");
assertUsagesContains("PHP_TEST", "PHP_TEST2");
}
}

View File

@@ -1,6 +1,5 @@
package ru.adelf.idea.dotenv.tests.usages;
import ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex;
import ru.adelf.idea.dotenv.tests.DotEnvLightCodeInsightFixtureTestCase;
public class PythonUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
@@ -16,6 +15,6 @@ public class PythonUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
}
public void testUsages() {
assertIndexContains(DotEnvUsagesIndex.KEY,"PYTHON_TEST", "PYTHON_TEST2");
assertUsagesContains("PYTHON_TEST", "PYTHON_TEST2");
}
}

View File

@@ -1,6 +1,5 @@
package ru.adelf.idea.dotenv.tests.usages;
import ru.adelf.idea.dotenv.indexing.DotEnvUsagesIndex;
import ru.adelf.idea.dotenv.tests.DotEnvLightCodeInsightFixtureTestCase;
public class RubyUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
@@ -16,6 +15,6 @@ public class RubyUsagesTest extends DotEnvLightCodeInsightFixtureTestCase {
}
public void testUsages() {
assertIndexContains(DotEnvUsagesIndex.KEY,"RUBY_TEST");
assertUsagesContains("RUBY_TEST");
}
}

View File

@@ -0,0 +1,8 @@
package fixtures
import "os"
func main() {
os.Getenv("GO_TEST")
os.Setenv("GO_TEST2", "1")
}