improve generic injection editor (groovy completion) cidr/96.311 idea/96.312 pycharm/96.313
authorGregory Shrago <Gregory.Shrago@jetbrains.com>
Mon, 31 May 2010 23:05:23 +0000 (03:05 +0400)
committerGregory Shrago <Gregory.Shrago@jetbrains.com>
Mon, 31 May 2010 23:09:51 +0000 (03:09 +0400)
plugins/IntelliLang/src/org/intellij/plugins/intelliLang/PatternBasedInjectionHelper.java
plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java
plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java
plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.form
plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.java
plugins/groovy/src/META-INF/intellilang-groovy-support.xml
plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java [new file with mode: 0644]

index 3d98cc71245ab996cdf72cd81e329f70094ded7f..9f586594b3a27ac53444ca63de9715eb86e79063 100644 (file)
@@ -25,15 +25,12 @@ import com.intellij.util.Function;
 import com.intellij.util.ReflectionCache;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.Stack;
+import gnu.trove.THashMap;
 import gnu.trove.THashSet;
 import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
-import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.Nullable;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
+import java.lang.reflect.*;
 import java.util.*;
 
 /**
@@ -123,9 +120,23 @@ public class PatternBasedInjectionHelper {
     }
   }
 
-  public static ElementPattern<PsiElement> compileElementPattern(final String text, final String supportId) {  
+  public static ElementPattern<PsiElement> compileElementPattern(final String text, final String supportId) {
+    final Set<Method> staticMethods = getStaticMethods(supportId);
+    return createElementPatternNoGroovy(text, new Function<Frame, Object>() {
+      public Object fun(final Frame frame) {
+        try {
+          return invokeMethod(frame.target, frame.methodName, frame.params.toArray(), staticMethods);
+        }
+        catch (Throwable throwable) {
+          throw new IllegalArgumentException(text, throwable);
+        }
+      }
+    });
+  }
+
+  private static Set<Method> getStaticMethods(String supportId) {
     final Class[] patternClasses = getPatternClasses(supportId);
-    final Set<Method> staticMethods = new THashSet<Method>(ContainerUtil.concat(patternClasses, new Function<Class, Collection<? extends Method>>() {
+    return new THashSet<Method>(ContainerUtil.concat(patternClasses, new Function<Class, Collection<? extends Method>>() {
       public Collection<Method> fun(final Class aClass) {
         return ContainerUtil.findAll(ReflectionCache.getMethods(aClass), new Condition<Method>() {
           public boolean value(final Method method) {
@@ -137,16 +148,6 @@ public class PatternBasedInjectionHelper {
         });
       }
     }));
-    return createElementPatternNoGroovy(text, new Function<Frame, Object>() {
-      public Object fun(final Frame frame) {
-        try {
-          return invokeMethod(frame.target, frame.methodName, frame.params.toArray(), staticMethods);
-        }
-        catch (Throwable throwable) {
-          throw new IllegalArgumentException(text, throwable);
-        }
-      }
-    });
   }
 
   private static enum State {
@@ -366,4 +367,152 @@ public class PatternBasedInjectionHelper {
     }, ", ")+")");
   }
 
+
+  public static String dumpContextDeclarations(String injectorId) {
+    final Set<Method> methods = getStaticMethods(injectorId);
+    final StringBuilder sb = new StringBuilder();
+    final THashMap<Class, Collection<Class>> classes = new THashMap<Class, Collection<Class>>();
+    final THashSet<Class> missingClasses = new THashSet<Class>();
+    classes.put(Object.class, missingClasses);
+    for (Method method : methods) {
+      for (Class<?> type = method.getReturnType(); type != null && ElementPattern.class.isAssignableFrom(type); type = type.getSuperclass()) {
+        final Class<?> enclosingClass = type.getEnclosingClass();
+        if (enclosingClass != null) {
+          Collection<Class> list = classes.get(enclosingClass);
+          if (list == null) {
+            list = new THashSet<Class>();
+            classes.put(enclosingClass, list);
+          }
+          list.add(type);
+        }
+        else if (!classes.containsKey(type)) {
+          classes.put(type, null);
+        }
+      }
+    }
+    for (Class aClass : classes.keySet()) {
+      if (aClass == Object.class) continue;
+      printClass(aClass, classes, sb);
+    }
+    for (Method method : methods) {
+      printMethodDeclaration(method, sb, classes);
+    }
+    for (Class aClass : missingClasses) {
+      sb.append("class ").append(aClass.getSimpleName());
+      final Class superclass = aClass.getSuperclass();
+      if (missingClasses.contains(superclass)) {
+        sb.append(" extends ").append(superclass.getSimpleName());
+      }
+      sb.append("{}\n");
+    }
+    //System.out.println(sb);
+    return sb.toString();
+  }
+
+  private static void printClass(Class aClass, Map<Class, Collection<Class>> classes, StringBuilder sb) {
+    final boolean isInterface = aClass.isInterface();
+    sb.append(isInterface ? "interface ": "class ");
+    dumpType(aClass, aClass, sb, classes);
+    final Type superClass = aClass.getGenericSuperclass();
+    final Class rawSuperClass = (Class)(superClass instanceof ParameterizedType ? ((ParameterizedType)superClass).getRawType() : superClass);
+    if (superClass != null && classes.containsKey(rawSuperClass)) {
+      sb.append(" extends ");
+      dumpType(null, superClass, sb, classes);
+    }
+    int implementsIdx = 1;
+    for (Type superInterface : aClass.getGenericInterfaces()) {
+      final Class rawSuperInterface = (Class)(superInterface instanceof ParameterizedType ? ((ParameterizedType)superInterface).getRawType() : superClass);
+      if (classes.containsKey(rawSuperInterface)) {
+        if (implementsIdx++ == 1) sb.append(isInterface? " extends " : " implements ");
+        else sb.append(", ");
+        dumpType(null, superInterface, sb, classes);
+      }
+    }
+    sb.append(" {\n");
+    for (Method method : aClass.getDeclaredMethods()) {
+      if (Modifier.isStatic(method.getModifiers()) ||
+          !Modifier.isPublic(method.getModifiers()) ||
+          Modifier.isVolatile(method.getModifiers())) continue;
+      printMethodDeclaration(method, sb.append("  "), classes);
+    }
+    final Collection<Class> innerClasses = classes.get(aClass);
+    sb.append("}\n");
+    if (innerClasses != null) {
+      for (Class innerClass : innerClasses) {
+        printClass(innerClass, classes, sb);
+      }
+    }
+  }
+
+  private static void dumpType(GenericDeclaration owner, Type type, StringBuilder sb, Map<Class, Collection<Class>> classes) {
+    if (type instanceof Class) {
+      final Class aClass = (Class)type;
+      final Class enclosingClass = aClass.getEnclosingClass();
+      if (enclosingClass != null) {
+        sb.append(enclosingClass.getSimpleName()).append("_");
+      }
+      else if (!aClass.isArray() && !aClass.isPrimitive() && !aClass.getName().startsWith("java.") && !classes.containsKey(aClass)) {
+        classes.get(Object.class).add(aClass);
+      }
+      sb.append(aClass.getSimpleName());
+      if (owner == aClass) {
+        dumpTypeParametersArray(owner, aClass.getTypeParameters(), sb, "<", ">", classes);
+      }
+    }
+    else if (type instanceof TypeVariable) {
+      TypeVariable typeVariable = (TypeVariable)type;
+      sb.append(typeVariable.getName());
+      if (typeVariable.getGenericDeclaration() == owner) {
+        dumpTypeParametersArray(null, typeVariable.getBounds(), sb, " extends ", "", classes);
+      }
+    }
+    else if (type instanceof WildcardType) {
+      final WildcardType wildcardType = (WildcardType)type;
+      sb.append("?");
+      dumpTypeParametersArray(owner, wildcardType.getUpperBounds(), sb, " extends ", "", classes);
+      dumpTypeParametersArray(owner, wildcardType.getLowerBounds(), sb, " super ", "", classes);
+    }
+    else if (type instanceof ParameterizedType) {
+      final ParameterizedType parameterizedType = (ParameterizedType)type;
+      final Type raw = parameterizedType.getRawType();
+      dumpType(null, raw, sb, classes);
+      dumpTypeParametersArray(owner, parameterizedType.getActualTypeArguments(), sb, "<", ">", classes);
+    }
+    else if (type instanceof GenericArrayType) {
+      dumpType(owner, ((GenericArrayType)type).getGenericComponentType(), sb, classes);
+      sb.append("[]");
+    }
+  }
+
+  private static void dumpTypeParametersArray(GenericDeclaration owner, final Type[] typeVariables,
+                                              final StringBuilder sb,
+                                              final String prefix, final String suffix, Map<Class, Collection<Class>> classes) {
+    int typeVarIdx = 1;
+    for (Type typeVariable : typeVariables) {
+      if (typeVariable == Object.class) continue;
+      if (typeVarIdx++ == 1) sb.append(prefix);
+      else sb.append(", ");
+      dumpType(owner, typeVariable, sb, classes);
+    }
+    if (typeVarIdx > 1) sb.append(suffix);
+  }
+
+  private static void printMethodDeclaration(Method method, StringBuilder sb, Map<Class, Collection<Class>> classes) {
+    if (Modifier.isStatic(method.getModifiers())) {
+      sb.append("static ");
+    }
+    dumpTypeParametersArray(method, method.getTypeParameters(), sb, "<", "> ", classes);
+    dumpType(null, method.getGenericReturnType(), sb, classes);
+    sb.append(" ").append(method.getName()).append("(");
+    int paramIdx = 1;
+    for (Type parameter : method.getGenericParameterTypes()) {
+      if (paramIdx != 1) sb.append(", ");
+      dumpType(null, parameter, sb, classes);
+      sb.append(" ").append("p").append(paramIdx++);
+    }
+    sb.append(")");
+    if (!method.getDeclaringClass().isInterface()) sb.append("{}");
+    sb.append("\n");
+  }
+
 }
index 73f08c034238482e4d6b2ee3b9ebb113a2f082e2..eeb554824b18f5bf9e15b0014df3ca75f3f1573c 100644 (file)
@@ -19,7 +19,6 @@ package org.intellij.plugins.intelliLang.inject;
 import com.intellij.lang.Language;
 import com.intellij.openapi.actionSystem.AnAction;
 import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.application.ex.ApplicationEx;
 import com.intellij.openapi.application.ex.ApplicationManagerEx;
 import com.intellij.openapi.options.Configurable;
 import com.intellij.openapi.project.Project;
@@ -27,6 +26,7 @@ import com.intellij.openapi.ui.DialogBuilder;
 import com.intellij.openapi.ui.DialogWrapper;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.util.Factory;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiLanguageInjectionHost;
 import com.intellij.ui.SimpleColoredText;
@@ -99,10 +99,11 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection
   public static AnAction createDefaultAddAction(final Project project,
                                                 final Consumer<BaseInjection> consumer,
                                                 final AbstractLanguageInjectionSupport support) {
-    return new AnAction("Generic "+support.getId().toUpperCase(), null, Icons.FILE_ICON) {
+    return new AnAction("Generic "+ StringUtil.capitalize(support.getId()), null, Icons.FILE_ICON) {
       @Override
       public void actionPerformed(AnActionEvent e) {
         final BaseInjection injection = new BaseInjection(support.getId());
+        injection.setDisplayName("New "+support.getId()+" Injection");
         final BaseInjection newInjection = showInjectionUI(project, injection);
         if (newInjection != null) {
           consumer.consume(injection);
index df9d93acb57bef0be61295e94252cd9ace654a72..710a47b8440c834059e4abfeac2b3766c2c58f11 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.JDOMExternalizer;
+import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.ElementManipulators;
@@ -49,6 +50,8 @@ import java.util.regex.Pattern;
  */
 public class BaseInjection implements Injection, PersistentStateComponent<Element> {
 
+  public static final Key<BaseInjection> INJECTION_KEY = Key.create("INJECTION_KEY");
+
   @NotNull private final String mySupportId;
   private String myDisplayName;
 
@@ -89,6 +92,10 @@ public class BaseInjection implements Injection, PersistentStateComponent<Elemen
     return myDisplayName;
   }
 
