InjectionCache: don't load AST, search in non-Java files as well

This commit is contained in:
peter
2016-08-26 08:07:50 +02:00
parent c4b6edecce
commit 4a2aef477e
5 changed files with 66 additions and 60 deletions
@@ -64,7 +64,7 @@ public class AnnotatedElementsSearcher implements QueryExecutor<PsiModifierListO
final PsiModifierListOwner candidate = ApplicationManager.getApplication().runReadAction(new Computable<PsiModifierListOwner>() {
@Override
public PsiModifierListOwner compute() {
PsiElement parent = ann.getParent();
PsiElement parent = ann.getContext();
if (!(parent instanceof PsiModifierList)) {
return null; // Can be a PsiNameValuePair, if annotation is used to annotate annotation parameters
}
@@ -18,11 +18,13 @@ package com.intellij.psi
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer
import com.intellij.psi.impl.source.PsiClassImpl
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.AnnotatedElementsSearch
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
class JavaStubsTest extends LightCodeInsightFixtureTestCase {
public void "test resolve from annotation method default"() {
void "test resolve from annotation method default"() {
def cls = myFixture.addClass("""
public @interface BrokenAnnotation {
enum Foo {DEFAULT, OTHER}
@@ -41,7 +43,7 @@ class JavaStubsTest extends LightCodeInsightFixtureTestCase {
assert file.stub
}
public void "test literal annotation value"() {
void "test literal annotation value"() {
def cls = myFixture.addClass("""
class Foo {
@org.jetbrains.annotations.Contract(pure=true)
@@ -55,7 +57,23 @@ class JavaStubsTest extends LightCodeInsightFixtureTestCase {
assert !file.contentsLoaded
}
public void "test applying type annotations"() {
void "test local variable annotation doesn't cause stub-ast switch"() {
def cls = myFixture.addClass("""
class Foo {
@Anno int foo() {
@Anno int var = 2;
}
}
@interface Anno {}
""")
def file = cls.containingFile as PsiFileImpl
assert AnnotatedElementsSearch.searchPsiMethods(myFixture.findClass("Anno"), GlobalSearchScope.allScope(project)).size() == 1
assert file.stub
assert !file.contentsLoaded
}
void "test applying type annotations"() {
def cls = myFixture.addClass("""
import java.lang.annotation.*;
class Foo {
@@ -31,7 +31,6 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import gnu.trove.THashSet;
import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
@@ -97,6 +96,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
@Override
protected boolean areThereInjectionsWithName(String methodName, boolean annoOnly) {
if (methodName == null) return false;
if (getAnnotatedElementsValue().contains(methodName)) {
return true;
}
@@ -206,7 +206,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
if (anchor != null && !processCommentInjection(anchor)) {
myShouldStop = true;
}
else if (areThereInjectionsWithName(variable.getName(), false)) {
else {
process(variable, null, -1);
}
return false;
@@ -287,16 +287,12 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
}
private boolean processAnnotationInjections(final PsiModifierListOwner annoElement) {
final String checkName;
if (annoElement instanceof PsiParameter) {
final PsiElement scope = ((PsiParameter)annoElement).getDeclarationScope();
checkName = scope instanceof PsiMethod ? ((PsiNamedElement)scope).getName() : ((PsiNamedElement)annoElement).getName();
if (scope instanceof PsiMethod && !areThereInjectionsWithName(((PsiNamedElement)scope).getName(), true)) {
return true;
}
}
else if (annoElement instanceof PsiNamedElement) {
checkName = ((PsiNamedElement)annoElement).getName();
}
else checkName = null;
if (checkName == null || !areThereInjectionsWithName(checkName, true)) return true;
final PsiAnnotation[] annotations =
AnnotationUtilEx.getAnnotationFrom(annoElement, myConfiguration.getAdvancedConfiguration().getLanguageAnnotationPair(), true);
if (annotations.length > 0) {
@@ -17,11 +17,10 @@ package org.intellij.plugins.intelliLang.inject.java;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
@@ -33,21 +32,20 @@ import gnu.trove.THashSet;
import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Created by Max Medvedev on 22/03/14
*/
public class InjectionCache {
private final CachedValue<Collection<String>> myAnnoIndex;
private final CachedValue<Set<String>> myAnnoIndex;
private final CachedValue<Collection<String>> myXmlIndex;
private final Project myProject;
public InjectionCache(final Project project, final Configuration configuration) {
myProject = project;
myXmlIndex = CachedValuesManager.getManager(project).createCachedValue(() -> {
final Map<ElementPattern<?>, BaseInjection> map = new THashMap<>();
for (BaseInjection injection : configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID)) {
@@ -61,45 +59,42 @@ public class InjectionCache {
}, false);
myAnnoIndex = CachedValuesManager.getManager(project).createCachedValue(() -> {
final String annotationClass = configuration.getAdvancedConfiguration().getLanguageAnnotationClass();
final Collection<String> result = new THashSet<>();
final ArrayList<String> annoClasses = new ArrayList<>(3);
annoClasses.add(StringUtil.getShortName(annotationClass));
for (int cursor = 0; cursor < annoClasses.size(); cursor++) {
final String annoClass = annoClasses.get(cursor);
for (PsiAnnotation annotation : JavaAnnotationIndex.getInstance().get(annoClass, project, GlobalSearchScope.allScope(project))) {
final PsiElement modList = annotation.getParent();
if (!(modList instanceof PsiModifierList)) continue;
final PsiElement element = modList.getParent();
if (element instanceof PsiParameter) {
final PsiElement scope = ((PsiParameter)element).getDeclarationScope();
if (scope instanceof PsiNamedElement) {
ContainerUtil.addIfNotNull(result, ((PsiNamedElement)scope).getName());
}
else {
ContainerUtil.addIfNotNull(result, ((PsiNamedElement)element).getName());
}
}
else if (element instanceof PsiNamedElement) {
if (element instanceof PsiClass && ((PsiClass)element).isAnnotationType()) {
final String s = ((PsiClass)element).getName();
if (!annoClasses.contains(s)) annoClasses.add(s);
}
else {
ContainerUtil.addIfNotNull(result, ((PsiNamedElement)element).getName());
}
}
}
}
Set<String> result = collectMethodNamesWithLanguage(
configuration.getAdvancedConfiguration().getLanguageAnnotationClass());
return new CachedValueProvider.Result<>(result, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, configuration);
}, false);
}
@NotNull
private Set<String> collectMethodNamesWithLanguage(String annotationClassName) {
GlobalSearchScope allScope = GlobalSearchScope.allScope(myProject);
Set<String> result = new THashSet<>();
ArrayList<PsiClass> annoClasses = ContainerUtil.newArrayList(JavaPsiFacade.getInstance(myProject).findClasses(annotationClassName, allScope));
for (int cursor = 0; cursor < annoClasses.size(); cursor++) {
AnnotatedElementsSearch.searchElements(annoClasses.get(cursor), allScope, PsiClass.class, PsiParameter.class, PsiMethod.class).forEach(element -> {
if (element instanceof PsiParameter) {
final PsiElement scope = ((PsiParameter)element).getDeclarationScope();
if (scope instanceof PsiMethod) {
ContainerUtil.addIfNotNull(result, ((PsiMethod)scope).getName());
}
}
else if (element instanceof PsiClass && ((PsiClass)element).isAnnotationType() && !annoClasses.contains(element)) {
annoClasses.add((PsiClass)element);
}
else if (element instanceof PsiMethod) {
ContainerUtil.addIfNotNull(result, element.getName());
}
return true;
});
}
return result;
}
public static InjectionCache getInstance(Project project) {
return ServiceManager.getService(project, InjectionCache.class);
}
public Collection<String> getAnnoIndex() {
public Set<String> getAnnoIndex() {
return myAnnoIndex.getValue();
}
@@ -93,6 +93,7 @@ public class GrConcatenationAwareInjector implements ConcatenationAwareInjector
@Override
protected boolean areThereInjectionsWithName(String methodName, boolean annoOnly) {
if (methodName == null) return false;
if (getAnnotatedElementsValue().contains(methodName)) {
return true;
}
@@ -201,7 +202,7 @@ public class GrConcatenationAwareInjector implements ConcatenationAwareInjector
if (!processCommentInjections(variable)) {
myShouldStop = true;
}
else if (areThereInjectionsWithName(variable.getName(), false)) {
else {
process(variable, null, -1);
}
return false;
@@ -266,16 +267,12 @@ public class GrConcatenationAwareInjector implements ConcatenationAwareInjector
}
private boolean processAnnotationInjections(final PsiModifierListOwner annoElement) {
final String checkName;
if (annoElement instanceof PsiParameter) {
final PsiElement scope = ((PsiParameter)annoElement).getDeclarationScope();
checkName = scope instanceof PsiMethod ? ((PsiNamedElement)scope).getName() : ((PsiNamedElement)annoElement).getName();
if (scope instanceof PsiMethod && !areThereInjectionsWithName(((PsiNamedElement)scope).getName(), true)) {
return true;
}
}
else if (annoElement instanceof PsiNamedElement) {
checkName = ((PsiNamedElement)annoElement).getName();
}
else checkName = null;
if (checkName == null || !areThereInjectionsWithName(checkName, true)) return true;
final PsiAnnotation[] annotations =
GrConcatenationInjector.getAnnotationFrom(annoElement, myConfiguration.getAdvancedConfiguration().getLanguageAnnotationPair(), true, true);
if (annotations.length > 0) {