private static TextRange calculateLimitRange( final PsiFile file, final Document doc, final int line) { final int offset = doc.getLineStartOffset(line); if (offset > 0) { PsiMethod method = PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiMethod.class, false); if (method != null) { final TextRange elemRange = method.getTextRange(); return new TextRange( doc.getLineNumber(elemRange.getStartOffset()), doc.getLineNumber(elemRange.getEndOffset())); } } return new TextRange(0, doc.getLineCount() - 1); }
public static List<PsiLambdaExpression> collectLambdas( @NotNull SourcePosition position, final boolean onlyOnTheLine) { ApplicationManager.getApplication().assertReadAccessAllowed(); PsiFile file = position.getFile(); final int line = position.getLine(); final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); if (document == null || line >= document.getLineCount()) { return Collections.emptyList(); } PsiElement element = position.getElementAt(); final TextRange lineRange = DocumentUtil.getLineTextRange(document, line); do { PsiElement parent = element.getParent(); if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) { break; } element = parent; } while (true); final List<PsiLambdaExpression> lambdas = new ArrayList<PsiLambdaExpression>(3); final PsiElementVisitor lambdaCollector = new JavaRecursiveElementVisitor() { @Override public void visitLambdaExpression(PsiLambdaExpression expression) { super.visitLambdaExpression(expression); if (!onlyOnTheLine || getFirstElementOnTheLine(expression, document, line) != null) { lambdas.add(expression); } } }; element.accept(lambdaCollector); // add initial lambda if we're inside already PsiElement method = getContainingMethod(element); if (method instanceof PsiLambdaExpression) { lambdas.add((PsiLambdaExpression) method); } for (PsiElement sibling = getNextElement(element); sibling != null; sibling = getNextElement(sibling)) { if (!intersects(lineRange, sibling)) { break; } sibling.accept(lambdaCollector); } return lambdas; }
@Override public void visitReferenceExpression(final PsiReferenceExpression reference) { if (myLineRange.intersects(reference.getTextRange())) { final PsiElement psiElement = reference.resolve(); if (psiElement instanceof PsiVariable) { final PsiVariable var = (PsiVariable) psiElement; if (var instanceof PsiField) { if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars( reference, myVisibleLocals)) { /* if (var instanceof PsiEnumConstant && reference.getQualifier() == null) { final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass(); if (enumClass != null) { final PsiExpression expression = JavaPsiFacade.getInstance(var.getProject()).getParserFacade().createExpressionFromText(enumClass.getName() + "." + var.getName(), var); final PsiReference ref = expression.getReference(); if (ref != null) { ref.bindToElement(var); myExpressions.add(new TextWithImportsImpl(expression)); } } } else { myExpressions.add(new TextWithImportsImpl(reference)); } */ final PsiModifierList modifierList = var.getModifierList(); boolean isConstant = (var instanceof PsiEnumConstant) || (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC) && modifierList.hasModifierProperty(PsiModifier.FINAL)); if (!isConstant) { myExpressions.add(new TextWithImportsImpl(reference)); } } } else { if (myVisibleLocals.contains(var.getName())) { myVars.add(var.getName()); } else { // fix for variables used in inner classes if (!Comparing.equal( PsiTreeUtil.getParentOfType(reference, PsiClass.class), PsiTreeUtil.getParentOfType(var, PsiClass.class))) { myExpressions.add(new TextWithImportsImpl(reference)); } } } } } super.visitReferenceExpression(reference); }
private static boolean shouldSkipLine(final PsiFile file, Document doc, int line) { final int start = doc.getLineStartOffset(line); final int end = doc.getLineEndOffset(line); final int _start = CharArrayUtil.shiftForward(doc.getCharsSequence(), start, " \n\t"); if (_start >= end) { return true; } TextRange alreadyChecked = null; for (PsiElement elem = file.findElementAt(_start); elem != null && elem.getTextOffset() <= end && (alreadyChecked == null || !alreadyChecked.contains(elem.getTextRange())); elem = elem.getNextSibling()) { for (PsiElement _elem = elem; _elem.getTextOffset() >= _start; _elem = _elem.getParent()) { alreadyChecked = _elem.getTextRange(); if (_elem instanceof PsiDeclarationStatement) { final PsiElement[] declared = ((PsiDeclarationStatement) _elem).getDeclaredElements(); for (PsiElement declaredElement : declared) { if (declaredElement instanceof PsiVariable) { return false; } } } if (_elem instanceof PsiJavaCodeReferenceElement) { final PsiElement resolved = ((PsiJavaCodeReferenceElement) _elem).resolve(); if (resolved instanceof PsiVariable) { return false; } } } } return true; }
public static boolean intersects(@NotNull TextRange range, @NotNull PsiElement elem) { TextRange elemRange = elem.getTextRange(); return elemRange != null && elemRange.intersects(range); }
private static Pair<Set<String>, Set<TextWithImports>> findReferencedVars( Set<String> visibleVars, SourcePosition position) { final int line = position.getLine(); if (line < 0) { return Pair.create(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet()); } final PsiFile positionFile = position.getFile(); if (!positionFile.getLanguage().isKindOf(JavaLanguage.INSTANCE)) { return Pair.create(visibleVars, Collections.<TextWithImports>emptySet()); } final VirtualFile vFile = positionFile.getVirtualFile(); final Document doc = vFile != null ? FileDocumentManager.getInstance().getDocument(vFile) : null; if (doc == null || doc.getLineCount() == 0 || line > (doc.getLineCount() - 1)) { return Pair.create(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet()); } final TextRange limit = calculateLimitRange(positionFile, doc, line); int startLine = Math.max(limit.getStartOffset(), line - 1); startLine = Math.min(startLine, limit.getEndOffset()); while (startLine > limit.getStartOffset() && shouldSkipLine(positionFile, doc, startLine)) { startLine--; } final int startOffset = doc.getLineStartOffset(startLine); int endLine = Math.min(line + 2, limit.getEndOffset()); while (endLine < limit.getEndOffset() && shouldSkipLine(positionFile, doc, endLine)) { endLine++; } final int endOffset = doc.getLineEndOffset(endLine); final TextRange lineRange = new TextRange(startOffset, endOffset); if (!lineRange.isEmpty()) { final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), doc.getLineStartOffset(line), " \t"); PsiElement element = positionFile.findElementAt(offset); if (element != null) { PsiMethod method = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class); if (method != null) { element = method; } else { PsiField field = PsiTreeUtil.getNonStrictParentOfType(element, PsiField.class); if (field != null) { element = field; } else { final PsiClassInitializer initializer = PsiTreeUtil.getNonStrictParentOfType(element, PsiClassInitializer.class); if (initializer != null) { element = initializer; } } } //noinspection unchecked if (element instanceof PsiCompiledElement) { return Pair.create(visibleVars, Collections.<TextWithImports>emptySet()); } else { VariablesCollector collector = new VariablesCollector(visibleVars, adjustRange(element, lineRange)); element.accept(collector); return Pair.create(collector.getVars(), collector.getExpressions()); } } } return Pair.create(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet()); }
private void processVariable(final PsiVariable variable) { if (myLineRange.intersects(variable.getTextRange()) && myVisibleLocals.contains(variable.getName())) { myVars.add(variable.getName()); } }
@Override public void visitElement(final PsiElement element) { if (myLineRange.intersects(element.getTextRange())) { super.visitElement(element); } }