1 /* 2 * Copyright 2000-2005 JetBrains s.r.o. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.intellij.lang.javascript.psi; 17 18 import com.intellij.psi.PsiElement; 19 import com.intellij.psi.PsiFile; 20 import com.intellij.psi.PsiNamedElement; 21 import com.intellij.psi.PsiSubstitutor; 22 import com.intellij.psi.scope.PsiScopeProcessor; 23 import org.jetbrains.annotations.Nullable; 24 import org.jetbrains.annotations.NotNull; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 29 /** 30 * @author max 31 */ 32 public class JSResolveUtil { 33 private JSResolveUtil() {} 34 35 @Nullable 36 public static PsiElement treeWalkUp(PsiScopeProcessor processor, PsiElement elt, PsiElement lastParent, PsiElement place) { 37 if (elt == null) return null; 38 39 PsiElement cur = elt; 40 do { 41 if (!cur.processDeclarations(processor, PsiSubstitutor.EMPTY, cur == elt ? lastParent : null, place)) { 42 if (processor instanceof ResolveProcessor) { 43 return ((ResolveProcessor)processor).getResult(); 44 } 45 } 46 if(cur instanceof PsiFile) break; 47 if (cur instanceof JSStatement && cur.getContext() instanceof JSIfStatement) { 48 // Do not try to resolve variables from then branch in else branch. 49 break; 50 } 51 52 53 cur = cur.getPrevSibling(); 54 } while (cur != null); 55 56 final PsiElement func = processFunctionDeclarations(processor, elt.getContext()); 57 if (func != null) return func; 58 59 return treeWalkUp(processor, elt.getContext(), elt, place); 60 } 61 62 @Nullable 63 private static PsiElement processFunctionDeclarations(final @NotNull PsiScopeProcessor processor, final @Nullable PsiElement context) { 64 if (context != null) { 65 PsiElement cur = context.getLastChild(); 66 while (cur != null) { 67 if (cur instanceof JSFunction) { 68 if (!processor.execute(cur, PsiSubstitutor.EMPTY)) { 69 if (processor instanceof ResolveProcessor) { 70 return ((ResolveProcessor)processor).getResult(); 71 } 72 } 73 } 74 cur = cur.getPrevSibling(); 75 } 76 } 77 return null; 78 } 79 80 public static class ResolveProcessor implements PsiScopeProcessor { 81 private String myName; 82 private PsiElement myResult = null; 83 84 public ResolveProcessor(final String name) { 85 myName = name; 86 } 87 88 public PsiElement getResult() { 89 return myResult; 90 } 91 92 public boolean execute(PsiElement element, PsiSubstitutor substitutor) { 93 if (element instanceof PsiNamedElement && 94 element instanceof JSElement 95 ) { 96 if (myName.equals(((PsiNamedElement)element).getName())) { 97 myResult = element; 98 return false; 99 } 100 } 101 102 return true; 103 } 104 105 public <T> T getHint(Class<T> hintClass) { 106 return null; 107 } 108 109 public void handleEvent(Event event, Object associated) { 110 } 111 } 112 113 public static class VariantsProcessor implements PsiScopeProcessor { 114 private List<PsiElement> myNames = new ArrayList<PsiElement>(); 115 116 public VariantsProcessor() { 117 } 118 119 public PsiElement[] getResult() { 120 return myNames.toArray(new PsiElement[myNames.size()]); 121 } 122 123 public boolean execute(PsiElement element, PsiSubstitutor substitutor) { 124 if (element instanceof PsiNamedElement && 125 element instanceof JSElement 126 ) { 127 myNames.add(element); 128 } 129 130 return true; 131 } 132 133 public <T> T getHint(Class<T> hintClass) { 134 return null; 135 } 136 137 public void handleEvent(Event event, Object associated) { 138 } 139 } 140 } 141