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
;
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() {
49 myVariablesSet
= null;
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();
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
);
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
);
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
) {
127 if (before
== null || before
.booleanValue()){
128 anchor
= findChildByRole(ChildRole
.RBRACE
);
129 before
= Boolean
.TRUE
;
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
));
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();
171 return getChildRole(child
, ChildRole
.LBRACE
);
173 else if (i
== RBRACE
) {
174 return getChildRole(child
, ChildRole
.RBRACE
);
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);
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
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
);
220 return PsiScopesUtil
.walkChildrenScopes(this, processor
, state
, lastParent
, place
);