Package org.jetbrains.plugins.clojure.psi.impl.list

Source Code of org.jetbrains.plugins.clojure.psi.impl.list.ListDeclarations

package org.jetbrains.plugins.clojure.psi.impl.list;

import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.clojure.psi.api.ClList;
import org.jetbrains.plugins.clojure.psi.api.ClVector;
import org.jetbrains.plugins.clojure.psi.api.defs.ClDef;
import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol;
import org.jetbrains.plugins.clojure.psi.impl.ImportOwner;
import org.jetbrains.plugins.clojure.psi.impl.ns.ClSyntheticNamespace;
import org.jetbrains.plugins.clojure.psi.impl.ns.NamespaceUtil;
import org.jetbrains.plugins.clojure.psi.impl.symbols.ClSymbolImpl;
import org.jetbrains.plugins.clojure.psi.resolve.ResolveUtil;
import org.jetbrains.plugins.clojure.psi.util.ClojureKeywords;

import java.util.Arrays;
import java.util.Set;

/**
* @author ilyas
*/
public class ListDeclarations {

  public static final String LET = "let";
  public static final String WITH_OPEN = "with-open";
  public static final String WITH_LOCAL_VARS = "with-local-vars";
  public static final String WHEN_LET = "when-let";
  public static final String WHEN_FIRST = "when-let";
  public static final String FOR = "for";
  public static final String IF_LET = "if-let";
  public static final String LOOP = "loop";
  public static final String DOSEQ = "doseq";
  public static final String DECLARE = "declare";
  public static final String FN = "fn";

  public static final String NS = "ns";

  public static final String DEFN = "defn";
  public static final String DEFN_ = "defn-";
  public static final String IMPORT = "import";
  private static final String MEMFN = "memfn";
  public static final String USE = "use";
  public static final String REFER = "refer";
  public static final String REQUIRE = "require";

  private static final String DOT = ".";

  private static final Set<String> LOCAL_BINDINGS = new HashSet<String>(Arrays.asList(
      LET, WITH_OPEN, WITH_LOCAL_VARS, WHEN_LET, WHEN_FIRST, FOR, IF_LET, LOOP, FN, DOSEQ
  ));

  public static boolean get(PsiScopeProcessor processor,
                            ResolveState state,
                            PsiElement lastParent,
                            PsiElement place,
                            ClList list,
                            @Nullable String headText) {
    if (headText == null) return true;
    if (headText.equals(FN)) return processFnDeclaration(processor, list, place, lastParent);
    if (headText.equals(IMPORT)) return ImportOwner.processImports(processor, place, list, headText);
    if (headText.equals(USE)) return ImportOwner.processUses(processor, place, list, headText);
    if (headText.equals(REFER)) return ImportOwner.processRefer(processor, place, list, headText);
    if (headText.equals(REQUIRE)) return ImportOwner.processRequires(processor, place, list, headText);
    if (headText.equals(MEMFN)) return processMemFnDeclaration(processor, list, place);
    if (headText.equals(DOT)) return processDotDeclaration(processor, list, place, lastParent);
    if (headText.equals(LOOP)) return processLoopDeclaration(processor, list, place, lastParent);
    if (headText.equals(DOSEQ)) return processDoseqDeclaration(processor, list, place, lastParent);
    if (headText.equals(DECLARE)) return processDeclareDeclaration(processor, list, place, lastParent);
    if (headText.equals(LET) && !processLetContents(processor, list, place)) return false;
    if (LOCAL_BINDINGS.contains(headText)) return processBindings(processor, list, place);

    final PsiElement parent = list.getParent();
    if (parent != null && parent instanceof ClList) {
      return getWithParentContext(processor, list, ((ClList) parent), state, lastParent, place);
    }

    return true;
  }

  private static boolean getWithParentContext(PsiScopeProcessor processor, ClList list, ClList parent,
                                              ResolveState state, PsiElement lastParent, PsiElement place) {
    final String parentHead = parent.getHeadText();
    final PsiElement first = list.getFirstNonLeafElement();
    if (processUseParent(processor, place, parentHead, first, state, lastParent)) return true;
    return true;
  }

  /*
    Handle (:use ...) parent, e.g.

    (ns my-namespace
     (:use (clojure <caret> data inspector)))

   */
  private static boolean processUseParent(PsiScopeProcessor processor, PsiElement place, String parentHead,
                                          PsiElement first, ResolveState state, PsiElement lastParent) {
    if ((USE.equals(parentHead) || ClojureKeywords.USE.equals(parentHead)) &&
        first instanceof ClSymbol) {
      final ClSymbol symbol = (ClSymbol) first;
      final ClSyntheticNamespace namespace = NamespaceUtil.getNamespace(symbol.getNameString(), place.getProject());
      return namespace == null? true : namespace.processDeclarations(processor, state, lastParent, place);
    }
    return true;
  }