+  public void setDisplayName(String displayName) {
+    myDisplayName = displayName;
+  }
+
   public void setInjectedLanguageId(@NotNull String injectedLanguageId) {
     myInjectedLanguageId = injectedLanguageId;
   }
index 63812ba1b9d588c7c57c9a77bde9bfb0bf351c09..7f40ff55ba56ffd87bc877de89b6139c05e4c8bd 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.intellij.plugins.intelliLang.inject.config.ui.BaseInjectionPanel">
-  <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+  <grid id="27dc6" binding="myRoot" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="0" left="0" bottom="0" right="0"/>
     <constraints>
       <xy x="20" y="20" width="500" height="400"/>
     <children>
       <nested-form id="1d540" form-file="org/intellij/plugins/intelliLang/inject/config/ui/LanguagePanel.form" binding="myLanguagePanel" custom-create="true">
         <constraints>
-          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
         </constraints>
       </nested-form>
       <grid id="84778" binding="myCenterPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
         <constraints>
-          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties/>
         <border type="none" title="Places Pattern"/>
       </grid>
       <nested-form id="b6e0b" form-file="org/intellij/plugins/intelliLang/inject/config/ui/AdvancedPanel.form" binding="myAdvancedPanel" custom-create="true">
         <constraints>
-          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
         </constraints>
       </nested-form>
