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
.compiled
;
18 import com
.intellij
.lang
.ASTNode
;
19 import com
.intellij
.lang
.Language
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
22 import com
.intellij
.openapi
.util
.Key
;
23 import com
.intellij
.openapi
.util
.TextRange
;
24 import com
.intellij
.psi
.*;
25 import com
.intellij
.psi
.codeStyle
.CodeStyleSettingsManager
;
26 import com
.intellij
.psi
.impl
.PsiElementBase
;
27 import com
.intellij
.psi
.impl
.source
.SourceTreeToPsiMap
;
28 import com
.intellij
.psi
.impl
.source
.tree
.TreeElement
;
29 import com
.intellij
.psi
.tree
.IElementType
;
30 import com
.intellij
.psi
.util
.PsiTreeUtil
;
31 import com
.intellij
.util
.IncorrectOperationException
;
32 import org
.jetbrains
.annotations
.NotNull
;
34 public abstract class ClsElementImpl
extends PsiElementBase
implements PsiCompiledElement
{
35 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.compiled.ClsElementImpl");
36 private static final boolean CHECK_MIRROR_ENABLED
= false;
37 protected static final Object LAZY_BUILT_LOCK
= new String("lazy cls tree initialization lock");
38 public static final Key
<PsiCompiledElement
> COMPILED_ELEMENT
= Key
.create("COMPILED_ELEMENT");
40 private TreeElement myMirror
= null;
43 public Language
getLanguage() {
44 return StdFileTypes
.JAVA
.getLanguage();
47 public PsiManager
getManager() {
48 return getParent().getManager();
51 public PsiFile
getContainingFile() {
52 PsiElement parent
= getParent();
54 if (!isValid()) throw new PsiInvalidElementAccessException(this);
57 return parent
.getContainingFile();
60 public final boolean isWritable() {
64 public boolean isPhysical() {
68 public boolean isValid() {
69 PsiElement parent
= getParent();
70 return parent
!= null && parent
.isValid();
73 public PsiElement
copy() {
77 public void checkAdd(@NotNull PsiElement element
) throws IncorrectOperationException
{
78 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
81 public PsiElement
add(@NotNull PsiElement element
) throws IncorrectOperationException
{
82 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
85 public PsiElement
addBefore(@NotNull PsiElement element
, PsiElement anchor
) throws IncorrectOperationException
{
86 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
89 public PsiElement
addAfter(@NotNull PsiElement element
, PsiElement anchor
) throws IncorrectOperationException
{
90 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
93 public void delete() throws IncorrectOperationException
{
94 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
97 public void checkDelete() throws IncorrectOperationException
{
98 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
101 public PsiElement
replace(@NotNull PsiElement newElement
) throws IncorrectOperationException
{
102 throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE
);
105 protected static final String CAN_NOT_MODIFY_MESSAGE
= PsiBundle
.message("psi.error.attempt.to.edit.class.file");
107 public abstract void appendMirrorText(final int indentLevel
, final StringBuffer buffer
);
109 protected static void goNextLine(int indentLevel
, StringBuffer buffer
) {
111 for (int i
= 0; i
< indentLevel
; i
++) buffer
.append(' ');
114 protected int getIndentSize() {
115 return CodeStyleSettingsManager
.getSettings(getProject()).getIndentSize(StdFileTypes
.JAVA
);
118 public abstract void setMirror(@NotNull TreeElement element
);
120 public PsiElement
getMirror() {
121 synchronized (ClsFileImpl
.MIRROR_LOCK
) {
122 if (myMirror
== null) {
123 final ClsFileImpl file
= (ClsFileImpl
)getContainingFile();
126 return SourceTreeToPsiMap
.treeElementToPsi(myMirror
);
130 public final TextRange
getTextRange() {
131 PsiElement mirror
= getMirror();
132 return mirror
!= null ? mirror
.getTextRange() : new TextRange(0, 0);
135 public final int getStartOffsetInParent() {
136 PsiElement mirror
= getMirror();
137 return mirror
!= null ? mirror
.getStartOffsetInParent() : -1;
140 public int getTextLength() {
141 String text
= getText();
143 LOG
.error("getText() == null, element = " + this + ", parent = " + getParent());
146 return text
.length();
149 public PsiElement
findElementAt(int offset
) {
150 PsiElement mirrorAt
= getMirror().findElementAt(offset
);
152 if (mirrorAt
== null) return null;
153 PsiElement elementAt
= mirrorToElement(mirrorAt
);
154 if (elementAt
!= null) return elementAt
;
155 mirrorAt
= mirrorAt
.getParent();
159 PsiElement[] children = getChildren();
160 if (children.length == 0) return this;
161 for(int i = 0; i < children.length; i++){
162 int start = children[i].getStartOffsetInParent();
163 if (offset < start) return null;
164 int end = start + children[i].getTextLength();
166 return children[i].findElementAt(offset - start);
173 public PsiReference
findReferenceAt(int offset
) {
174 PsiReference mirrorRef
= getMirror().findReferenceAt(offset
);
175 if (mirrorRef
== null) return null;
176 PsiElement mirrorElement
= mirrorRef
.getElement();
177 PsiElement element
= mirrorToElement(mirrorElement
);
178 if (element
== null) return null;
179 return element
.getReference();
182 private PsiElement
mirrorToElement(PsiElement mirror
) {
183 final PsiElement m
= getMirror();
184 if (m
== mirror
) return this;
186 PsiElement
[] children
= getChildren();
187 if (children
.length
== 0) return null;
189 for (PsiElement child
: children
) {
190 ClsElementImpl clsChild
= (ClsElementImpl
)child
;
191 if (PsiTreeUtil
.isAncestor(clsChild
.getMirror(), mirror
, false)) {
192 PsiElement element
= clsChild
.mirrorToElement(mirror
);
193 if (element
!= null) return element
;
200 public final int getTextOffset() {
201 PsiElement mirror
= getMirror();
202 return mirror
!= null ? mirror
.getTextOffset() : -1;
205 public String
getText() {
206 PsiElement mirror
= getMirror();
207 return mirror
!= null ? mirror
.getText() : null;
211 public char[] textToCharArray() {
212 return getMirror().textToCharArray();
215 public boolean textMatches(@NotNull CharSequence text
) {
216 return getText().equals(text
.toString());
219 public boolean textMatches(@NotNull PsiElement element
) {
220 return getText().equals(element
.getText());
224 public PsiElement
getNavigationElement() {
228 public PsiElement
getOriginalElement() {
232 public ASTNode
getNode() {
236 protected void setMirrorCheckingType(@NotNull TreeElement element
, IElementType type
) {
237 if (CHECK_MIRROR_ENABLED
) {
238 LOG
.assertTrue(myMirror
== null);
242 LOG
.assertTrue(element
.getElementType() == type
);
245 element
.putUserData(COMPILED_ELEMENT
, this);