  private static boolean processDeclareDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place, PsiElement lastParent) {
    final ClVector paramVector = list.findFirstChildByClass(ClVector.class);
    if (paramVector != null) {
      for (ClSymbol symbol : paramVector.getOddSymbols()) {
        if (!ResolveUtil.processElement(processor, symbol)) return false;
      }
    }
    return true;
  }

  private static boolean processLoopDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place, PsiElement lastParent) {
    if (lastParent != null && lastParent.getParent() == list) {
      final ClVector paramVector = list.findFirstChildByClass(ClVector.class);
      if (paramVector != null) {
        for (ClSymbol symbol : paramVector.getOddSymbols()) {
          if (!ResolveUtil.processElement(processor, symbol)) return false;
        }
      }
      return true;
    }
    return true;
  }


  private static boolean processDoseqDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place, PsiElement lastParent) {
    if (lastParent != null && lastParent.getParent() == list) {
      final ClVector paramVector = list.findFirstChildByClass(ClVector.class);
      if (paramVector != null) {
        for (ClSymbol symbol : paramVector.getOddSymbols()) {
          if (!ResolveUtil.processElement(processor, symbol)) return false;
        }
      }
      return true;
    }
    return true;
  }

  private static boolean processDotDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place, PsiElement lastParent) {
    final PsiElement parent = place.getParent();
    if (parent == null || list == parent) return true;

    final PsiElement second = list.getSecondNonLeafElement();
    if (second instanceof ClSymbol && place != second) {
      ClSymbol symbol = (ClSymbol) second;
      for (ResolveResult result : symbol.multiResolve(false)) {
        final PsiElement element = result.getElement();
        if (element instanceof PsiNamedElement && !ResolveUtil.processElement(processor, (PsiNamedElement) element)) {
          return false;
        }
      }

      if (lastParent == null || lastParent == list) {
        return true;
      }
      if (parent.getParent() == list) {
        if (place instanceof ClSymbol && ((ClSymbol) place).getQualifierSymbol() == null) {
          ClSymbol symbol2 = (ClSymbol) place;
          ResolveResult[] results = ClSymbolImpl.MyResolver.resolveJavaMethodReference(symbol2, list, true);
          for (ResolveResult result : results) {
            final PsiElement element = result.getElement();
            if (element instanceof PsiNamedElement && !ResolveUtil.processElement(processor, (PsiNamedElement) element)) {
              return false;
            }
          }
        }
      }
    }
    return true;
  }

  private static boolean processMemFnDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place) {
    if (place instanceof ClSymbol && place.getParent() == list && ((ClSymbol) place).getQualifierSymbol() == null) {
      ClSymbol symbol = (ClSymbol) place;
      ResolveResult[] results = ClSymbolImpl.MyResolver.resolveJavaMethodReference(symbol, list.getParent(), true);
      for (ResolveResult result : results) {
        final PsiElement element = result.getElement();
        if (element instanceof PsiNamedElement && !ResolveUtil.processElement(processor, (PsiNamedElement) element)) {
          return false;
        }
      }
    }

    return true;
  }

  private static boolean processBindings(PsiScopeProcessor processor, ClList list, PsiElement place) {
    if (PsiTreeUtil.findCommonParent(place, list) == list) {
      final ClVector paramVector = list.findFirstChildByClass(ClVector.class);
      if (paramVector != null) {
        for (ClSymbol symbol : paramVector.getOddSymbols()) {
          if (!ResolveUtil.processElement(processor, symbol)) return false;
        }
      }
      return true;
    }
    return true;
  }

  private static boolean processLetContents(PsiScopeProcessor processor, ClList list, PsiElement place) {
    if (PsiTreeUtil.findCommonParent(place, list) != list) {
      final ClDef def = list.findFirstChildByClass(ClDef.class);
      if (def != null) {
        return ResolveUtil.processElement(processor, def);
      }
      return true;
    }
    return true;
  }

  private static boolean processFnDeclaration(PsiScopeProcessor processor, ClList list, PsiElement place, PsiElement lastParent) {
    final PsiElement second = list.getSecondNonLeafElement();

    if (lastParent == second) return true;

    if ((second instanceof ClSymbol) && !ResolveUtil.processElement(processor, ((ClSymbol) second)))
      return false;

    if (PsiTreeUtil.findCommonParent(place, list) == list) {
      ClVector paramVector = list.findFirstChildByClass(ClVector.class);
      if (paramVector == null && lastParent instanceof ClList) {
        paramVector = ((ClList) lastParent).findFirstChildByClass(ClVector.class);
      }

      if (paramVector != null) {
        for (ClSymbol symbol : paramVector.getAllSymbols()) {
          if (!ResolveUtil.processElement(processor, symbol)) return false;
        }
      }
      return true;
    }
    return true;

  }

  public static boolean isLocal(PsiElement element) {
    if (element instanceof ClSymbol) {
      ClSymbol symbol = (ClSymbol) element;
      final PsiElement parent = symbol.getParent();

      if (parent instanceof ClList) {
        ClList list = (ClList) parent;
        if (FN.equals(list.getHeadText())) return true;
      } else if (parent instanceof ClVector) {
        final PsiElement par = parent.getParent();
        if (par instanceof ClDef && ((ClDef) par).getSecondNonLeafElement() == element) return true;
        if (par instanceof ClList) {
          final String ht = ((ClList) par).getHeadText();
          if (LOCAL_BINDINGS.contains(ht)) return true;
        }
      }
    }

    return false;
  }
}
TOP

Related Classes of org.jetbrains.plugins.clojure.psi.impl.list.ListDeclarations

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.