+      <grid id="b5d68" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="46a6b" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <labelFor value="5916a"/>
+              <text value="Display &amp;Name:"/>
+            </properties>
+          </component>
+          <component id="5916a" class="javax.swing.JTextField" binding="myNameTextField">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                <preferred-size width="150" height="-1"/>
+              </grid>
+            </constraints>
+            <properties/>
+          </component>
+        </children>
+      </grid>
     </children>
   </grid>
   <inspectionSuppressions>
index 91ad20570129d5c5f6f3f4ed3ed91bf131e8071a..1cee03a0e9be2d9f4868b19684025c51fd28b20b 100644 (file)
  */
 package org.intellij.plugins.intelliLang.inject.config.ui;
 
-import com.intellij.openapi.editor.colors.EditorColorsManager;
-import com.intellij.openapi.editor.colors.EditorFontType;
+import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.FileTypeManager;
 import com.intellij.openapi.fileTypes.FileTypes;
 import com.intellij.openapi.fileTypes.UnknownFileType;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
 import com.intellij.ui.EditorTextField;
-import com.intellij.ui.ScrollPaneFactory;
 import org.intellij.plugins.intelliLang.PatternBasedInjectionHelper;
 import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
 import org.intellij.plugins.intelliLang.inject.config.InjectionPlace;
