From 2bcf6510fa36e62f9ecff1019a72fc3497beacf5 Mon Sep 17 00:00:00 2001 From: greg Date: Fri, 8 May 2009 15:47:47 +0400 Subject: [PATCH] un-inject language action in Java fix inject language action in annotation values fix --- .../plugins/intelliLang/Configuration.java | 36 ++++++++- .../intelliLang/inject/ConcatenationInjector.java | 85 ++++++++++++---------- .../intelliLang/inject/CustomLanguageInjector.java | 19 +++-- .../intelliLang/inject/InjectLanguageAction.java | 19 ++++- .../intelliLang/inject/UnInjectLanguageAction.java | 64 +++++++++++----- 5 files changed, 154 insertions(+), 69 deletions(-) diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java index 9633c02f28..bdbf6c3560 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java @@ -32,10 +32,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; /** * Configuration that holds configured xml tag, attribute and method parameter @@ -354,4 +351,35 @@ public final class Configuration implements PersistentStateComponent { public InstrumentationType getInstrumentation() { return myInstrumentationType; } + + private long myCacheModificationCount; + private MultiValuesMap, MethodParameterInjection> myMethodCache; + + private MultiValuesMap, MethodParameterInjection> getMethodCache() { + if (myMethodCache != null && getModificationCount() == myCacheModificationCount) { + return myMethodCache; + } + myCacheModificationCount = getModificationCount(); + final MultiValuesMap, MethodParameterInjection> tmpMap = + new MultiValuesMap, MethodParameterInjection>(); + for (MethodParameterInjection injection : getParameterInjections()) { + for (MethodParameterInjection.MethodInfo info : injection.getMethodInfos()) { + final boolean[] flags = info.getParamFlags(); + for (int i = 0; i < flags.length; i++) { + if (!flags[i]) continue; + tmpMap.put(Trinity.create(info.getMethodName(), flags.length, i), injection); + } + if (info.isReturnFlag()) { + tmpMap.put(Trinity.create(info.getMethodName(), 0, -1), injection); + } + } + } + myMethodCache = tmpMap; + return tmpMap; + } + + public Collection getPossibleCachedInjections(final Trinity key) { + final Collection list = getMethodCache().get(key); + return list == null? Collections.emptyList() : list; + } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/ConcatenationInjector.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/ConcatenationInjector.java index e6c04b47fb..9734156679 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/ConcatenationInjector.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/ConcatenationInjector.java @@ -3,7 +3,6 @@ package org.intellij.plugins.intelliLang.inject; import com.intellij.lang.Language; import com.intellij.lang.injection.ConcatenationAwareInjector; import com.intellij.lang.injection.MultiHostRegistrar; -import com.intellij.openapi.util.MultiValuesMap; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; @@ -15,6 +14,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.PairProcessor; +import com.intellij.util.Processor; import gnu.trove.THashSet; import org.intellij.plugins.intelliLang.Configuration; import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; @@ -29,8 +29,6 @@ import java.util.*; */ public class ConcatenationInjector implements ConcatenationAwareInjector { private final Configuration myInjectionConfiguration; - private long myConfigurationModificationCount; - private MultiValuesMap, MethodParameterInjection> myMethodCache; public ConcatenationInjector(Configuration configuration) { myInjectionConfiguration = configuration; @@ -63,8 +61,44 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { } return false; } + private void processLiteralExpressionInjections(final PairProcessor>> processor, final PsiElement... operands) { + processLiteralExpressionInjectionsInner(myInjectionConfiguration, new Processor() { + public boolean process(final Info info) { + if (processAnnotationInjections(info.owner, processor, operands)) return false; // annotated element + for (MethodParameterInjection injection : info.injections) { + if (injection.isApplicable(info.method)) { + processInjectionWithContext(info.unparsable, injection, processor, operands); + if (injection.isTerminal()) { + return false; + } + } + } + return true; + } + }, operands); + } + + public static class Info { + PsiModifierListOwner owner; + PsiMethod method; + Collection injections; + boolean unparsable; + + public Info(final PsiModifierListOwner owner, + final PsiMethod method, + final Collection injections, + final boolean unparsable) { + this.owner = owner; + this.method = method; + this.injections = injections; + this.unparsable = unparsable; + } + } + + public static void processLiteralExpressionInjectionsInner(final Configuration configuration, final Processor processor, + final PsiElement... operands) { if (operands.length == 0) return; final PsiElement firstOperand = operands[0]; final PsiElement topBlock = PsiUtil.getTopLevelEnclosingCodeBlock(firstOperand, null); @@ -78,7 +112,6 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { final PsiElement curPlace = places.removeFirst(); final PsiModifierListOwner owner = AnnotationUtilEx.getAnnotatedElementFor(curPlace, AnnotationUtilEx.LookupType.PREFER_CONTEXT); if (owner == null) continue; - if (processAnnotationInjections(owner, processor, operands)) return; // annotated element final PsiMethod psiMethod; final Trinity trin; @@ -94,7 +127,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { psiMethod = (PsiMethod)owner; trin = Trinity.create(psiMethod.getName(), psiMethod.getParameterList().getParametersCount(), -1); } - else if (myInjectionConfiguration.isResolveReferences() && + else if (configuration.isResolveReferences() && owner instanceof PsiVariable && visitedVars.add(owner)) { final PsiVariable variable = (PsiVariable)owner; for (PsiReference psiReference : ReferencesSearch.search(variable, searchScope).findAll()) { @@ -107,21 +140,17 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { } } } - continue; + trin = null; + psiMethod = null; } else { - continue; - } - final Collection injections = getMethodCache().get(trin); - if (injections == null) return; - for (MethodParameterInjection injection : injections) { - if (injection.isApplicable(psiMethod)) { - processInjectionWithContext(unparsable, injection, processor, operands); - if (injection.isTerminal()) { - return; - } - } + trin = null; + psiMethod = null; } + final Collection injections = + trin == null? Collections.emptyList() : configuration.getPossibleCachedInjections(trin); + final Info info = new Info(owner, psiMethod, injections, unparsable); + if (!processor.process(info)) return; } } @@ -202,26 +231,4 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { } return false; } - private MultiValuesMap, MethodParameterInjection> getMethodCache() { - if (myMethodCache != null && myInjectionConfiguration.getModificationCount() == myConfigurationModificationCount) { - return myMethodCache; - } - myConfigurationModificationCount = myInjectionConfiguration.getModificationCount(); - final MultiValuesMap, MethodParameterInjection> tmpMap = - new MultiValuesMap, MethodParameterInjection>(); - for (MethodParameterInjection injection : myInjectionConfiguration.getParameterInjections()) { - for (MethodParameterInjection.MethodInfo info : injection.getMethodInfos()) { - final boolean[] flags = info.getParamFlags(); - for (int i = 0; i < flags.length; i++) { - if (!flags[i]) continue; - tmpMap.put(Trinity.create(info.getMethodName(), flags.length, i), injection); - } - if (info.isReturnFlag()) { - tmpMap.put(Trinity.create(info.getMethodName(), 0, -1), injection); - } - } - } - myMethodCache = tmpMap; - return tmpMap; - } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/CustomLanguageInjector.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/CustomLanguageInjector.java index f34cd7ade6..df065c0728 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/CustomLanguageInjector.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/CustomLanguageInjector.java @@ -30,12 +30,13 @@ import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.xml.*; import com.intellij.util.PairProcessor; +import com.intellij.util.containers.ContainerUtil; import com.intellij.xml.util.XmlUtil; import gnu.trove.THashSet; import org.intellij.plugins.intelliLang.Configuration; -import org.intellij.plugins.intelliLang.util.PsiUtilEx; import org.intellij.plugins.intelliLang.inject.config.XmlAttributeInjection; import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection; +import org.intellij.plugins.intelliLang.util.PsiUtilEx; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -85,14 +86,16 @@ public final class CustomLanguageInjector implements ProjectComponent { // optimization if (place instanceof PsiLiteralExpression && !PsiUtilEx.isStringOrCharacterLiteral(place)) return; - for (Iterator, InjectedLanguage>> it = myTempPlaces.iterator(); it.hasNext();) { - final Pair, InjectedLanguage> pair = it.next(); - final PsiLanguageInjectionHost element = pair.first.getElement(); - if (element == null) { - it.remove(); + myTempPlaces.removeAll(ContainerUtil.findAll(myTempPlaces, new Condition, InjectedLanguage>>() { + public boolean value(final Pair, InjectedLanguage> pair) { + return pair.first.getElement() == null; } - else if (element == place) { - processor.process(pair.second.getLanguage(), Collections.singletonList(Trinity.create(element, pair.second, ElementManipulators.getManipulator(element).getRangeInElement(element)))); + })); + for (final Pair, InjectedLanguage> pair : myTempPlaces) { + if (pair.first.getElement() == place) { + final PsiLanguageInjectionHost host = (PsiLanguageInjectionHost)place; + processor.process(pair.second.getLanguage(), Collections.singletonList( + Trinity.create(host, pair.second, ElementManipulators.getManipulator(host).getRangeInElement(host)))); return; } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java index fe1ba2369c..16031d97b3 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java @@ -133,7 +133,9 @@ public class InjectLanguageAction implements IntentionAction { if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != target) continue; break; } - if (parent instanceof PsiReturnStatement || parent instanceof PsiMethod) { + if (parent instanceof PsiReturnStatement || + parent instanceof PsiMethod || + parent instanceof PsiNameValuePair) { return doInjectInJavaMethod(project, findPsiMethod(parent), -1, languageId); } else if (parent instanceof PsiExpressionList && parent.getParent() instanceof PsiMethodCallExpression) { @@ -210,6 +212,21 @@ public class InjectLanguageAction implements IntentionAction { @Nullable private static PsiMethod findPsiMethod(final PsiElement parent) { + if (parent instanceof PsiNameValuePair) { + final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(parent, PsiAnnotation.class); + if (annotation != null) { + final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement(); + if (referenceElement != null) { + PsiElement resolved = referenceElement.resolve(); + if (resolved != null) { + PsiMethod[] methods = ((PsiClass)resolved).findMethodsByName(((PsiNameValuePair)parent).getName(), false); + if (methods.length == 1) { + return methods[0]; + } + } + } + } + } final PsiMethod first; if (parent.getParent() instanceof PsiMethodCallExpression) { first = ((PsiMethodCallExpression)parent.getParent()).resolveMethod(); diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java index c928484de3..26d3918456 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java @@ -1,27 +1,27 @@ package org.intellij.plugins.intelliLang.inject; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiLanguageInjectionHost; -import com.intellij.psi.PsiMethod; +import com.intellij.psi.*; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlTag; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.FileContentUtil; -import org.jetbrains.annotations.NotNull; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NullableFunction; +import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import org.intellij.plugins.intelliLang.Configuration; +import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; import org.intellij.plugins.intelliLang.inject.config.XmlAttributeInjection; import org.intellij.plugins.intelliLang.inject.config.XmlTagInjection; -import org.intellij.plugins.intelliLang.inject.config.MethodParameterInjection; +import org.intellij.plugins.intelliLang.util.AnnotationUtilEx; +import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.Iterator; -import java.util.Collections; +import java.util.*; /** * @author Dmitry Avdeev @@ -44,7 +44,7 @@ public class UnInjectLanguageAction extends InjectLanguageAction { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { PsiLanguageInjectionHost host = findInjectionHost(editor, file); - Configuration configuration = Configuration.getInstance(); + final Configuration configuration = Configuration.getInstance(); if (host instanceof XmlAttributeValue) { for (Iterator it = configuration.getAttributeInjections().iterator(); it.hasNext();) { XmlAttributeInjection injection = it.next(); @@ -61,13 +61,43 @@ public class UnInjectLanguageAction extends InjectLanguageAction { break; } } - } else if (host instanceof PsiMethod) { - for (Iterator it = configuration.getParameterInjections().iterator(); it.hasNext();) { - MethodParameterInjection injection = it.next(); - if (injection.isApplicable((PsiMethod)host)) { - it.remove(); - break; + } else if (host instanceof PsiLiteralExpression) { + final ArrayList annotationsToRemove = new ArrayList(); + final ArrayList injectionsToRemove = new ArrayList(); + ConcatenationInjector.processLiteralExpressionInjectionsInner(configuration, new Processor() { + public boolean process(final ConcatenationInjector.Info info) { + final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(info.owner, configuration.getLanguageAnnotationPair(), true); + annotationsToRemove.addAll(Arrays.asList(annotations)); + for (MethodParameterInjection injection : info.injections) { + if (injection.isApplicable(info.method)) { + injectionsToRemove.add(injection); + } + } + return true; } + }, host); + if (!injectionsToRemove.isEmpty()) { + new WriteCommandAction.Simple(project) { + public void run() { + for (MethodParameterInjection injection : injectionsToRemove) { + configuration.getParameterInjections().remove(injection); + } + } + }.execute(); + } + if (!annotationsToRemove.isEmpty()) { + final List psiFiles = ContainerUtil.mapNotNull(annotationsToRemove, new NullableFunction() { + public PsiFile fun(final PsiAnnotation psiAnnotation) { + return psiAnnotation instanceof PsiCompiledElement ? null : psiAnnotation.getContainingFile(); + } + }); + new WriteCommandAction.Simple(project, psiFiles.toArray(new PsiFile[psiFiles.size()])) { + protected void run() throws Throwable { + for (PsiAnnotation annotation : annotationsToRemove) { + annotation.delete(); + } + } + }.execute(); } } configuration.configurationModified(); -- 2.11.4.GIT