Files
openide/java/java-frontback-psi-impl/src/com/intellij/psi/impl/source/BasicJavaAstTreeUtil.java
T
Max Medvedevandintellij-monorepo-bot c4d2a83d30 IDEA-359853 introduce JavaBinaryOperations
GitOrigin-RevId: 8c4cd1a8fb76a7c79bce882a669af0a057045ab0
2025-04-01 00:38:44 +00:00

805 lines
27 KiB
Java

// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.impl.source;
import com.intellij.lang.ASTNode;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.java.parser.JavaBinaryOperations;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ParentAwareTokenSet;
import com.intellij.psi.tree.ParentProviderElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.tree.java.IJavaDocElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static com.intellij.psi.JavaTokenType.JAVA_TOKEN_TYPE_SET;
import static com.intellij.psi.JavaTokenType.RPARENTH;
import static com.intellij.psi.impl.source.BasicElementTypes.BASIC_KEYWORD_BIT_SET;
import static com.intellij.psi.impl.source.BasicJavaDocElementType.BASIC_DOC_COMMENT;
import static com.intellij.psi.impl.source.BasicJavaDocElementType.BASIC_DOC_SNIPPET_ATTRIBUTE_VALUE;
import static com.intellij.psi.impl.source.BasicJavaElementType.*;
public final class BasicJavaAstTreeUtil {
private BasicJavaAstTreeUtil() { }
@Contract("null ,_ -> false")
public static boolean is(@Nullable ASTNode element, @Nullable IElementType iElementType) {
boolean notNull = element != null && iElementType != null;
if (!notNull) {
return false;
}
IElementType sourceElementType = element.getElementType();
return is(sourceElementType, iElementType);
}
public static boolean is(@NotNull IElementType source, @NotNull IElementType target) {
if (source == target) {
return true;
}
if (source instanceof ParentProviderElementType) {
Set<IElementType> parents = ((ParentProviderElementType)source).getParents();
return ContainerUtil.exists(parents, parent -> parent != null && is(parent, target));
}
return false;
}
@Contract("null ,_ -> false")
public static boolean is(@Nullable ASTNode element, @NotNull Set<IElementType> iElementTypes) {
boolean isNotNull = element != null;
if (!isNotNull) {
return false;
}
return is(element.getElementType(), iElementTypes);
}
//needs for FrontBackJavaTokenSet
public static boolean is(@Nullable ASTNode element, @NotNull TokenSet tokenSet) {
boolean isNotNull = element != null;
if (!isNotNull) {
return false;
}
return ParentProviderElementType.containsWithSourceParent(element.getElementType(), tokenSet);
}
public static boolean is(@Nullable ASTNode element, @NotNull ParentAwareTokenSet tokenSet) {
boolean isNotNull = element != null;
if (!isNotNull) {
return false;
}
return is(element.getElementType(), tokenSet);
}
private static boolean is(@NotNull IElementType source, @NotNull ParentAwareTokenSet tokenSet) {
//not call iteratively!
if (tokenSet.contains(source)) {
return true;
}
return false;
}
private static boolean is(@NotNull IElementType source, @NotNull Set<IElementType> tokenSet) {
if (tokenSet.contains(source)) {
return true;
}
if (source instanceof ParentProviderElementType) {
Set<IElementType> parents = ((ParentProviderElementType)source).getParents();
return ContainerUtil.exists(parents, parent -> parent != null && is(parent, tokenSet));
}
return false;
}
public static boolean is(@Nullable ASTNode element, IElementType... iElementTypes) {
return is(element, ParentAwareTokenSet.create(iElementTypes));
}
public static List<ASTNode> getChildren(@Nullable ASTNode element) {
ArrayList<ASTNode> results = new ArrayList<>();
if (element == null) {
return results;
}
for (ASTNode child = element.getFirstChildNode(); child != null; child = child.getTreeNext()) {
results.add(child);
}
return results;
}
public static @Nullable ASTNode getReferenceNameElement(@Nullable ASTNode element) {
if (element == null) {
return null;
}
IElementType type = element.getElementType();
if (is(type, BASIC_IMPORT_STATIC_REFERENCE)) {
return findChildByType(element, JavaTokenType.IDENTIFIER);
}
else if (is(type, BASIC_JAVA_CODE_REFERENCE)) {
return TreeUtil.findChildBackward(element, JavaTokenType.IDENTIFIER);
}
else if (is(type, BASIC_METHOD_REF_EXPRESSION)) {
final ASTNode lastChild = element.getLastChildNode();
return is(lastChild, JavaTokenType.IDENTIFIER) || is(lastChild, JavaTokenType.NEW_KEYWORD) ? lastChild : null;
}
else if (is(type, BASIC_REFERENCE_EXPRESSION)) {
ASTNode lastChild = element.getLastChildNode();
return lastChild == null || is(lastChild,
ContainerUtil.newHashSet(JavaTokenType.IDENTIFIER, JavaTokenType.THIS_KEYWORD,
JavaTokenType.SUPER_KEYWORD)) ?
lastChild : findChildByType(element, JavaTokenType.IDENTIFIER);
}
return null;
}
public static @Nullable ASTNode findChildByType(@Nullable ASTNode astNode, IElementType... targets) {
return findChildByType(astNode, ParentAwareTokenSet.create(targets));
}
public static @Nullable ASTNode findChildByType(@Nullable ASTNode astNode, Collection<IElementType> targets) {
return findChildByType(astNode, ParentAwareTokenSet.create(targets));
}
public static @Nullable ASTNode findChildByType(@Nullable ASTNode astNode, ParentAwareTokenSet targets) {
if (astNode == null) {
return null;
}
for (ASTNode child = astNode.getFirstChildNode(); child != null; child = child.getTreeNext()) {
IElementType elementType = child.getElementType();
if (is(elementType, targets)) return child;
}
return null;
}
public static @Nullable ASTNode getElseElement(@NotNull ASTNode element) {
if (!is(element, BASIC_IF_STATEMENT)) {
return null;
}
return findChildByType(element, JavaTokenType.ELSE_KEYWORD);
}
public static @Nullable ASTNode getThenBranch(@NotNull ASTNode element) {
if (!is(element, BASIC_IF_STATEMENT)) {
return null;
}
for (ASTNode child : getChildren(element)) {
if (is(child, STATEMENT_SET)) {
return child;
}
}
return null;
}
public static ASTNode getElseBranch(@Nullable ASTNode element) {
if (!is(element, BASIC_IF_STATEMENT)) {
return null;
}
ASTNode elseKeyword = getElseElement(element);
if (elseKeyword == null) return null;
for (ASTNode child = elseKeyword.getTreeNext(); child != null; child = child.getTreeNext()) {
if (is(child, STATEMENT_SET)) return child;
}
return null;
}
public static @Nullable ASTNode getLParenth(@Nullable ASTNode element) {
return findChildByType(element, JavaTokenType.LPARENTH);
}
public static @Nullable ASTNode getRParenth(@Nullable ASTNode element) {
return findChildByType(element, RPARENTH);
}
public static @Nullable ASTNode getFinallyBlock(@Nullable ASTNode element) {
if (!is(element, BASIC_TRY_STATEMENT)) {
return null;
}
ASTNode finallyKeyword = findChildByType(element, JavaTokenType.FINALLY_KEYWORD);
if (finallyKeyword == null) return null;
for (ASTNode child = finallyKeyword.getTreeNext(); child != null; child = child.getTreeNext()) {
if (is(child, BASIC_CODE_BLOCK)) {
return child;
}
}
return null;
}
public static @Nullable ASTNode getNameIdentifier(@Nullable ASTNode element) {
return findChildByType(element, JavaTokenType.IDENTIFIER);
}
public static @Nullable ASTNode getInitializer(@Nullable ASTNode element) {
return findChildByType(element, EXPRESSION_SET);
}
public static @Nullable ASTNode getDocComment(@Nullable ASTNode element) {
return findChildByType(element, BASIC_DOC_COMMENT);
}
public static @Nullable ASTNode getTypeElement(@Nullable ASTNode element) {
return findChildByType(element, BASIC_TYPE);
}
public static @Nullable ASTNode getModifierList(@Nullable ASTNode element) {
return findChildByType(element, BASIC_MODIFIER_LIST);
}
public static @Nullable ASTNode getLBrace(@Nullable ASTNode element) {
return findChildByType(element, JavaTokenType.LBRACE);
}
public static @Nullable ASTNode getRBrace(@Nullable ASTNode element) {
return findChildByType(element, JavaTokenType.RBRACE);
}
public static boolean isJavaToken(@Nullable ASTNode element) {
if (element == null) {
return false;
}
return toPsi(element) instanceof PsiJavaToken ||
is(element, JavaTokenType.IDENTIFIER) ||
isKeyword(element) ||
JAVA_TOKEN_TYPE_SET.contains(element.getElementType());
}
public static boolean isKeyword(@Nullable ASTNode element) {
return is(element, BASIC_KEYWORD_BIT_SET);
}
public static boolean isWhiteSpace(@Nullable ASTNode element) {
return is(element, TokenType.WHITE_SPACE);
}
public static @Nullable ASTNode skipSiblingsBackward(@Nullable ASTNode element,
IElementType... elementClasses) {
if (element != null) {
for (ASTNode e = element.getTreePrev(); e != null; e = e.getTreePrev()) {
if (!is(e, elementClasses)) {
return e;
}
}
}
return null;
}
public static @Nullable ASTNode skipSiblingsForward(@Nullable ASTNode element,
IElementType... elementClasses) {
if (element != null) {
for (ASTNode e = element.getTreeNext(); e != null; e = e.getTreeNext()) {
if (!is(e, elementClasses)) {
return e;
}
}
}
return null;
}
public static @Nullable PsiElement toPsi(@Nullable ASTNode astNode) {
return SourceTreeToPsiMap.treeElementToPsi(astNode);
}
public static @Nullable ASTNode toNode(@Nullable PsiElement psiElement) {
if (psiElement == null) {
return null;
}
return psiElement.getNode();
}
public static @Nullable ASTNode getParentOfType(@Nullable ASTNode e, @NotNull ParentAwareTokenSet set) {
if (e == null) {
return null;
}
return findParent(e, set);
}
private static @Nullable ASTNode findParent(@NotNull ASTNode element, @NotNull IElementType type) {
for (ASTNode parent = element.getTreeParent(); parent != null; parent = parent.getTreeParent()) {
if (is(parent.getElementType(), type)) return parent;
}
return null;
}
private static @Nullable ASTNode findParent(@NotNull ASTNode element, @NotNull ParentAwareTokenSet type) {
for (ASTNode parent = element.getTreeParent(); parent != null; parent = parent.getTreeParent()) {
if (is(parent.getElementType(), type)) return parent;
}
return null;
}
public static @Nullable ASTNode getParentOfType(@Nullable ASTNode e, @NotNull IElementType elementType) {
if (e == null) {
return null;
}
return findParent(e, elementType);
}
public static @Nullable ASTNode getMethodExpression(@Nullable ASTNode element) {
if (!is(element, BASIC_METHOD_CALL_EXPRESSION)) {
return null;
}
return element.getFirstChildNode();
}
public static @Nullable ASTNode getExpressionList(@Nullable ASTNode element) {
return findChildByType(element, BASIC_EXPRESSION_LIST);
}
public static @Nullable ASTNode getTypeParameterList(@Nullable ASTNode element) {
return findChildByType(element, BASIC_TYPE_PARAMETER_LIST);
}
public static boolean isComment(@Nullable ASTNode element) {
return is(element, BasicElementTypes.BASIC_JAVA_COMMENT_BIT_SET);
}
public static boolean isDocToken(@Nullable ASTNode element) {
return
element != null &&
element.getElementType().getClass().equals(IJavaDocElementType.class) &&
!is(element, BASIC_DOC_SNIPPET_ATTRIBUTE_VALUE);
}
public static @Nullable String getTagName(@Nullable ASTNode element) {
if (element == null) {
return null;
}
ASTNode docTagName = findChildByType(element, JavaDocTokenType.DOC_TAG_NAME);
if (docTagName == null) {
return null;
}
String text = docTagName.getText();
if (text.isEmpty()) {
return null;
}
return text.substring(1);
}
public static @Nullable ASTNode getROperand(@Nullable ASTNode element) {
if (element == null) {
return null;
}
if (!is(element, BASIC_BINARY_EXPRESSION)) {
return null;
}
return findChildByType(element, EXPRESSION_SET);
}
public static @Nullable ASTNode getBlock(@Nullable ASTNode statement) {
if (statement == null) return null;
return findChildByType(statement, STATEMENT_SET);
}
public static @Nullable ASTNode getAnonymousClass(@Nullable ASTNode expression) {
if (expression == null) return null;
return findChildByType(expression, BASIC_ANONYMOUS_CLASS);
}
@Contract("null, _, _, _ -> null")
public static @Nullable PsiElement getParentOfType(@Nullable PsiElement element,
@NotNull IElementType target,
boolean strict,
@Nullable ParentAwareTokenSet stopAt) {
if (element == null) return null;
if (strict) {
if (element instanceof PsiFile) return null;
element = element.getParent();
}
while (element != null && !is(element.getNode(), target)) {
if (stopAt != null && is(element.getNode(), stopAt)) return null;
if (element instanceof PsiFile) return null;
element = element.getParent();
}
return element;
}
public static @Nullable ASTNode findElementInRange(@NotNull PsiFile file, int startOffset, int endOffset, @NotNull IElementType elementType) {
PsiElement element1 = file.getViewProvider().findElementAt(startOffset, JavaLanguage.INSTANCE);
PsiElement element2 = file.getViewProvider().findElementAt(endOffset - 1, JavaLanguage.INSTANCE);
if (element1 instanceof PsiWhiteSpace) {
startOffset = element1.getTextRange().getEndOffset();
element1 = file.getViewProvider().findElementAt(startOffset, JavaLanguage.INSTANCE);
}
if (element2 instanceof PsiWhiteSpace) {
endOffset = element2.getTextRange().getStartOffset();
element2 = file.getViewProvider().findElementAt(endOffset - 1, JavaLanguage.INSTANCE);
}
if (element2 == null || element1 == null) return null;
final PsiElement commonParent = PsiTreeUtil.findCommonParent(element1, element2);
if (commonParent == null) {
return null;
}
ASTNode node = commonParent.getNode();
final ASTNode element = is(node, elementType) ? node : getParentOfType(node, elementType);
if (element == null || element.getTextRange().getStartOffset() != startOffset || element.getTextRange().getEndOffset() != endOffset) {
return null;
}
return element;
}
public static @Nullable ASTNode getForInitialization(@Nullable ASTNode forStatement) {
if (!is(forStatement, BASIC_FOR_STATEMENT)) {
return null;
}
ASTNode initialization = findChildByType(forStatement, STATEMENT_SET);
if (initialization == null) {
return null;
}
// should be inside parens
ASTNode paren = getLParenth(forStatement);
if (paren == null) {
return null;
}
for (ASTNode child = paren; child != null; child = child.getTreeNext()) {
if (child == initialization) return initialization;
if (is(child, RPARENTH)) return null;
}
return null;
}
@Contract(pure = true)
public static @Nullable ASTNode findElementOfClassAtOffset(@NotNull PsiFile file,
int offset,
@NotNull IElementType elementType,
boolean strictStart) {
PsiElement result = null;
for (PsiElement root : file.getViewProvider().getAllFiles()) {
PsiElement elementAt = root.findElementAt(offset);
if (elementAt != null) {
PsiElement parent = getParentOfType(elementAt, elementType, strictStart, null);
if (parent != null) {
TextRange range = parent.getTextRange();
if (!strictStart || range.getStartOffset() == offset) {
if (result == null || result.getTextRange().getEndOffset() > range.getEndOffset()) {
result = parent;
}
}
}
}
}
return result == null ? null : result.getNode();
}
public static @Nullable ASTNode getParentOfType(@Nullable ASTNode e, @NotNull ParentAwareTokenSet types, boolean strict) {
if (!strict && is(e, types)) {
return e;
}
return getParentOfType(e, types);
}
public static @Nullable PsiElement getParentOfType(@Nullable PsiElement e, @NotNull Set<IElementType> types, boolean strict) {
if (!strict && e != null && is(e.getNode(), types)) {
return e;
}
if (e == null) {
return null;
}
return toPsi(getParentOfType(e.getNode(), ParentAwareTokenSet.create(types)));
}
public static @Nullable ASTNode getCatchBlock(@Nullable ASTNode element) {
if (!is(element, BASIC_CATCH_SECTION)) {
return null;
}
return findChildByType(element, BASIC_CODE_BLOCK);
}
public static @Nullable ASTNode getParameter(@Nullable ASTNode element) {
return findChildByType(element, BASIC_PARAMETER);
}
public static @Nullable ASTNode getWhileKeyword(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return findChildByType(element, JavaTokenType.WHILE_KEYWORD);
}
public static @Nullable ASTNode getWhileCondition(@Nullable ASTNode element) {
if (!is(element, BASIC_DO_WHILE_STATEMENT) &&
!is(element, BASIC_WHILE_STATEMENT)) {
return null;
}
return findChildByType(element, EXPRESSION_SET);
}
public static @Nullable ASTNode getDoWhileBody(@Nullable ASTNode element) {
if (!is(element, BASIC_DO_WHILE_STATEMENT)) {
return null;
}
return findChildByType(element, STATEMENT_SET);
}
public static @Nullable ASTNode getForUpdate(@Nullable ASTNode statement) {
if (!is(statement, BASIC_FOR_STATEMENT)) {
return null;
}
ASTNode semicolon = findChildByType(statement, JavaTokenType.SEMICOLON);
if (semicolon == null) {
return null;
}
for (ASTNode child = semicolon; child != null; child = child.getTreeNext()) {
if (is(child, STATEMENT_SET)) {
return child;
}
if (is(child, RPARENTH)) break;
}
return null;
}
public static @Nullable ASTNode getForCondition(@Nullable ASTNode element) {
if (!is(element, BASIC_FOR_STATEMENT)) {
return null;
}
return findChildByType(element, EXPRESSION_SET);
}
public static @Nullable ASTNode getIfCondition(@Nullable ASTNode statement) {
if (!is(statement, BASIC_IF_STATEMENT)) {
return null;
}
return findChildByType(statement, EXPRESSION_SET);
}
public static boolean hasModifierProperty(@Nullable ASTNode element,
@NotNull IElementType property) {
if (element == null) {
return false;
}
ASTNode modifierList = findChildByType(element, BASIC_MODIFIER_LIST);
if (modifierList == null) {
return false;
}
ASTNode firstChild = modifierList.getFirstChildNode();
if (firstChild == null) {
return false;
}
for (ASTNode child = firstChild; child != null; child = child.getTreeNext()) {
if (is(child, property)) {
return true;
}
}
return false;
}
public static boolean isInterfaceEnumClassOrRecord(@Nullable ASTNode element,
@NotNull IElementType elementType) {
if (!is(element, CLASS_SET)) {
return false;
}
if (element == null) {
return false;
}
ASTNode firstChild = element.getFirstChildNode();
if (firstChild == null) {
return false;
}
for (ASTNode child = firstChild; child != null; child = child.getTreeNext()) {
if (is(child, elementType)) return true;
}
return false;
}
public static ASTNode @Nullable [] getParameterListParameters(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return getChildren(element).stream().filter(ch -> is(ch, BASIC_PARAMETER)).toArray(ASTNode[]::new);
}
public static ASTNode @Nullable [] getAnnotationParameterListAttributes(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return getChildren(element).stream().filter(ch -> is(ch, BASIC_NAME_VALUE_PAIR)).toArray(ASTNode[]::new);
}
public static @Nullable ASTNode getFirstBodyElement(@Nullable ASTNode block) {
if (block == null) {
return null;
}
final ASTNode lBrace = getLBrace(block);
if (lBrace == null) return null;
final ASTNode nextSibling = lBrace.getTreeNext();
return nextSibling == getRBrace(block) ? null : nextSibling;
}
public static @Nullable ASTNode getCodeBlock(@Nullable ASTNode element) {
if (element == null) return null;
return findChildByType(element, BASIC_CODE_BLOCK);
}
public static @Nullable ASTNode getForBody(@Nullable ASTNode element) {
if (element == null) {
return null;
}
ASTNode rparenth = getRParenth(element);
if (rparenth == null) {
return null;
}
for (ASTNode child = rparenth; child != null; child = child.getTreeNext()) {
if (is(child, STATEMENT_SET)) {
return child;
}
}
return null;
}
public static ASTNode[] getCatchBlocks(@Nullable ASTNode element) {
ASTNode tryBlock = getCodeBlock(element);
if (tryBlock != null) {
final List<ASTNode> catchSections = ContainerUtil.filter(getChildren(element), ch -> is(ch, BASIC_CATCH_SECTION));
return catchSections.stream()
.map(t -> getCatchBlock(t))
.filter(t -> t != null)
.toArray(ASTNode[]::new);
}
return ASTNode.EMPTY_ARRAY;
}
public static @Nullable ASTNode getConditionalExpressionThenExpression(@Nullable ASTNode element) {
if (element == null) {
return null;
}
ASTNode quest = findChildByType(element, JavaTokenType.QUEST);
if (quest == null) {
return null;
}
ASTNode child = quest.getTreeNext();
while (true) {
if (child == null) return null;
if (EXPRESSION_SET.contains(child.getElementType())) break;
child = child.getTreeNext();
}
return child;
}
public static @Nullable IElementType getAssignmentOperationTokenType(@Nullable ASTNode expr) {
if (expr == null) {
return null;
}
ASTNode ASTNode = findChildByType(expr, JavaBinaryOperations.ASSIGNMENT_OPS.getTypes());
if (ASTNode == null) {
return null;
}
return ASTNode.getElementType();
}
public static @Nullable ASTNode getPatternVariable(@Nullable ASTNode ASTNode) {
if (ASTNode == null) {
return null;
}
return findChildByType(ASTNode, BASIC_DECONSTRUCTION_PATTERN_VARIABLE, BASIC_PATTERN_VARIABLE);
}
public static @Nullable ASTNode getExpression(@Nullable ASTNode ASTNode) {
if (ASTNode == null) {
return null;
}
return findChildByType(ASTNode, EXPRESSION_SET);
}
public static @Nullable ASTNode getRecordComponentContainingClass(@Nullable ASTNode element) {
if (element == null) {
return null;
}
ASTNode parent = element.getTreeParent();
if (parent == null) {
return null;
}
ASTNode grandParent = parent.getTreeParent();
if (is(grandParent, CLASS_SET)) {
return grandParent;
}
return null;
}
public static @Nullable ASTNode getRecordHeader(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return findChildByType(element, BASIC_RECORD_HEADER);
}
public static @Nullable ASTNode getRuleBody(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return findChildByType(element, ParentAwareTokenSet.orSet(
ParentAwareTokenSet.create(BASIC_BLOCK_STATEMENT, BASIC_THROW_STATEMENT), EXPRESSION_SET));
}
public static @Nullable ASTNode getCaseLabelElementList(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return findChildByType(element, BASIC_CASE_LABEL_ELEMENT_LIST);
}
public static @Nullable ASTNode getReturnValue(@Nullable ASTNode element) {
if (element == null) {
return null;
}
return findChildByType(element, EXPRESSION_SET);
}
public static @Nullable ASTNode getForEachIteratedValue(@Nullable ASTNode statement) {
if (!is(statement, BASIC_FOREACH_STATEMENT)) {
return null;
}
return findChildByType(statement, EXPRESSION_SET);
}
public static @Nullable ASTNode getForEachIterationParameter(@Nullable ASTNode statement) {
if (statement == null) {
return null;
}
if (!is(statement, BASIC_FOREACH_STATEMENT)) {
return null;
}
return findChildByType(statement, BASIC_PARAMETER);
}
public static @Nullable ASTNode getForeachBody(@Nullable ASTNode statement) {
if (statement == null) {
return null;
}
if (!is(statement, BASIC_FOREACH_STATEMENT)) {
return null;
}
return findChildByType(statement, STATEMENT_SET);
}
public static @Nullable ASTNode getWhileBody(@Nullable ASTNode statement) {
if (statement == null) {
return null;
}
if (!is(statement, BASIC_WHILE_STATEMENT)) {
return null;
}
return findChildByType(statement, STATEMENT_SET);
}
public static boolean hasErrorElements(@Nullable ASTNode node) {
return !SyntaxTraverser.astTraverser(node).traverse()
.filter(t -> is(t, TokenType.ERROR_ELEMENT)).isEmpty();
}
public static int getTextOffset(@NotNull ASTNode node) {
if (is(node, BASIC_LOCAL_VARIABLE, BASIC_PATTERN_VARIABLE, BASIC_RECORD_COMPONENT,
BASIC_RECEIVER_PARAMETER, BASIC_MODULE,
BASIC_IMPORT_STATIC_REFERENCE, BASIC_JAVA_CODE_REFERENCE)) {
ASTNode identifier = findChildByType(node, JavaTokenType.IDENTIFIER);
if (identifier != null) {
return identifier.getStartOffset();
}
}
if (is(node, BASIC_REFERENCE_EXPRESSION)) {
ASTNode identifier = findChildByType(node, JavaTokenType.IDENTIFIER, JavaTokenType.THIS_KEYWORD, JavaTokenType.SUPER_KEYWORD);
if (identifier != null) {
return identifier.getStartOffset();
}
}
ASTNode doc = findChildByType(node, JavaDocTokenType.DOC_TAG_VALUE_TOKEN);
if (doc != null) {
return doc.getStartOffset();
}
return node.getStartOffset();
}
}