update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / source / tree / java / PsiCodeBlockImpl.java
blob0c04702abc28de99f90abee272a04a26dc963248
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.psi.impl.source.tree.java;
18 import com.intellij.lang.ASTNode;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.util.Pair;
21 import com.intellij.openapi.util.Ref;
22 import com.intellij.psi.*;
23 import com.intellij.psi.impl.source.Constants;
24 import com.intellij.psi.impl.source.jsp.jspJava.JspExpressionStatement;
25 import com.intellij.psi.impl.source.jsp.jspJava.JspTemplateStatement;
26 import com.intellij.psi.impl.source.tree.*;
27 import com.intellij.psi.scope.BaseScopeProcessor;
28 import com.intellij.psi.scope.ElementClassHint;
29 import com.intellij.psi.scope.NameHint;
30 import com.intellij.psi.scope.PsiScopeProcessor;
31 import com.intellij.psi.scope.util.PsiScopesUtil;
32 import com.intellij.psi.tree.ChildRoleBase;
33 import com.intellij.psi.tree.IElementType;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.NotNull;
37 import java.util.Collections;
38 import java.util.Set;
40 public class PsiCodeBlockImpl extends LazyParseablePsiElement implements PsiCodeBlock, Constants {
41 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiCodeBlockImpl");
43 public PsiCodeBlockImpl(CharSequence text) {
44 super(CODE_BLOCK, text);
47 public void clearCaches() {
48 super.clearCaches();
49 myVariablesSet = null;
50 myClassesSet = null;
51 myConflict = false;
54 @NotNull
55 public PsiStatement[] getStatements() {
56 return getChildrenAsPsiElements(STATEMENT_BIT_SET, PSI_STATEMENT_ARRAY_CONSTRUCTOR);
59 public PsiElement getFirstBodyElement() {
60 final PsiElement nextSibling = getLBrace().getNextSibling();
61 return nextSibling == getRBrace() ? null : nextSibling;
64 public PsiElement getLastBodyElement() {
65 final PsiJavaToken rBrace = getRBrace();
66 if (rBrace != null) {
67 final PsiElement prevSibling = rBrace.getPrevSibling();
68 return prevSibling == getLBrace() ? null : prevSibling;
70 return getLastChild();
73 public PsiJavaToken getLBrace() {
74 return (PsiJavaToken)findChildByRoleAsPsiElement(ChildRole.LBRACE);
77 public PsiJavaToken getRBrace() {
78 return (PsiJavaToken)findChildByRoleAsPsiElement(ChildRole.RBRACE);
81 private volatile Set<String> myVariablesSet = null;
82 private volatile Set<String> myClassesSet = null;
83 private volatile boolean myConflict = false;
85 // return Pair(classesset, localsSet) or null if there was conflict
86 private Pair<Set<String>, Set<String>> buildMaps() {
87 Set<String> set1 = myClassesSet;
88 Set<String> set2 = myVariablesSet;
89 boolean wasConflict = myConflict;
90 if (set1 == null || set2 == null) {
91 final Set<String> localsSet = new THashSet<String>();
92 final Set<String> classesSet = new THashSet<String>();
93 final Ref<Boolean> conflict = new Ref<Boolean>(Boolean.FALSE);
94 PsiScopesUtil.walkChildrenScopes(this, new BaseScopeProcessor() {
95 public boolean execute(PsiElement element, ResolveState state) {
96 if (element instanceof PsiLocalVariable) {
97 final PsiLocalVariable variable = (PsiLocalVariable)element;
98 final String name = variable.getName();
99 if (!localsSet.add(name)) {
100 conflict.set(Boolean.TRUE);
101 localsSet.clear();
102 classesSet.clear();
105 else if (element instanceof PsiClass) {
106 final PsiClass psiClass = (PsiClass)element;
107 final String name = psiClass.getName();
108 if (!classesSet.add(name)) {
109 conflict.set(Boolean.TRUE);
110 localsSet.clear();
111 classesSet.clear();
114 return !conflict.get();
116 }, ResolveState.initial(), this, this);
118 myClassesSet = set1 = (classesSet.isEmpty() ? Collections.<String>emptySet() : classesSet);
119 myVariablesSet = set2 = (localsSet.isEmpty() ? Collections.<String>emptySet() : localsSet);
120 myConflict = wasConflict = conflict.get();
122 return wasConflict ? null : Pair.create(set1, set2);
125 public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) {
126 if (anchor == null){
127 if (before == null || before.booleanValue()){
128 anchor = findChildByRole(ChildRole.RBRACE);
129 before = Boolean.TRUE;
131 else{
132 anchor = findChildByRole(ChildRole.LBRACE);
133 before = Boolean.FALSE;
137 if (before == Boolean.TRUE) {
138 while (anchor instanceof JspExpressionStatement || anchor instanceof JspTemplateStatement) {
139 anchor = anchor.getTreePrev();
140 before = Boolean.FALSE;
143 else if (before == Boolean.FALSE) {
144 while (anchor instanceof JspExpressionStatement || anchor instanceof JspTemplateStatement) {
145 anchor = anchor.getTreeNext();
146 before = Boolean.TRUE;
150 return super.addInternal(first, last, anchor, before);
153 public ASTNode findChildByRole(int role) {
154 LOG.assertTrue(ChildRole.isUnique(role));
155 switch(role){
156 default:
157 return null;
159 case ChildRole.LBRACE:
160 return findChildByType(LBRACE);
162 case ChildRole.RBRACE:
163 return TreeUtil.findChildBackward(this, RBRACE);
167 public int getChildRole(ASTNode child) {
168 LOG.assertTrue(child.getTreeParent() == this);
169 IElementType i = child.getElementType();
170 if (i == LBRACE) {
171 return getChildRole(child, ChildRole.LBRACE);
173 else if (i == RBRACE) {
174 return getChildRole(child, ChildRole.RBRACE);
176 else {
177 if (ElementType.STATEMENT_BIT_SET.contains(child.getElementType())) {
178 return ChildRole.STATEMENT_IN_BLOCK;
180 return ChildRoleBase.NONE;
184 public void accept(@NotNull PsiElementVisitor visitor) {
185 if (visitor instanceof JavaElementVisitor) {
186 ((JavaElementVisitor)visitor).visitCodeBlock(this);
188 else {
189 visitor.visitElement(this);
193 public String toString() {
194 return "PsiCodeBlock";
198 public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
199 processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this);
200 if (lastParent == null) {
201 // Parent element should not see our vars
202 return true;
204 Pair<Set<String>, Set<String>> pair = buildMaps();
205 boolean conflict = pair == null;
206 final Set<String> classesSet = conflict ? null : pair.getFirst();
207 final Set<String> variablesSet = conflict ? null : pair.getSecond();
208 final NameHint hint = processor.getHint(NameHint.KEY);
209 if (hint != null && !conflict) {
210 final ElementClassHint elementClassHint = processor.getHint(ElementClassHint.KEY);
211 final String name = hint.getName(state);
212 if ((elementClassHint == null || elementClassHint.shouldProcess(ElementClassHint.DeclaractionKind.CLASS)) && classesSet.contains(name)) {
213 return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place);
215 if ((elementClassHint == null || elementClassHint.shouldProcess(ElementClassHint.DeclaractionKind.VARIABLE)) && variablesSet.contains(name)) {
216 return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place);
219 else {
220 return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place);
222 return true;