@@ -46,26 +48,38 @@ public class BaseInjectionPanel extends AbstractInjectionPanel<BaseInjection> {
   AdvancedPanel myAdvancedPanel;
 
   private JPanel myRoot;
+  private JTextField myNameTextField;
 
   public BaseInjectionPanel(BaseInjection injection, Project project) {
     super(injection, project);
     $$$setupUI$$$(); // see IDEA-9987
     final FileType groovy = FileTypeManager.getInstance().getFileTypeByExtension("groovy");
-    myTextArea = new EditorTextField("", project, groovy == UnknownFileType.INSTANCE? FileTypes.PLAIN_TEXT : groovy) {
+    final FileType realFileType = groovy == UnknownFileType.INSTANCE ? FileTypes.PLAIN_TEXT : groovy;
+    final PsiFile psiFile = PsiFileFactory.getInstance(project).createFileFromText("injection." + realFileType.getDefaultExtension(), realFileType, "", 0, true);
+    final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
+    psiFile.putUserData(BaseInjection.INJECTION_KEY, injection);
+    myTextArea = new EditorTextField(document, project, realFileType) {
       @Override
       protected EditorEx createEditor() {
         final EditorEx ex = super.createEditor();
         ex.setOneLineMode(false);
+        ex.setVerticalScrollbarVisible(true);
+        ex.setHorizontalScrollbarVisible(true);
         return ex;
       }
     };
-    myCenterPanel.add(ScrollPaneFactory.createScrollPane(myTextArea), BorderLayout.CENTER);
+    myCenterPanel.add(myTextArea, BorderLayout.CENTER);
     myTextArea.setFontInheritedFromLAF(false);
     //myTextArea.setFont(EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN));
     init(injection.copy());
   }
 
   protected void apply(BaseInjection other) {
+    final String displayName = myNameTextField.getText();
+    if (StringUtil.isEmpty(displayName)) {
+      throw new IllegalArgumentException("Display name should not be empty");
+    }
+    other.setDisplayName(displayName);
     boolean enabled = true;
     final StringBuilder sb = new StringBuilder();
     final ArrayList<InjectionPlace> places = new ArrayList<InjectionPlace>();
@@ -104,6 +118,7 @@ public class BaseInjectionPanel extends AbstractInjectionPanel<BaseInjection> {
       sb.append(place.isEnabled()?"+ ":"- ").append(place.getText()).append("\n");
     }
     myTextArea.setText(sb.toString());
+    myNameTextField.setText(myOrigInjection.getDisplayName());
   }
 
   public JPanel getComponent() {
index 365491c9511ed91d9d7f9efe9f587dc4f9779c4d..e731f61f3561d7ea6ab49ecab3b6de370231d851 100644 (file)
@@ -6,5 +6,8 @@
     <languageSupport implementation="org.intellij.plugins.intelliLang.inject.groovy.GroovyLanguageInjectionSupport"
                      config="/resources/groovyInjections.xml"/>
   </extensions>
+  <extensions defaultExtensionNs="org.intellij.groovy">
+    <nonCodeProcessor implementation="org.intellij.plugins.intelliLang.inject.groovy.PatternEditorContextMembersProvider"/>
+  </extensions>
 
 </idea-plugin>
diff --git a/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java b/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java
new file mode 100644 (file)
index 0000000..b78c906
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.intellij.plugins.intelliLang.inject.groovy;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.AtomicNotNullLazyValue;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.UserDataHolderEx;
+import com.intellij.psi.*;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import org.intellij.plugins.intelliLang.PatternBasedInjectionHelper;
+import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.GroovyFileType;
+import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor;
+
+/**
+ * @author Gregory.Shrago
+ */
+public class PatternEditorContextMembersProvider implements NonCodeMembersProcessor {
+
+  public static final Key<AtomicNotNullLazyValue<PsiFile>> INJECTION_PARSED_CONTEXT = Key.create("INJECTION_PARSED_CONTEXT");
+
+  public boolean processNonCodeMembers(PsiType type, PsiScopeProcessor processor, PsiElement place, boolean forCompletion) {
+    final PsiFile file = place.getContainingFile().getOriginalFile();
+    final BaseInjection injection = file.getUserData(BaseInjection.INJECTION_KEY);
+    if (injection == null) return true;
+    return ((UserDataHolderEx)file).putUserDataIfAbsent(INJECTION_PARSED_CONTEXT, new AtomicNotNullLazyValue<PsiFile>() {
+      @NotNull
+      @Override
+      protected PsiFile compute() {
+        return parseInjectionContext(injection, file.getProject());
+      }
+    }).getValue().processDeclarations(processor, ResolveState.initial(), null, place);
+  }
+
+  private static PsiFile parseInjectionContext(@NotNull BaseInjection injection, Project project) {
+    final String text = PatternBasedInjectionHelper.dumpContextDeclarations(injection.getSupportId());
+    return PsiFileFactory.getInstance(project).createFileFromText("context.groovy", GroovyFileType.GROOVY_FILE_TYPE, text);
+  }
+}