blob: 39300b5141106cf9434ea15fc60e5d236e262e92 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.ArrayFactory;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* The common base interface for all elements of the PSI tree.
* <p/>
* Please see <a href="http://confluence.jetbrains.net/display/IDEADEV/IntelliJ+IDEA+Architectural+Overview">IntelliJ IDEA Architectural Overview </a>
* for high-level overview.
*/
public interface PsiElement extends UserDataHolder, Iconable {
/**
* The empty array of PSI elements which can be reused to avoid unnecessary allocations.
*/
PsiElement[] EMPTY_ARRAY = new PsiElement[0];
ArrayFactory<PsiElement> ARRAY_FACTORY = new ArrayFactory<PsiElement>() {
@NotNull
@Override
public PsiElement[] create(final int count) {
return count == 0 ? EMPTY_ARRAY : new PsiElement[count];
}
};
/**
* Returns the project to which the PSI element belongs.
*
* @return the project instance.
* @throws PsiInvalidElementAccessException
* if this element is invalid
*/
@NotNull
Project getProject() throws PsiInvalidElementAccessException;
/**
* Returns the language of the PSI element.
*
* @return the language instance.
*/
@NotNull
Language getLanguage();
/**
* Returns the PSI manager for the project to which the PSI element belongs.
*
* @return the PSI manager instance.
*/
PsiManager getManager();
/**
* Returns the array of children for the PSI element.
* Important: In some implementations children are only composite elements, i.e. not a leaf elements
*
* @return the array of child elements.
*/
@NotNull
PsiElement[] getChildren();
/**
* Returns the parent of the PSI element.
*
* @return the parent of the element, or null if the element has no parent.
*/
PsiElement getParent();
/**
* Returns the first child of the PSI element.
*
* @return the first child, or null if the element has no children.
*/
PsiElement getFirstChild();
/**
* Returns the last child of the PSI element.
*
* @return the last child, or null if the element has no children.
*/
PsiElement getLastChild();
/**
* Returns the next sibling of the PSI element.
*
* @return the next sibling, or null if the node is the last in the list of siblings.
*/
PsiElement getNextSibling();
/**
* Returns the previous sibling of the PSI element.
*
* @return the previous sibling, or null if the node is the first in the list of siblings.
*/
PsiElement getPrevSibling();
/**
* Returns the file containing the PSI element.
*
* @return the file instance, or null if the PSI element is not contained in a file (for example,
* the element represents a package or directory).
* @throws PsiInvalidElementAccessException
* if this element is invalid
*/
PsiFile getContainingFile() throws PsiInvalidElementAccessException;
/**
* Returns the text range in the document occupied by the PSI element.
*
* @return the text range.
*/
TextRange getTextRange();
/**
* Returns the text offset of the PSI element relative to its parent.
*
* @return the relative offset.
*/
int getStartOffsetInParent();
/**
* Returns the length of text of the PSI element.
*
* @return the text length.
*/
int getTextLength();
/**
* Finds a leaf PSI element at the specified offset from the start of the text range of this node.
*
* @param offset the relative offset for which the PSI element is requested.
* @return the element at the offset, or null if none is found.
*/
@Nullable
PsiElement findElementAt(int offset);
/**
* Finds a reference at the specified offset from the start of the text range of this node.
*
* @param offset the relative offset for which the reference is requested.
* @return the reference at the offset, or null if none is found.
*/
@Nullable
PsiReference findReferenceAt(int offset);
/**
* Returns the offset in the file to which the caret should be placed
* when performing the navigation to the element. (For classes implementing
* {@link PsiNamedElement}, this should return the offset in the file of the
* name identifier.)
*
* @return the offset of the PSI element.
*/
int getTextOffset();
/**
* Returns the text of the PSI element.
*
* @return the element text.
*/
@NonNls
String getText();
/**
* Returns the text of the PSI element as a character array.
*
* @return the element text as a character array.
*/
@NotNull
char[] textToCharArray();
/**
* Returns the PSI element which should be used as a navigation target
* when navigation to this PSI element is requested. The method can either
* return <code>this</code> or substitute a different element if this element
* does not have an associated file and offset. (For example, if the source code
* of a library is attached to a project, the navigation element for a compiled
* library class is its source class.)
*
* @return the navigation target element.
*/
PsiElement getNavigationElement();
/**
* Returns the PSI element which corresponds to this element and belongs to
* either the project source path or class path. The method can either return
* <code>this</code> or substitute a different element if this element does
* not belong to the source path or class path. (For example, the original
* element for a library source file is the corresponding compiled class file.)
*
* @return the original element.
*/
PsiElement getOriginalElement();
//Q: get rid of these methods?
/**
* Checks if the text of this PSI element is equal to the specified character sequence.
*
* @param text the character sequence to compare with.
* @return true if the text is equal, false otherwise.
*/
boolean textMatches(@NotNull @NonNls CharSequence text);
/**
* Checks if the text of this PSI element is equal to the text of the specified PSI element.
*
* @param element the element to compare the text with.
* @return true if the text is equal, false otherwise.
*/
boolean textMatches(@NotNull PsiElement element);
/**
* Checks if the text of this element contains the specified character.
*
* @param c the character to search for.
* @return true if the character is found, false otherwise.
*/
boolean textContains(char c);
/**
* Passes the element to the specified visitor.
*
* @param visitor the visitor to pass the element to.
*/
void accept(@NotNull PsiElementVisitor visitor);
/**
* Passes the children of the element to the specified visitor.
*
* @param visitor the visitor to pass the children to.
*/
void acceptChildren(@NotNull PsiElementVisitor visitor);
/**
* Creates a copy of the file containing the PSI element and returns the corresponding
* element in the created copy. Resolve operations performed on elements in the copy
* of the file will resolve to elements in the copy, not in the original file.
*
* @return the element in the file copy corresponding to this element.
*/
PsiElement copy();
/**
* Adds a child to this PSI element.
*
* @param element the child element to add.
* @return the element which was actually added (either <code>element</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException;
/**
* Adds a child to this PSI element, before the specified anchor element.
*
* @param element the child element to add.
* @param anchor the anchor before which the child element is inserted (must be a child of this PSI element)
* @return the element which was actually added (either <code>element</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement addBefore(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException;
/**
* Adds a child to this PSI element, after the specified anchor element.
*
* @param element the child element to add.
* @param anchor the anchor after which the child element is inserted (must be a child of this PSI element)
* @return the element which was actually added (either <code>element</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement addAfter(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException;
/**
* Checks if it is possible to add the specified element as a child to this element,
* and throws an exception if the add is not possible. Does not actually modify anything.
*
* @param element the child element to check the add possibility.
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
* @deprecated not all PSI implementations implement this method correctly.
*/
void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException;
/**
* Adds a range of elements as children to this PSI element.
*
* @param first the first child element to add.
* @param last the last child element to add (must have the same parent as <code>first</code>)
* @return the first child element which was actually added (either <code>first</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException;
/**
* Adds a range of elements as children to this PSI element, before the specified anchor element.
*
* @param first the first child element to add.
* @param last the last child element to add (must have the same parent as <code>first</code>)
* @param anchor the anchor before which the child element is inserted (must be a child of this PSI element)
* @return the first child element which was actually added (either <code>first</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement addRangeBefore(@NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException;
/**
* Adds a range of elements as children to this PSI element, after the specified anchor element.
*
* @param first the first child element to add.
* @param last the last child element to add (must have the same parent as <code>first</code>)
* @param anchor the anchor after which the child element is inserted (must be a child of this PSI element)
* @return the first child element which was actually added (either <code>first</code> or its copy).
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement addRangeAfter(PsiElement first, PsiElement last, PsiElement anchor) throws IncorrectOperationException;
/**
* Deletes this PSI element from the tree.
*
* @throws IncorrectOperationException if the modification is not supported
* or not possible for some reason (for example, the file containing the element is read-only).
*/
void delete() throws IncorrectOperationException;
/**
* Checks if it is possible to delete the specified element from the tree,
* and throws an exception if the add is not possible. Does not actually modify anything.
*
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
* @deprecated not all PSI implementations implement this method correctly.
*/
void checkDelete() throws IncorrectOperationException;
/**
* Deletes a range of children of this PSI element from the tree.
*
* @param first the first child to delete (must be a child of this PSI element)
* @param last the last child to delete (must be a child of this PSI element)
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException;
/**
* Replaces this PSI element (along with all its children) with another element
* (along with the children).
*
* @param newElement the element to replace this element with.
* @return the element which was actually inserted in the tree (either <code>newElement</code> or its copy)
* @throws IncorrectOperationException if the modification is not supported or not possible for some reason.
*/
PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException;
/**
* Checks if this PSI element is valid. Valid elements and their hierarchy members
* can be accessed for reading and writing. Valid elements can still correspond to
* underlying documents whose text is different, when those documents have been changed
* and not yet committed ({@link com.intellij.psi.PsiDocumentManager#commitDocument(com.intellij.openapi.editor.Document)}).
* (In this case an attempt to change PSI will result in an exception).
*
* Any access to invalid elements results in {@link com.intellij.psi.PsiInvalidElementAccessException}.
*
* Once invalid, elements can't become valid again.
*
* Elements become invalid in following cases:
* <ul>
* <li>They have been deleted via PSI operation ({@link #delete()})</li>
* <li>They have been deleted as a result of an incremental reparse (document commit)</li>
* <li>Their containing file has been changed externally, or renamed so that its PSI had to be rebuilt from scratch</li>
* </ul>
*
* @return true if the element is valid, false otherwise.
* @see com.intellij.psi.util.PsiUtilCore#ensureValid(PsiElement)
*/
boolean isValid();
/**
* Checks if the contents of the element can be modified (if it belongs to a
* non-read-only source file.)
*
* @return true if the element can be modified, false otherwise.
*/
boolean isWritable();
/**
* Returns the reference associated with this PSI element. If the element has multiple
* associated references (see {@link #getReferences()} for an example), returns the first
* associated reference.
*
* @return the reference instance, or null if the PSI element does not have any
* associated references.
*/
@Nullable
PsiReference getReference();
/**
* Returns all references associated with this PSI element. An element can be associated
* with multiple references when, for example, the element is a string literal containing
* multiple sub-strings which are valid full-qualified class names. If an element
* contains only one text fragment which acts as a reference but the reference has
* multiple possible targets, {@link PsiPolyVariantReference} should be used instead
* of returning multiple references.
* <p/>
* Actually, it's preferable to call {@link com.intellij.psi.PsiReferenceService#getReferences} instead
* as it allows adding references by plugins when the element implements {@link com.intellij.psi.ContributedReferenceHost}.
*
* @return the array of references, or an empty array if the element has no associated
* references.
* @see com.intellij.psi.PsiReferenceService#getReferences
*/
@NotNull
PsiReference[] getReferences();
/**
* Returns a copyable user data object attached to this element.
*
* @param key the key for accessing the user data object.
* @return the user data object, or null if no such object is found in the current element.
* @see #putCopyableUserData(com.intellij.openapi.util.Key, Object)
*/
@Nullable
<T> T getCopyableUserData(Key<T> key);
/**
* Attaches a copyable user data object to this element. Copyable user data objects are copied
* when the PSI elements are copied.
*
* @param key the key for accessing the user data object.
* @param value the user data object to attach.
* @see #getCopyableUserData(com.intellij.openapi.util.Key)
*/
<T> void putCopyableUserData(Key<T> key, @Nullable T value);
/**
* Passes the declarations contained in this PSI element and its children
* for processing to the specified scope processor.
*
* @param processor the processor receiving the declarations.
* @param lastParent the child of this element has been processed during the previous
* step of the tree up walk (declarations under this element do not need
* to be processed again)
* @param place the original element from which the tree up walk was initiated.
* @return true if the declaration processing should continue or false if it should be stopped.
*/
boolean processDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
@Nullable PsiElement lastParent,
@NotNull PsiElement place);
/**
* Returns the element which should be used as the parent of this element in a tree up
* walk during a resolve operation. For most elements, this returns <code>getParent()</code>,
* but the context can be overridden for some elements like code fragments (see
* {@link PsiElementFactory#createCodeBlockCodeFragment(String, PsiElement, boolean)}).
*
* @return the resolve context element.
*/
@Nullable
PsiElement getContext();
/**
* Checks if an actual source or class file corresponds to the element. Non-physical elements include,
* for example, PSI elements created for the watch expressions in the debugger.
* Non-physical elements do not generate tree change events.
* Also, {@link PsiDocumentManager#getDocument(PsiFile)} returns null for non-physical elements.
*
* @return true if the element is physical, false otherwise.
*/
boolean isPhysical();
/**
* Returns the scope in which the declarations for the references in this PSI element are searched.
*
* @return the resolve scope instance.
*/
@NotNull
GlobalSearchScope getResolveScope();
/**
* Returns the scope in which references to this element are searched.
*
* @return the search scope instance.
* @see {@link com.intellij.psi.search.PsiSearchHelper#getUseScope(PsiElement)}
*/
@NotNull
SearchScope getUseScope();
/**
* Returns the AST node corresponding to the element.
*
* @return the AST node instance.
*/
ASTNode getNode();
/**
* toString() should never be presented to the user.
*/
@NonNls
String toString();
boolean isEquivalentTo(PsiElement another);
}