[groovy] make GrReferenceResolveRunner stateless by passing processor and element...
authorDaniil Ovchinnikov <daniil.ovchinnikov@jetbrains.com>
Wed, 25 May 2016 12:35:37 +0000 (15:35 +0300)
committerDaniil Ovchinnikov <daniil.ovchinnikov@jetbrains.com>
Wed, 25 May 2016 13:01:17 +0000 (16:01 +0300)
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java [deleted file]
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.kt [new file with mode: 0644]

index 74bc7bd82a0ee9ff2818d62dba88c17400775999..a60a573f51180e10de3beec59d10e13b7898b0ea 100644 (file)
@@ -511,7 +511,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
       .setAllVariants(allVariants)
       .setUpToArgument(upToArgument)
       .build(this);
-    new GrReferenceResolveRunner(this, processor).resolveImpl();
+    GrReferenceResolveRunnerKt.resolveReferenceExpression(this, processor);
     return processor.getCandidatesArray();
   }
 
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java
deleted file mode 100644 (file)
index 7fdc741..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2000-2016 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.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
-
-import com.intellij.psi.*;
-import com.intellij.psi.util.InheritanceUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
-import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
-import org.jetbrains.plugins.groovy.lang.psi.impl.GrTraitType;
-import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
-import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer;
-import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
-import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor;
-import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
-import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
-import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor;
-
-/**
- * @author Medvedev Max
- */
-public class GrReferenceResolveRunner {
-  private final GrReferenceExpression place;
-  private final GroovyResolverProcessor processor;
-
-  public GrReferenceResolveRunner(GrReferenceExpression place,
-                                  GroovyResolverProcessor processor) {
-    this.place = place;
-    this.processor = processor;
-  }
-
-  public void resolveImpl() {
-    GrExpression qualifier = place.getQualifier();
-    if (qualifier == null) {
-      if (!ResolveUtil.treeWalkUp(place, processor, true)) return;
-
-      if (place.getContext() instanceof GrMethodCall) {
-        if (!ClosureMissingMethodContributor.processMethodsFromClosures(place, processor)) return;
-      }
-    }
-    else {
-      if (place.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) {
-        final PsiType qtype = qualifier.getType();
-        final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qtype, place);
-        if (componentType != null) {
-          final ResolveState state = ResolveState.initial()
-            .put(ClassHint.RESOLVE_CONTEXT, qualifier)
-            .put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null));
-          processQualifierType(componentType, state);
-        }
-      }
-      else {
-        if (ResolveUtil.isClassReference(place)) return;
-        if (!processJavaLangClass(qualifier)) return;
-        processQualifier(qualifier);
-      }
-    }
-  }
-
-  private boolean processJavaLangClass(@NotNull GrExpression qualifier) {
-    if (!(qualifier instanceof GrReferenceExpression)) return true;
-
-    //optimization: only 'class' or 'this' in static context can be an alias of java.lang.Class
-    if (!"class".equals(((GrReferenceExpression)qualifier).getReferenceName()) &&
-        !PsiUtil.isThisReference(qualifier) &&
-        !(((GrReferenceExpression)qualifier).resolve() instanceof PsiClass)) {
-      return true;
-    }
-
-    PsiType classType = ResolveUtil.unwrapClassType(qualifier.getType());
-    return classType == null || processQualifierType(classType, ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier));
-  }
-
-  private boolean processQualifier(@NotNull GrExpression qualifier) {
-    PsiType qualifierType = qualifier.getType();
-    ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier);
-    if (qualifierType == null || PsiType.VOID.equals(qualifierType)) {
-      if (qualifier instanceof GrReferenceExpression) {
-        PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
-        if (resolved instanceof PsiClass) {
-          if (!ResolveUtil.processClassDeclarations((PsiClass)resolved, processor, state, null, place)) return false;
-        }
-        else if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false;
-        if (!(resolved instanceof PsiPackage)) {
-          PsiType objectQualifier = TypesUtil.getJavaLangObject(place);
-          if (!processQualifierType(objectQualifier, state)) return false;
-        }
-      }
-    }
-    else {
-      if (!processQualifierType(qualifierType, state)) return false;
-    }
-    return true;
-  }
-
-  private boolean processQualifierType(@NotNull PsiType originalQualifierType,
-                                       @NotNull ResolveState state) {
-    PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
-                            ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
-                            : originalQualifierType;
-
-    if (qualifierType instanceof PsiIntersectionType) {
-      for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
-        if (!processQualifierType(conjunct, state)) return false;
-      }
-      return true;
-    }
-
-    if (qualifierType instanceof PsiCapturedWildcardType) {
-      PsiWildcardType wildcard = ((PsiCapturedWildcardType)qualifierType).getWildcard();
-      if (wildcard.isExtends()) {
-        PsiType bound = wildcard.getExtendsBound();
-        return processQualifierType(bound, state);
-      }
-    }
-
-    if (qualifierType instanceof GrTraitType) {
-      return processTraitType((GrTraitType)qualifierType, state);
-    }
-
-    if (qualifierType instanceof PsiClassType) {
-      PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics();
-      PsiClass qualifierClass = qualifierResult.getElement();
-      if (qualifierClass != null) {
-        if (!ResolveUtil.processClassDeclarations(qualifierClass, processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) {
-          return false;
-        }
-      }
-    }
-    else if (qualifierType instanceof PsiArrayType) {
-      final GroovyPsiManager gmanager = GroovyPsiManager.getInstance(place.getProject());
-      final GrTypeDefinition arrayClass = gmanager.getArrayClass(((PsiArrayType)qualifierType).getComponentType());
-      if (arrayClass != null && !ResolveUtil.processClassDeclarations(arrayClass, processor, state, null, place)) return false;
-    }
-
-    if (!(place.getParent() instanceof GrMethodCall) && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
-      final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qualifierType, place);
-      if (componentType != null) {
-        final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
-        processQualifierType(componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)));
-      }
-    }
-
-    if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
-    if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
-    return true;
-  }
-
-  /**
-   * Process trait type conjuncts in reversed order because last applied trait matters.
-   */
-  private boolean processTraitType(@NotNull GrTraitType traitType, @NotNull ResolveState state) {
-    final PsiType[] conjuncts = traitType.getConjuncts();
-    for (int i = conjuncts.length - 1; i >= 0; i--) {
-      if (!processQualifierType(conjuncts[i], state)) return false;
-    }
-    return true;
-  }
-}
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.kt
new file mode 100644 (file)
index 0000000..2ea4489
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2000-2016 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.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions
+
+import com.intellij.psi.*
+import com.intellij.psi.scope.PsiScopeProcessor
+import com.intellij.psi.util.InheritanceUtil
+import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes
+import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
+import org.jetbrains.plugins.groovy.lang.psi.impl.GrTraitType
+import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager
+import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer
+import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil
+import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor
+import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
+import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint
+
+fun resolveReferenceExpression(place: GrReferenceExpression, processor: PsiScopeProcessor): Boolean {
+  val qualifier = place.qualifier
+  if (qualifier == null) {
+    if (!ResolveUtil.treeWalkUp(place, processor, true)) return false
+    return place.context !is GrMethodCall || ClosureMissingMethodContributor.processMethodsFromClosures(place, processor)
+  }
+  else {
+    if (place.dotTokenType === GroovyTokenTypes.mSPREAD_DOT) {
+      val qType = qualifier.type
+      val componentType = ClosureParameterEnhancer.findTypeForIteration(qType, place)
+      if (componentType != null) {
+        val state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier).put(SpreadState.SPREAD_STATE, SpreadState.create(qType, null))
+        return processQualifierType(place, componentType, processor, state)
+      }
+    }
+    else {
+      if (ResolveUtil.isClassReference(place)) return false
+      if (!processJavaLangClass(place, qualifier, processor)) return false
+      return processQualifier(place, qualifier, processor)
+    }
+  }
+  return true
+}
+
+fun processJavaLangClass(place: PsiElement, qualifier: GrExpression, processor: PsiScopeProcessor): Boolean {
+  if (qualifier !is GrReferenceExpression) return true
+
+  //optimization: only 'class' or 'this' in static context can be an alias of java.lang.Class
+  if ("class" != qualifier.referenceName && !PsiUtil.isThisReference(qualifier) && qualifier.resolve() !is PsiClass) return true
+
+  val classType = ResolveUtil.unwrapClassType(qualifier.getType())
+  return classType?.let {
+    val state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier)
+    processQualifierType(place, classType, processor, state)
+  } ?: true
+}
+
+fun processQualifier(place: PsiElement, qualifier: GrExpression, processor: PsiScopeProcessor): Boolean {
+  val qualifierType = qualifier.type
+  val state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier)
+  if (qualifierType == null || PsiType.VOID == qualifierType) {
+    if (qualifier is GrReferenceExpression) {
+      val resolved = qualifier.resolve()
+      if (resolved is PsiClass) {
+        if (!ResolveUtil.processClassDeclarations((resolved as PsiClass?)!!, processor, state, null, place)) return false
+      }
+      else if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false
+      if (resolved !is PsiPackage) {
+        val objectQualifier = TypesUtil.getJavaLangObject(place)
+        if (!processQualifierType(place, objectQualifier, processor, state)) return false
+      }
+    }
+  }
+  else {
+    if (!processQualifierType(place, qualifierType, processor, state)) return false
+  }
+  return true
+}
+
+fun processQualifierType(place: PsiElement, qualifierType: PsiType, processor: PsiScopeProcessor, state: ResolveState): Boolean {
+  val type = if (qualifierType is PsiDisjunctionType) qualifierType.leastUpperBound else qualifierType
+  return doProcessQualifierType(place, type, processor, state)
+}
+
+fun doProcessQualifierType(place: PsiElement, qualifierType: PsiType, processor: PsiScopeProcessor, state: ResolveState): Boolean {
+  if (qualifierType is PsiIntersectionType) {
+    return qualifierType.conjuncts.find { !processQualifierType(place, it, processor, state) } == null
+  }
+
+  if (qualifierType is PsiCapturedWildcardType) {
+    val wildcard = qualifierType.wildcard
+    if (wildcard.isExtends) {
+      return processQualifierType(place, wildcard.extendsBound, processor, state)
+    }
+  }
+
+  // Process trait type conjuncts in reversed order because last applied trait matters.
+  if (qualifierType is GrTraitType) return qualifierType.conjuncts.findLast { !processQualifierType(place, it, processor, state) } == null
+
+  if (qualifierType is PsiClassType) {
+    val qualifierResult = qualifierType.resolveGenerics()
+    qualifierResult.element?.let {
+      val resolveState = state.put(PsiSubstitutor.KEY, qualifierResult.substitutor)
+      if (!ResolveUtil.processClassDeclarations(it, processor, resolveState, null, place)) return false
+    }
+  }
+  else if (qualifierType is PsiArrayType) {
+    GroovyPsiManager.getInstance(place.project).getArrayClass(qualifierType.componentType)?.let {
+      if (!ResolveUtil.processClassDeclarations(it, processor, state, null, place)) return false
+    }
+  }
+
+  if (place.parent !is GrMethodCall && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
+    ClosureParameterEnhancer.findTypeForIteration(qualifierType, place)?.let {
+      val spreadState = state.get(SpreadState.SPREAD_STATE)
+      val resolveState = state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState))
+      if (!processQualifierType(place, it, processor, resolveState)) return false
+    }
+  }
+
+  if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false
+  if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false
+  return true
+}
\ No newline at end of file