@Override public boolean flip(PsiElement left, PsiElement right) { if (left instanceof PsiVariable && right instanceof PsiVariable) { final PsiElement first = left.getFirstChild(); if (!(first instanceof PsiModifierList)) { return false; } final PsiElement child = PsiTreeUtil.skipSiblingsForward(first, PsiWhiteSpace.class); if (!(child instanceof PsiTypeElement)) { return false; } final PsiElement last = child.getNextSibling(); if (!(last instanceof PsiWhiteSpace)) { return false; } final PsiElement anchor = right.getFirstChild(); if (!(anchor instanceof PsiIdentifier)) { return false; } final PsiElement semiColon = right.getLastChild(); if (!(semiColon instanceof PsiJavaToken)) { return false; } right.addRangeBefore(first, last, anchor); left.deleteChildRange(first, last); left.add(semiColon); semiColon.delete(); final PsiElement copy = left.copy(); left.replace(right); right.replace(copy); return true; } return false; }
@Override public void visitElement(PsiElement element) { super.visitElement(element); final EquivalenceDescriptorProvider descriptorProvider = EquivalenceDescriptorProvider.getInstance(element); if (descriptorProvider != null) { final EquivalenceDescriptor descriptor1 = descriptorProvider.buildDescriptor(element); final EquivalenceDescriptor descriptor2 = descriptorProvider.buildDescriptor(myGlobalVisitor.getElement()); if (descriptor1 != null && descriptor2 != null) { final boolean result = DuplocatorUtil.match( descriptor1, descriptor2, myGlobalVisitor, Collections.<PsiElementRole>emptySet(), null); myGlobalVisitor.setResult(result); return; } } if (isLiteral(element)) { visitLiteral(element); return; } if (canBePatternVariable(element) && myGlobalVisitor.getMatchContext().getPattern().isRealTypedVar(element) && !shouldIgnoreVarNode(element)) { PsiElement matchedElement = myGlobalVisitor.getElement(); PsiElement newElement = SkippingHandler.skipNodeIfNeccessary(matchedElement); while (newElement != matchedElement) { matchedElement = newElement; newElement = SkippingHandler.skipNodeIfNeccessary(matchedElement); } myGlobalVisitor.setResult(myGlobalVisitor.handleTypedElement(element, matchedElement)); } else if (element instanceof LeafElement) { myGlobalVisitor.setResult(element.getText().equals(myGlobalVisitor.getElement().getText())); } else if (element.getFirstChild() == null && element.getTextLength() == 0) { myGlobalVisitor.setResult(true); } else { PsiElement patternChild = element.getFirstChild(); PsiElement matchedChild = myGlobalVisitor.getElement().getFirstChild(); FilteringNodeIterator patternIterator = new SsrFilteringNodeIterator(patternChild); FilteringNodeIterator matchedIterator = new SsrFilteringNodeIterator(matchedChild); boolean matched = myGlobalVisitor.matchSequentially(patternIterator, matchedIterator); myGlobalVisitor.setResult(matched); } }
public boolean matchSonsOptionally(final PsiElement element, final PsiElement element2) { if (element == null && isLeftLooseMatching()) { return true; } if (element2 == null && isRightLooseMatching()) { return true; } if (element == null || element2 == null) { return element == element2; } return matchSequentiallyOptionally(element.getFirstChild(), element2.getFirstChild()); }
@NotNull private static Collection<PsiLanguageInjectionHost> collectInjectionHosts( @NotNull PsiFile file, @NotNull TextRange range) { Stack<PsiElement> toProcess = new Stack<PsiElement>(); for (PsiElement e = file.findElementAt(range.getStartOffset()); e != null; e = e.getNextSibling()) { if (e.getTextRange().getStartOffset() >= range.getEndOffset()) { break; } toProcess.push(e); } if (toProcess.isEmpty()) { return Collections.emptySet(); } Set<PsiLanguageInjectionHost> result = null; while (!toProcess.isEmpty()) { PsiElement e = toProcess.pop(); if (e instanceof PsiLanguageInjectionHost) { if (result == null) { result = ContainerUtilRt.newHashSet(); } result.add((PsiLanguageInjectionHost) e); } else { for (PsiElement child = e.getFirstChild(); child != null; child = child.getNextSibling()) { if (e.getTextRange().getStartOffset() >= range.getEndOffset()) { break; } toProcess.push(child); } } } return result == null ? Collections.<PsiLanguageInjectionHost>emptySet() : result; }
/** * Get array string values mapped with their PsiElements * * <p>["value", "value2"] */ @NotNull public static Map<String, PsiElement> getArrayValuesAsMap( @NotNull ArrayCreationExpression arrayCreationExpression) { List<PsiElement> arrayValues = PhpPsiUtil.getChildren( arrayCreationExpression, new Condition<PsiElement>() { @Override public boolean value(PsiElement psiElement) { return psiElement.getNode().getElementType() == PhpElementTypes.ARRAY_VALUE; } }); if (arrayValues == null) { return Collections.emptyMap(); } Map<String, PsiElement> keys = new HashMap<String, PsiElement>(); for (PsiElement child : arrayValues) { String stringValue = PhpElementsUtil.getStringValue(child.getFirstChild()); if (stringValue != null && StringUtils.isNotBlank(stringValue)) { keys.put(stringValue, child); } } return keys; }
private static boolean isPossibleEmptyAttrs(PsiElement attrs) { if (!(attrs instanceof BnfParenExpression)) return false; if (attrs.getFirstChild().getNode().getElementType() != BnfTypes.BNF_LEFT_BRACE) return false; if (!(((BnfParenExpression) attrs).getExpression() instanceof BnfReferenceOrToken)) return false; return isLastInRuleOrFree(attrs); }
public static PsiElement getChild( final PsiElement parent, int position, boolean ignoreWhiteSpaces, boolean ignoreComments, boolean ignoreErrors) { PsiElement curChild = parent.getFirstChild(); int i = 0; while (i <= position && curChild != null) { if (WHITE_SPACES.contains(curChild.getNode().getElementType())) { if (!ignoreWhiteSpaces) i++; curChild = curChild.getNextSibling(); } else if (COMMENTS.contains(curChild.getNode().getElementType())) { if (!ignoreComments) i++; curChild = curChild.getNextSibling(); } else if (curChild instanceof PsiErrorElement) { if (!ignoreErrors) { return null; } i++; curChild = curChild.getNextSibling(); } else { if (i == position) return curChild; i++; curChild = curChild.getNextSibling(); } } return null; }
private static boolean isBlockElement(@NotNull PsiElement element) { PsiElement firstChild = element.getFirstChild(); PsiElement lastChild = element.getLastChild(); return firstChild != null && "{".equals(firstChild.getText()) && lastChild != null && "}".equals(lastChild.getText()); }
private static void addFoldingDescriptorsFromChildren( List<FoldingDescriptor> descriptors, PsiElement tag, @NotNull Document document) { for (PsiElement child = tag.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof CfmlCompositeElement || child instanceof PsiComment) { addFoldingDescriptors(descriptors, child, document); } } }
public static void changeModifier( PsiElement element, @Nullable JetModifierList modifierList, @Nullable PsiElement insertAnchor, JetToken[] modifiersThatCanBeReplaced, Project project, boolean toBeginning, JetModifierList listWithModifier) { PsiElement whiteSpace = JetPsiFactory.createWhiteSpace(project); if (modifierList == null) { if (listWithModifier != null) { if (insertAnchor != null) { listWithModifier = (JetModifierList) element.addBefore(listWithModifier, insertAnchor); element.addBefore(whiteSpace, insertAnchor); element.addBefore(whiteSpace, listWithModifier); } else { PsiElement firstChild = element.getFirstChild(); element.addBefore(listWithModifier, firstChild); element.addBefore(whiteSpace, firstChild); } } } else { boolean replaced = false; if (modifiersThatCanBeReplaced != null) { PsiElement toBeReplaced = null; PsiElement toReplace = null; for (JetToken modifierThatCanBeReplaced : modifiersThatCanBeReplaced) { if (modifierList.hasModifier(modifierThatCanBeReplaced)) { PsiElement modifierElement = modifierList.getModifierNode(modifierThatCanBeReplaced).getPsi(); assert modifierElement != null; if (!replaced && listWithModifier != null) { toBeReplaced = modifierElement; toReplace = listWithModifier.getFirstChild(); // modifierElement.replace(listWithModifier.getFirstChild()); replaced = true; } else { modifierList.deleteChildInternal(modifierElement.getNode()); } } } if (toBeReplaced != null && toReplace != null) { toBeReplaced.replace(toReplace); } } if (!replaced && listWithModifier != null) { if (toBeginning) { PsiElement firstChild = modifierList.getFirstChild(); modifierList.addBefore(listWithModifier.getFirstChild(), firstChild); modifierList.addBefore(whiteSpace, firstChild); } else { PsiElement lastChild = modifierList.getLastChild(); modifierList.addAfter(listWithModifier.getFirstChild(), lastChild); modifierList.addAfter(whiteSpace, lastChild); } } } }
/** Depth first traversal to find all PsiCodeBlock children. */ private static void collectFollowingBlocks(PsiElement element, List<PsiCodeBlock> out) { while (element != null) { if (element instanceof PsiCodeBlock) { out.add((PsiCodeBlock) element); } collectFollowingBlocks(element.getFirstChild(), out); element = element.getNextSibling(); } }
public final boolean matchSonsInAnyOrder(PsiElement element1, PsiElement element2) { if (element1 == null && isLeftLooseMatching()) { return true; } if (element2 == null && isRightLooseMatching()) { return true; } if (element1 == null || element2 == null) { return element1 == element2; } PsiElement e = element1.getFirstChild(); PsiElement e2 = element2.getFirstChild(); return (e == null && isLeftLooseMatching()) || (e2 == null && isRightLooseMatching()) || matchInAnyOrder( new FilteringNodeIterator(new SiblingNodeIterator(e), getNodeFilter()), new FilteringNodeIterator(new SiblingNodeIterator(e2), getNodeFilter())); }
/** @return leading regex or null if it does not exist */ @Nullable private static GrLiteral getRegexAtTheBeginning(PsiElement expr) { PsiElement fchild = expr; while (fchild != null) { if (fchild instanceof GrLiteral && GrStringUtil.isRegex((GrLiteral) fchild)) return (GrLiteral) fchild; fchild = fchild.getFirstChild(); } return null; }
@Nullable public static String getUnescapedLeafText(PsiElement element, boolean strict) { String unescaped = element.getCopyableUserData(LeafPatcher.UNESCAPED_TEXT); if (unescaped != null) { return unescaped; } if (!strict && element.getFirstChild() == null) { return element.getText(); } return null; }
private static PsiElement[] getChildren(PsiElement element) { PsiElement psiChild = element.getFirstChild(); if (psiChild == null) return new PsiElement[0]; List<PsiElement> result = new ArrayList<PsiElement>(); while (psiChild != null) { result.add(psiChild); psiChild = psiChild.getNextSibling(); } return result.toArray(new PsiElement[result.size()]); }
@Nullable public static String getNameByReference(@Nullable PsiElement expression) { if (!(expression instanceof GrReferenceExpression)) return null; PsiElement firstChild = expression.getFirstChild(); if (firstChild != expression.getLastChild() || !PsiImplUtil.isLeafElementOfType(firstChild, GroovyTokenTypes.mIDENT)) return null; GrReferenceExpression ref = (GrReferenceExpression) expression; if (ref.isQualified()) return null; return ref.getReferenceName(); }
@Nullable private static String getDocumentationText(final DartComponent dartComponent) { // PSI is not perfect currently, doc comment may be not part of the corresponding DartComponent // element, so docs are searched for in several places: // - direct child of this DartComponent // - previous sibling (or previous sibling of parent element if this element is first child of // its parent DartClassMembers) // Consequent line doc comments (///) are joined // 1. Look for multiline doc comment as direct child final DartDocComment multilineComment = PsiTreeUtil.getChildOfType(dartComponent, DartDocComment.class); if (multilineComment != null) return getMultilineDocCommentText(multilineComment); // 2. Look for single line doc comments as direct children final PsiComment[] childComments = PsiTreeUtil.getChildrenOfType(dartComponent, PsiComment.class); if (childComments != null) { // final String docText = getSingleLineDocCommentsText(childComments); if (docText != null) return docText; } PsiElement anchorElement = dartComponent; final PsiElement parent = dartComponent.getParent(); if (parent instanceof DartClassMembers && parent.getFirstChild() == dartComponent || dartComponent instanceof DartVarAccessDeclaration) { anchorElement = parent; } // 3. Look for multiline doc comment or line doc comments as previous siblings final List<PsiComment> siblingComments = new ArrayList<PsiComment>(); PsiElement previous = anchorElement; while ((previous = UsefulPsiTreeUtil.getPrevSiblingSkipWhiteSpaces(previous, true)) instanceof PsiComment) { if (previous instanceof DartDocComment) { return getMultilineDocCommentText((DartDocComment) previous); } siblingComments.add(0, (PsiComment) previous); } if (!siblingComments.isEmpty()) { return getSingleLineDocCommentsText( siblingComments.toArray(new PsiComment[siblingComments.size()])); } return null; }
/** * Allows to answer if it's possible to use {@link #TOP_LEVEL_CHILD_MARKER} for the given element. * * @param element element to check * @return <code>true</code> if {@link #TOP_LEVEL_CHILD_MARKER} can be used for the given element; * <code>false</code> otherwise */ private static boolean canResolveTopLevelChild(@NotNull PsiElement element) { final PsiElement parent = element.getParent(); if (parent == null) { return false; } for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof PsiWhiteSpace) { continue; } if (child != element) { return false; } } return true; }
@Nullable public static <T extends PsiElement> T getChildrenOfType( @Nullable PsiElement element, ElementPattern<T> pattern) { if (element == null) return null; for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { if (pattern.accepts(child)) { //noinspection unchecked return (T) child; } } return null; }
protected int getCloseQuoteOffset() { PsiElement lastChild = getLastChild(); if (lastChild instanceof PerlParsableStringWrapperlImpl) { PsiElement realString = lastChild.getFirstChild(); assert realString instanceof PerlStringImplMixin; return ((PerlStringImplMixin) realString).getCloseQuoteOffset(); } ASTNode currentNode = lastChild.getNode(); if (PerlParserUtil.CLOSE_QUOTES.contains(currentNode.getElementType())) return currentNode.getStartOffset(); // unclosed string return lastChild.getTextOffset() + lastChild.getTextLength(); }
@Nullable private static PsiElement getMovableElement(@NotNull PsiElement element, boolean lookRight) { //noinspection unchecked PsiElement movableElement = PsiUtilPackage.getParentByTypesAndPredicate( element, false, MOVABLE_ELEMENT_CLASSES, MOVABLE_ELEMENT_CONSTRAINT); if (movableElement == null) return null; if (isBracelessBlock(movableElement)) { movableElement = firstNonWhiteElement( lookRight ? movableElement.getLastChild() : movableElement.getFirstChild(), !lookRight); } return movableElement; }
private void initTopLevelElement(PsiElement element) { CompiledPattern pattern = myGlobalVisitor.getContext().getPattern(); PsiElement newElement = SkippingHandler.skipNodeIfNeccessary(element); if (element != newElement && newElement != null) { // way to support partial matching (ex. if ($condition$) ) newElement.accept(this); pattern.setHandler(element, new LightTopLevelMatchingHandler(pattern.getHandler(element))); } else { myGlobalVisitor.setCodeBlockLevel(myGlobalVisitor.getCodeBlockLevel() + 1); for (PsiElement el = element.getFirstChild(); el != null; el = el.getNextSibling()) { if (GlobalCompilingVisitor.getFilter().accepts(el)) { if (el instanceof PsiWhiteSpace) { myGlobalVisitor.addLexicalNode(el); } } else { el.accept(this); MatchingHandler matchingHandler = pattern.getHandler(el); pattern.setHandler( el, element == myTopElement ? new TopLevelMatchingHandler(matchingHandler) : new LightTopLevelMatchingHandler(matchingHandler)); /* do not assign light-top-level handlers through skipping, because it is incorrect; src: if (...) { st1; st2; } pattern: if (...) {$a$;} $a$ will have top-level handler, so matching will be considered as correct, although "st2;" is left! */ } } myGlobalVisitor.setCodeBlockLevel(myGlobalVisitor.getCodeBlockLevel() - 1); pattern.setHandler(element, new TopLevelMatchingHandler(pattern.getHandler(element))); } }
private void appendDescriptors( ASTNode node, Document document, List<FoldingDescriptor> descriptors) { if (node == null) { return; } IElementType type = node.getElementType(); if (type == SparqlElementTypes.GROUP_GRAPH_PATTERN && isMultiline(node)) { descriptors.add(new FoldingDescriptor(node, node.getTextRange())); } else if (type == SparqlElementTypes.PREFIX_DECLS && isMultiline(node)) { descriptors.add(new FoldingDescriptor(node, node.getTextRange())); } final PsiElement psi = node.getPsi(); if (psi != null) { PsiElement child = psi.getFirstChild(); while (child != null) { appendDescriptors(child.getNode(), document, descriptors); child = child.getNextSibling(); } } }
protected int getOpenQuoteOffset() { PsiElement firstChild = getFirstChild(); if (firstChild instanceof PerlParsableStringWrapperlImpl) { PsiElement realString = firstChild.getFirstChild(); assert realString instanceof PerlStringImplMixin; return ((PerlStringImplMixin) realString).getOpenQuoteOffset(); } ASTNode currentNode = firstChild.getNode(); while (currentNode != null) { if (PerlParserUtil.OPEN_QUOTES.contains(currentNode.getElementType())) return currentNode.getStartOffset(); currentNode = currentNode.getTreeNext(); } throw new RuntimeException( "Unable to find opening quote inside: " + getText() + " " + getContainingFile().getVirtualFile()); }
private void highlightUsages() { Editor e = getEditor(); if (e == null) return; boolean foundVisibleElement = false; int offset = Integer.MAX_VALUE; for (SearchResult sr : searchResults.values()) { Map<Node, PsiElement> match = sr.getMatch(); TextAttributes textAttributes = createUniqueTextAttrsFor(sr); PsiElement targetElement = match.get(pattern.getTheOne()); if (!foundVisibleElement && insideVisibleArea(e, targetElement)) { foundVisibleElement = true; } if (!foundVisibleElement && targetElement.getTextOffset() < offset) { offset = targetElement.getTextOffset(); } for (PsiElement element : match.values()) { TextAttributes attributes = textAttributes; if (element == targetElement) { attributes = MAIN_TARGET_ATTRIBUTES; } if (element instanceof XmlTag) { element = element.getFirstChild().getNextSibling(); } TextRange textRange = element.getTextRange(); e.getMarkupModel() .addRangeHighlighter( textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION + 1, attributes, HighlighterTargetArea.EXACT_RANGE); } } if (!foundVisibleElement && offset != Integer.MAX_VALUE) { e.getScrollingModel().scrollTo(e.offsetToLogicalPosition(offset), ScrollType.CENTER); } }
@Override protected Boolean compute(PsiElement parent, Object p) { OuterLanguageElement element = PsiTreeUtil.getChildOfType(parent, OuterLanguageElement.class); if (element == null) { // JspOuterLanguageElement is located under XmlText for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof XmlText) { element = PsiTreeUtil.getChildOfType(child, OuterLanguageElement.class); if (element != null) { break; } } } } if (element == null) return false; PsiFile containingFile = parent.getContainingFile(); return containingFile.getViewProvider().getBaseLanguage() != containingFile.getLanguage(); }
private static void divideInsideAndOutside( @NotNull PsiFile root, int startOffset, int endOffset, @NotNull TextRange range, @NotNull List<PsiElement> inside, @NotNull List<PsiElement> outside, boolean includeParents) { final int currentOffset = root.getTextRange().getStartOffset(); final Condition<PsiElement>[] filters = Extensions.getExtensions(CollectHighlightsUtil.EP_NAME); int offset = currentOffset; final TIntStack starts = new TIntStack(STARTING_TREE_HEIGHT); starts.push(startOffset); final Stack<PsiElement> elements = new Stack<PsiElement>(STARTING_TREE_HEIGHT); final Stack<PsiElement> children = new Stack<PsiElement>(STARTING_TREE_HEIGHT); PsiElement element = root; PsiElement child = PsiUtilBase.NULL_PSI_ELEMENT; while (true) { ProgressManager.checkCanceled(); for (Condition<PsiElement> filter : filters) { if (!filter.value(element)) { assert child == PsiUtilBase.NULL_PSI_ELEMENT; child = null; // do not want to process children break; } } boolean startChildrenVisiting; if (child == PsiUtilBase.NULL_PSI_ELEMENT) { startChildrenVisiting = true; child = element.getFirstChild(); } else { startChildrenVisiting = false; } if (child == null) { if (startChildrenVisiting) { // leaf element offset += element.getTextLength(); } int start = starts.pop(); if (startOffset <= start && offset <= endOffset) { if (range.containsRange(start, offset)) { inside.add(element); } else { outside.add(element); } } if (elements.isEmpty()) break; element = elements.pop(); child = children.pop(); } else { // composite element if (offset > endOffset) break; children.push(child.getNextSibling()); starts.push(offset); elements.push(element); element = child; child = PsiUtilBase.NULL_PSI_ELEMENT; } } if (includeParents) { PsiElement parent = !outside.isEmpty() ? outside.get(outside.size() - 1) : !inside.isEmpty() ? inside.get(inside.size() - 1) : CollectHighlightsUtil.findCommonParent(root, startOffset, endOffset); while (parent != null && parent != root) { parent = parent.getParent(); if (parent != null) outside.add(parent); } } }
@Override protected PsiElement restoreBySignatureTokens( @NotNull PsiFile file, @NotNull PsiElement parent, @NotNull final String type, @NotNull StringTokenizer tokenizer, @Nullable StringBuilder processingInfoStorage) { if (!TYPE_MARKER.equals(type)) { if (processingInfoStorage != null) { processingInfoStorage.append( String.format( "Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'%n", getClass().getName(), TYPE_MARKER, type)); } return null; } String elementMarker = tokenizer.nextToken(); if (TOP_LEVEL_CHILD_MARKER.equals(elementMarker)) { PsiElement result = null; for (PsiElement child = file.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof PsiWhiteSpace) { continue; } if (result == null) { result = child; } else { if (processingInfoStorage != null) { processingInfoStorage.append( String.format( "Stopping '%s' provider because it has top level marker but more than one non white-space child: %s%n", getClass().getName(), Arrays.toString(file.getChildren()))); } // More than one top-level non-white space children. Can't match. return null; } } if (processingInfoStorage != null) { processingInfoStorage.append( String.format( "Finished processing of '%s' provider because all of its top-level children have been processed: %s%n", getClass().getName(), Arrays.toString(file.getChildren()))); } return result; } if (DOC_COMMENT_MARKER.equals(elementMarker)) { PsiElement candidate = parent.getFirstChild(); return candidate instanceof PsiComment ? candidate : null; } if (CODE_BLOCK_MARKER.equals(elementMarker)) { int index = 0; if (tokenizer.hasMoreTokens()) { String indexStr = tokenizer.nextToken(); try { index = Integer.parseInt(indexStr); } catch (NumberFormatException e) { if (processingInfoStorage != null) { processingInfoStorage.append("Invalid block index: ").append(indexStr).append("\n"); } } } for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { if (isBlockElement(child)) { if (--index < 0) { return child; } } } return null; } if (!tokenizer.hasMoreTokens()) { if (processingInfoStorage != null) { processingInfoStorage.append( String.format( "Stopping '%s' provider because it has no more data to process%n", getClass().getName())); } return null; } try { int index = Integer.parseInt(tokenizer.nextToken()); if (processingInfoStorage != null) { processingInfoStorage.append( String.format( "Looking for the child with a name '%s' # %d at the element '%s'%n", elementMarker, index, parent)); } return restoreElementInternal(parent, unescape(elementMarker), index, PsiNamedElement.class); } catch (NumberFormatException e) { return null; } }
/** * Tries to produce signature for the exact given PSI element. * * @param element target element * @param buffer buffer to store the signature in * @return buffer that contains signature of the given element if it was produced; <code>null * </code> as an indication that signature for the given element was not produced */ @SuppressWarnings("unchecked") @Nullable private static StringBuilder getSignature( @NotNull PsiElement element, @Nullable StringBuilder buffer) { if (element instanceof PsiNamedElement) { PsiNamedElement named = (PsiNamedElement) element; final String name = named.getName(); if (StringUtil.isEmpty(name)) { return null; } int index = getChildIndex(named, element.getParent(), name, PsiNamedElement.class); StringBuilder bufferToUse = buffer; if (bufferToUse == null) { bufferToUse = new StringBuilder(); } bufferToUse .append(TYPE_MARKER) .append(ELEMENT_TOKENS_SEPARATOR) .append(escape(name)) .append(ELEMENT_TOKENS_SEPARATOR) .append(index); return bufferToUse; } if (element instanceof PsiComment) { PsiElement parent = element.getParent(); boolean nestedComment = false; if (parent instanceof PsiComment && parent.getTextRange().equals(element.getTextRange())) { parent = parent.getParent(); nestedComment = true; } if (parent instanceof PsiNamedElement && (nestedComment || parent.getFirstChild() == element)) { // Consider doc comment element that is the first child of named element to be a doc // comment. StringBuilder bufferToUse = buffer; if (bufferToUse == null) { bufferToUse = new StringBuilder(); } bufferToUse.append(TYPE_MARKER).append(ELEMENT_TOKENS_SEPARATOR).append(DOC_COMMENT_MARKER); return bufferToUse; } } PsiElement parent = element.getParent(); if (parent instanceof PsiNamedElement && !(parent instanceof PsiFile)) { if (isBlockElement(element)) { int index = getBlockElementIndex(element); StringBuilder bufferToUse = buffer; if (bufferToUse == null) { bufferToUse = new StringBuilder(); } bufferToUse.append(TYPE_MARKER).append(ELEMENT_TOKENS_SEPARATOR).append(CODE_BLOCK_MARKER); if (index > 0) { bufferToUse.append(ELEMENT_TOKENS_SEPARATOR).append(index); } return bufferToUse; } } return null; }
@Nullable public static GrExpression replaceExpression( GrExpression oldExpr, GrExpression newExpr, boolean removeUnnecessaryParentheses) { PsiElement oldParent = oldExpr.getParent(); if (oldParent == null) throw new PsiInvalidElementAccessException(oldExpr); if (!(oldExpr instanceof GrApplicationStatement)) { newExpr = ApplicationStatementUtil.convertToMethodCallExpression(newExpr); } // Remove unnecessary parentheses if (removeUnnecessaryParentheses && oldParent instanceof GrParenthesizedExpression && !(oldParent.getParent() instanceof GrArgumentLabel)) { return ((GrExpression) oldParent) .replaceWithExpression(newExpr, removeUnnecessaryParentheses); } // regexes cannot be after identifier , try to replace it with simple string if (getRegexAtTheBeginning(newExpr) != null && isAfterIdentifier(oldExpr)) { final PsiElement copy = newExpr.copy(); final GrLiteral regex = getRegexAtTheBeginning(copy); LOG.assertTrue(regex != null); final GrLiteral stringLiteral = GrStringUtil.createStringFromRegex(regex); if (regex == copy) { return oldExpr.replaceWithExpression(stringLiteral, removeUnnecessaryParentheses); } else { regex.replace(stringLiteral); return oldExpr.replaceWithExpression((GrExpression) copy, removeUnnecessaryParentheses); } } GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject()); if (oldParent instanceof GrStringInjection) { if (newExpr instanceof GrString || newExpr instanceof GrLiteral && ((GrLiteral) newExpr).getValue() instanceof String) { return GrStringUtil.replaceStringInjectionByLiteral( (GrStringInjection) oldParent, (GrLiteral) newExpr); } else { newExpr = factory.createExpressionFromText("{" + newExpr.getText() + "}"); oldParent.getNode().replaceChild(oldExpr.getNode(), newExpr.getNode()); return newExpr; } } if (PsiTreeUtil.getParentOfType(oldExpr, GrStringInjection.class, false, GrCodeBlock.class) != null) { final PsiElement replaced = oldExpr.replace(newExpr); final GrStringInjection stringInjection = PsiTreeUtil.getParentOfType(replaced, GrStringInjection.class); GrStringUtil.wrapInjection(stringInjection); assert stringInjection != null; return stringInjection.getClosableBlock(); } // check priorities if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) { GrExpression addedParenth = addParenthesesIfNeeded(newExpr, oldExpr, (GrExpression) oldParent); if (newExpr != addedParenth) { return oldExpr.replaceWithExpression(addedParenth, removeUnnecessaryParentheses); } } // if replace closure argument with expression // we should add the expression in arg list if (oldExpr instanceof GrClosableBlock && !(newExpr instanceof GrClosableBlock) && oldParent instanceof GrMethodCallExpression && ArrayUtil.contains( oldExpr, ((GrMethodCallExpression) oldParent).getClosureArguments())) { return ((GrMethodCallExpression) oldParent) .replaceClosureArgument((GrClosableBlock) oldExpr, newExpr); } newExpr = (GrExpression) oldExpr.replace(newExpr); // if newExpr is the first grand child of command argument list we should replace command arg // list with parenthesised arg list. // In other case the code will be broken. So we try to find wrapping command arg list counting // levels. After arg list replace we go inside it // to find target parenthesised expression. if (newExpr instanceof GrParenthesizedExpression && isFirstChild(newExpr)) { int parentCount = 0; PsiElement element = oldParent; while (element != null && !(element instanceof GrCommandArgumentList)) { if (element instanceof GrCodeBlock || element instanceof GrParenthesizedExpression) break; if (element instanceof PsiFile) break; final PsiElement parent = element.getParent(); if (parent == null) break; if (!isFirstChild(element)) break; element = parent; parentCount++; } if (element instanceof GrCommandArgumentList) { final GrCommandArgumentList commandArgList = (GrCommandArgumentList) element; final PsiElement parent = commandArgList.getParent(); LOG.assertTrue(parent instanceof GrApplicationStatement); final GrMethodCall methodCall = factory.createMethodCallByAppCall((GrApplicationStatement) parent); final GrMethodCall newCall = (GrMethodCall) parent.replace(methodCall); PsiElement result = newCall.getArgumentList().getAllArguments()[0]; for (int i = 0; i < parentCount; i++) { result = PsiUtil.skipWhitespacesAndComments(result.getFirstChild(), true); } LOG.assertTrue(result instanceof GrParenthesizedExpression); return (GrExpression) result; } } return newExpr; }